diff options
1740 files changed, 40013 insertions, 21198 deletions
diff --git a/Android.bp b/Android.bp index cff863b44499..64d2c66f013c 100644 --- a/Android.bp +++ b/Android.bp @@ -410,6 +410,7 @@ java_defaults { "spatializer-aidl-java", "audiopolicy-aidl-java", "sounddose-aidl-java", + "modules-utils-expresslog", ], } diff --git a/apct-tests/perftests/blobstore/Android.bp b/apct-tests/perftests/blobstore/Android.bp index 9064b4494ed1..2590fe3d843f 100644 --- a/apct-tests/perftests/blobstore/Android.bp +++ b/apct-tests/perftests/blobstore/Android.bp @@ -29,7 +29,7 @@ android_test { "androidx.test.rules", "androidx.annotation_annotation", "apct-perftests-utils", - "ub-uiautomator", + "androidx.test.uiautomator_uiautomator", "collector-device-lib-platform", "androidx.benchmark_benchmark-macro", ], diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/AtraceUtils.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/AtraceUtils.java index 0208dab33746..4e4780ff8948 100644 --- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/AtraceUtils.java +++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/AtraceUtils.java @@ -21,10 +21,10 @@ import android.app.UiAutomation; import android.os.ParcelFileDescriptor; import android.perftests.utils.TraceMarkParser; import android.perftests.utils.TraceMarkParser.TraceMarkSlice; -import android.support.test.uiautomator.UiDevice; import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.uiautomator.UiDevice; import java.io.BufferedReader; import java.io.IOException; diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java index 03e5468a342a..3cd9f50aee6a 100644 --- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java +++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java @@ -25,12 +25,12 @@ import android.perftests.utils.ManualBenchmarkState; import android.perftests.utils.PerfManualStatusReporter; import android.perftests.utils.TraceMarkParser; import android.perftests.utils.TraceMarkParser.TraceMarkSlice; -import android.support.test.uiautomator.UiDevice; import android.util.DataUnit; import androidx.benchmark.macro.MacrobenchmarkScope; import androidx.test.filters.LargeTest; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.uiautomator.UiDevice; import com.android.utils.blob.FakeBlobData; diff --git a/apct-tests/perftests/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp index e84aea1e7fac..b6ea54d3d53f 100644 --- a/apct-tests/perftests/packagemanager/Android.bp +++ b/apct-tests/perftests/packagemanager/Android.bp @@ -34,6 +34,55 @@ android_test { test_suites: ["device-tests"], data: [ + ":QueriesAll4", + ":QueriesAll31", + ":QueriesAll43", + ":QueriesAll15", + ":QueriesAll27", + ":QueriesAll39", + ":QueriesAll11", + ":QueriesAll23", + ":QueriesAll35", + ":QueriesAll47", + ":QueriesAll9", + ":QueriesAll19", + ":QueriesAll1", + ":QueriesAll5", + ":QueriesAll40", + ":QueriesAll20", + ":QueriesAll32", + ":QueriesAll48", + ":QueriesAll16", + ":QueriesAll28", + ":QueriesAll44", + ":QueriesAll12", + ":QueriesAll24", + ":QueriesAll36", + ":QueriesAll6", + ":QueriesAll2", + ":QueriesAll41", + ":QueriesAll21", + ":QueriesAll37", + ":QueriesAll49", + ":QueriesAll17", + ":QueriesAll29", + ":QueriesAll33", + ":QueriesAll45", + ":QueriesAll13", + ":QueriesAll25", + ":QueriesAll7", + ":QueriesAll3", + ":QueriesAll30", + ":QueriesAll42", + ":QueriesAll10", + ":QueriesAll26", + ":QueriesAll38", + ":QueriesAll18", + ":QueriesAll22", + ":QueriesAll34", + ":QueriesAll46", + ":QueriesAll14", + ":QueriesAll8", ":QueriesAll0", ":perfetto_artifacts", ], diff --git a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java index f56e1eea0f23..36174c6aad3d 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java @@ -20,6 +20,7 @@ import android.annotation.SystemApi; import android.app.JobSchedulerImpl; import android.app.SystemServiceRegistry; import android.app.tare.EconomyManager; +import android.app.tare.IEconomyManager; import android.content.Context; import android.os.DeviceIdleManager; import android.os.IDeviceIdleController; @@ -58,6 +59,7 @@ public class JobSchedulerFrameworkInitializer { Context.POWER_EXEMPTION_SERVICE, PowerExemptionManager.class, PowerExemptionManager::new); SystemServiceRegistry.registerStaticService( - Context.RESOURCE_ECONOMY_SERVICE, EconomyManager.class, EconomyManager::new); + Context.RESOURCE_ECONOMY_SERVICE, EconomyManager.class, + (b) -> new EconomyManager(IEconomyManager.Stub.asInterface(b))); } } diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java index 581ea7adc465..0bea028e6f50 100644 --- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java +++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java @@ -19,7 +19,9 @@ package android.app.tare; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; +import android.os.RemoteException; import android.util.Log; import java.lang.annotation.Retention; @@ -30,6 +32,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@TestApi @SystemService(Context.RESOURCE_ECONOMY_SERVICE) public class EconomyManager { private static final String TAG = "TARE-" + EconomyManager.class.getSimpleName(); @@ -95,13 +98,17 @@ public class EconomyManager { } } - + /** @hide */ + @TestApi public static final int ENABLED_MODE_OFF = 0; + /** @hide */ public static final int ENABLED_MODE_ON = 1; /** * Go through the motions, tracking events, updating balances and other TARE state values, * but don't use TARE to affect actual device behavior. + * @hide */ + @TestApi public static final int ENABLED_MODE_SHADOW = 2; /** @hide */ @@ -114,6 +121,7 @@ public class EconomyManager { public @interface EnabledMode { } + /** @hide */ public static String enabledModeToString(@EnabledMode int mode) { switch (mode) { case ENABLED_MODE_OFF: return "ENABLED_MODE_OFF"; @@ -123,11 +131,18 @@ public class EconomyManager { } } + /** @hide */ + @TestApi public static final String KEY_ENABLE_TARE_MODE = "enable_tare_mode"; + /** @hide */ public static final String KEY_ENABLE_POLICY_ALARM = "enable_policy_alarm"; + /** @hide */ public static final String KEY_ENABLE_POLICY_JOB_SCHEDULER = "enable_policy_job"; + /** @hide */ public static final int DEFAULT_ENABLE_TARE_MODE = ENABLED_MODE_OFF; + /** @hide */ public static final boolean DEFAULT_ENABLE_POLICY_ALARM = true; + /** @hide */ public static final boolean DEFAULT_ENABLE_POLICY_JOB_SCHEDULER = true; // Keys for AlarmManager TARE factors @@ -612,4 +627,27 @@ public class EconomyManager { public static final long DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE_CAKES = arcToCake(1); /** @hide */ public static final long DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE_CAKES = arcToCake(60); + + //////// APIs below //////// + + private final IEconomyManager mService; + + /** @hide */ + public EconomyManager(IEconomyManager service) { + mService = service; + } + + /** + * Returns the current enabled status of TARE. + * @hide + */ + @EnabledMode + @TestApi + public int getEnabledMode() { + try { + return mService.getEnabledMode(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl b/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl index bb150118ebb1..2be0db7a4c9f 100644 --- a/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl +++ b/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl @@ -21,4 +21,5 @@ package android.app.tare; * {@hide} */ interface IEconomyManager { + int getEnabledMode(); } diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java index c956bf52ed55..fd8ddbcf3809 100644 --- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java @@ -16,6 +16,7 @@ package com.android.server.job; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.job.JobInfo; import android.app.job.JobParameters; @@ -59,6 +60,19 @@ public interface JobSchedulerInternal { void reportAppUsage(String packageName, int userId); /** + * @return {@code true} if the given notification is associated with any user-initiated jobs. + */ + boolean isNotificationAssociatedWithAnyUserInitiatedJobs(int notificationId, + int userId, @NonNull String packageName); + + /** + * @return {@code true} if the given notification channel is associated with any user-initiated + * jobs. + */ + boolean isNotificationChannelAssociatedWithAnyUserInitiatedJobs( + @NonNull String notificationChannel, int userId, @NonNull String packageName); + + /** * Report a snapshot of sync-related jobs back to the sync manager */ JobStorePersistStats getPersistStats(); diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 0650ce3d141c..f779b4d96b45 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -355,7 +355,7 @@ public class DeviceIdleController extends SystemService @GuardedBy("this") private boolean mHasGps; @GuardedBy("this") - private boolean mHasNetworkLocation; + private boolean mHasFusedLocation; @GuardedBy("this") private Location mLastGenericLocation; @GuardedBy("this") @@ -3782,12 +3782,14 @@ public class DeviceIdleController extends SystemService scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT); LocationManager locationManager = mInjector.getLocationManager(); if (locationManager != null - && locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) { - locationManager.requestLocationUpdates(mLocationRequest, - mGenericLocationListener, mHandler.getLooper()); + && locationManager.getProvider(LocationManager.FUSED_PROVIDER) != null) { + locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER, + mLocationRequest, + AppSchedulingModuleThread.getExecutor(), + mGenericLocationListener); mLocating = true; } else { - mHasNetworkLocation = false; + mHasFusedLocation = false; } if (locationManager != null && locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { @@ -5301,9 +5303,10 @@ public class DeviceIdleController extends SystemService pw.print(" "); pw.print(mStationaryListeners.size()); pw.println(" stationary listeners registered"); } - pw.print(" mLocating="); pw.print(mLocating); pw.print(" mHasGps="); - pw.print(mHasGps); pw.print(" mHasNetwork="); - pw.print(mHasNetworkLocation); pw.print(" mLocated="); pw.println(mLocated); + pw.print(" mLocating="); pw.print(mLocating); + pw.print(" mHasGps="); pw.print(mHasGps); + pw.print(" mHasFused="); pw.print(mHasFusedLocation); + pw.print(" mLocated="); pw.println(mLocated); if (mLastGenericLocation != null) { pw.print(" mLastGenericLocation="); pw.println(mLastGenericLocation); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java index 4477e94b77f1..b9b825c9f75c 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -1925,6 +1925,18 @@ class JobConcurrencyManager { return null; } + boolean isNotificationAssociatedWithAnyUserInitiatedJobs(int notificationId, int userId, + @NonNull String packageName) { + return mNotificationCoordinator.isNotificationAssociatedWithAnyUserInitiatedJobs( + notificationId, userId, packageName); + } + + boolean isNotificationChannelAssociatedWithAnyUserInitiatedJobs( + @NonNull String notificationChannel, int userId, @NonNull String packageName) { + return mNotificationCoordinator.isNotificationChannelAssociatedWithAnyUserInitiatedJobs( + notificationChannel, userId, packageName); + } + @NonNull private JobServiceContext createNewJobServiceContext() { return mInjector.createJobServiceContext(mService, this, mNotificationCoordinator, diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java index 5a1214296526..d94674b5cab0 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java @@ -27,16 +27,28 @@ import android.content.pm.UserPackage; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IntArray; import android.util.Slog; +import android.util.SparseArrayMap; import android.util.SparseSetArray; +import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; +import com.android.server.job.controllers.JobStatus; import com.android.server.notification.NotificationManagerInternal; class JobNotificationCoordinator { private static final String TAG = "JobNotificationCoordinator"; /** + * Local lock for independent objects like mUijNotifications and mUijNotificationChannels which + * don't depend on other JS objects such as JobServiceContext which require the global JS lock. + * + * Note: do <b>NOT</b> acquire the global lock while this one is held. + */ + private final Object mUijLock = new Object(); + + /** * Mapping of UserPackage -> {notificationId -> List<JobServiceContext>} to track which jobs * are associated with each app's notifications. */ @@ -48,20 +60,43 @@ class JobNotificationCoordinator { private final ArrayMap<JobServiceContext, NotificationDetails> mNotificationDetails = new ArrayMap<>(); + /** + * Mapping of userId -> {packageName, notificationIds} tracking which notifications + * associated with each app belong to user-initiated jobs. + * + * Note: this map can be accessed without holding the main JS lock, so that other services like + * NotificationManagerService can call into JS and verify associations. + */ + @GuardedBy("mUijLock") + private final SparseArrayMap<String, IntArray> mUijNotifications = new SparseArrayMap<>(); + + /** + * Mapping of userId -> {packageName, notificationChannels} tracking which notification channels + * associated with each app are hosting a user-initiated job notification. + * + * Note: this map can be accessed without holding the main JS lock, so that other services like + * NotificationManagerService can call into JS and verify associations. + */ + @GuardedBy("mUijLock") + private final SparseArrayMap<String, ArraySet<String>> mUijNotificationChannels = + new SparseArrayMap<>(); + private static final class NotificationDetails { @NonNull public final UserPackage userPackage; public final int notificationId; + public final String notificationChannel; public final int appPid; public final int appUid; @JobService.JobEndNotificationPolicy public final int jobEndNotificationPolicy; NotificationDetails(@NonNull UserPackage userPackage, int appPid, int appUid, - int notificationId, + int notificationId, String notificationChannel, @JobService.JobEndNotificationPolicy int jobEndNotificationPolicy) { this.userPackage = userPackage; this.notificationId = notificationId; + this.notificationChannel = notificationChannel; this.appPid = appPid; this.appUid = appUid; this.jobEndNotificationPolicy = jobEndNotificationPolicy; @@ -78,20 +113,29 @@ class JobNotificationCoordinator { int callingPid, int callingUid, int notificationId, @NonNull Notification notification, @JobService.JobEndNotificationPolicy int jobEndNotificationPolicy) { validateNotification(packageName, callingUid, notification, jobEndNotificationPolicy); + final JobStatus jobStatus = hostingContext.getRunningJobLocked(); final NotificationDetails oldDetails = mNotificationDetails.get(hostingContext); if (oldDetails != null && oldDetails.notificationId != notificationId) { // App is switching notification IDs. Remove association with the old one. - removeNotificationAssociation(hostingContext, JobParameters.STOP_REASON_UNDEFINED); + removeNotificationAssociation(hostingContext, JobParameters.STOP_REASON_UNDEFINED, + jobStatus); } final int userId = UserHandle.getUserId(callingUid); - // TODO(260848384): ensure apps can't cancel the notification for user-initiated job - // eg., by calling NotificationManager.cancel/All or deleting the notification channel - mNotificationManagerInternal.enqueueNotification( - packageName, packageName, callingUid, callingPid, /* tag */ null, - notificationId, notification, userId); + if (jobStatus != null && jobStatus.startedAsUserInitiatedJob) { + notification.flags |= Notification.FLAG_USER_INITIATED_JOB; + synchronized (mUijLock) { + maybeCreateUijNotificationSetsLocked(userId, packageName); + final IntArray notificationIds = mUijNotifications.get(userId, packageName); + if (notificationIds.indexOf(notificationId) == -1) { + notificationIds.add(notificationId); + } + mUijNotificationChannels.get(userId, packageName).add(notification.getChannelId()); + } + } final UserPackage userPackage = UserPackage.of(userId, packageName); final NotificationDetails details = new NotificationDetails( - userPackage, callingPid, callingUid, notificationId, jobEndNotificationPolicy); + userPackage, callingPid, callingUid, notificationId, notification.getChannelId(), + jobEndNotificationPolicy); SparseSetArray<JobServiceContext> appNotifications = mCurrentAssociations.get(userPackage); if (appNotifications == null) { appNotifications = new SparseSetArray<>(); @@ -99,10 +143,15 @@ class JobNotificationCoordinator { } appNotifications.add(notificationId, hostingContext); mNotificationDetails.put(hostingContext, details); + // Call into NotificationManager after internal data structures have been updated since + // NotificationManager calls into this class to check for any existing associations. + mNotificationManagerInternal.enqueueNotification( + packageName, packageName, callingUid, callingPid, /* tag */ null, + notificationId, notification, userId); } void removeNotificationAssociation(@NonNull JobServiceContext hostingContext, - @JobParameters.StopReason int stopReason) { + @JobParameters.StopReason int stopReason, JobStatus completedJob) { final NotificationDetails details = mNotificationDetails.remove(hostingContext); if (details == null) { return; @@ -113,18 +162,138 @@ class JobNotificationCoordinator { Slog.wtf(TAG, "Association data structures not in sync"); return; } - ArraySet<JobServiceContext> associatedContexts = associations.get(details.notificationId); + final int userId = UserHandle.getUserId(details.appUid); + final String packageName = details.userPackage.packageName; + final int notificationId = details.notificationId; + boolean stripUijFlag = true; + ArraySet<JobServiceContext> associatedContexts = associations.get(notificationId); if (associatedContexts == null || associatedContexts.isEmpty()) { // No more jobs using this notification. Apply the final job stop policy. // If the user attempted to stop the job/app, then always remove the notification // so the user doesn't get confused about the app state. if (details.jobEndNotificationPolicy == JOB_END_NOTIFICATION_POLICY_REMOVE || stopReason == JobParameters.STOP_REASON_USER) { - final String packageName = details.userPackage.packageName; mNotificationManagerInternal.cancelNotification( packageName, packageName, details.appUid, details.appPid, /* tag */ null, - details.notificationId, UserHandle.getUserId(details.appUid)); + notificationId, userId); + stripUijFlag = false; } + } else { + // Strip the UIJ flag only if there are no other UIJs associated with the notification + stripUijFlag = !isNotificationUsedForAnyUij(userId, packageName, notificationId); + } + if (stripUijFlag) { + mNotificationManagerInternal.removeUserInitiatedJobFlagFromNotification( + packageName, notificationId, userId); + } + + // Clean up UIJ related objects if the just completed job was a UIJ + if (completedJob != null && completedJob.startedAsUserInitiatedJob) { + maybeDeleteNotificationIdAssociation(userId, packageName, notificationId); + maybeDeleteNotificationChannelAssociation( + userId, packageName, details.notificationChannel); + } + } + + boolean isNotificationAssociatedWithAnyUserInitiatedJobs(int notificationId, + int userId, @NonNull String packageName) { + synchronized (mUijLock) { + final IntArray notifications = mUijNotifications.get(userId, packageName); + if (notifications != null) { + return notifications.indexOf(notificationId) != -1; + } + return false; + } + } + + boolean isNotificationChannelAssociatedWithAnyUserInitiatedJobs( + @NonNull String notificationChannel, int userId, @NonNull String packageName) { + synchronized (mUijLock) { + final ArraySet<String> channels = mUijNotificationChannels.get(userId, packageName); + if (channels != null) { + return channels.contains(notificationChannel); + } + return false; + } + } + + private boolean isNotificationUsedForAnyUij(int userId, String packageName, + int notificationId) { + final UserPackage pkgDetails = UserPackage.of(userId, packageName); + final SparseSetArray<JobServiceContext> associations = mCurrentAssociations.get(pkgDetails); + if (associations == null) { + return false; + } + final ArraySet<JobServiceContext> associatedContexts = associations.get(notificationId); + if (associatedContexts == null) { + return false; + } + + // Check if any UIJs associated with this package are using the same notification + for (int i = associatedContexts.size() - 1; i >= 0; i--) { + final JobStatus jobStatus = associatedContexts.valueAt(i).getRunningJobLocked(); + if (jobStatus != null && jobStatus.startedAsUserInitiatedJob) { + return true; + } + } + return false; + } + + private void maybeDeleteNotificationIdAssociation(int userId, String packageName, + int notificationId) { + if (isNotificationUsedForAnyUij(userId, packageName, notificationId)) { + return; + } + + // Safe to delete - no UIJs for this package are using this notification id + synchronized (mUijLock) { + final IntArray notifications = mUijNotifications.get(userId, packageName); + if (notifications != null) { + notifications.remove(notifications.indexOf(notificationId)); + if (notifications.size() == 0) { + mUijNotifications.delete(userId, packageName); + } + } + } + } + + private void maybeDeleteNotificationChannelAssociation(int userId, String packageName, + String notificationChannel) { + for (int i = mNotificationDetails.size() - 1; i >= 0; i--) { + final JobServiceContext jsc = mNotificationDetails.keyAt(i); + final NotificationDetails details = mNotificationDetails.get(jsc); + // Check if the details for the given notification match and if the associated job + // was started as a user initiated job + if (details != null + && UserHandle.getUserId(details.appUid) == userId + && details.userPackage.packageName.equals(packageName) + && details.notificationChannel.equals(notificationChannel)) { + final JobStatus jobStatus = jsc.getRunningJobLocked(); + if (jobStatus != null && jobStatus.startedAsUserInitiatedJob) { + return; + } + } + } + + // Safe to delete - no UIJs for this package are using this notification channel + synchronized (mUijLock) { + ArraySet<String> channels = mUijNotificationChannels.get(userId, packageName); + if (channels != null) { + channels.remove(notificationChannel); + if (channels.isEmpty()) { + mUijNotificationChannels.delete(userId, packageName); + } + } + } + } + + @GuardedBy("mUijLock") + private void maybeCreateUijNotificationSetsLocked(int userId, String packageName) { + if (mUijNotifications.get(userId, packageName) == null) { + mUijNotifications.add(userId, packageName, new IntArray()); + } + if (mUijNotificationChannels.get(userId, packageName) == null) { + mUijNotificationChannels.add(userId, packageName, new ArraySet<>()); } } 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 644d92cc5eaa..6eeff82f1158 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1588,12 +1588,12 @@ public class JobSchedulerService extends com.android.server.SystemService final ArrayMap<String, List<JobInfo>> outMap = new ArrayMap<>(); synchronized (mLock) { ArraySet<JobStatus> jobs = mJobs.getJobsByUid(uid); - // Write out for loop to avoid addAll() creating an Iterator. + // Write out for loop to avoid creating an Iterator. for (int i = jobs.size() - 1; i >= 0; i--) { final JobStatus job = jobs.valueAt(i); List<JobInfo> outList = outMap.get(job.getNamespace()); if (outList == null) { - outList = new ArrayList<JobInfo>(jobs.size()); + outList = new ArrayList<>(); outMap.put(job.getNamespace(), outList); } @@ -1606,7 +1606,7 @@ public class JobSchedulerService extends com.android.server.SystemService private List<JobInfo> getPendingJobsInNamespace(int uid, @Nullable String namespace) { synchronized (mLock) { ArraySet<JobStatus> jobs = mJobs.getJobsByUid(uid); - ArrayList<JobInfo> outList = new ArrayList<JobInfo>(jobs.size()); + ArrayList<JobInfo> outList = new ArrayList<>(); // Write out for loop to avoid addAll() creating an Iterator. for (int i = jobs.size() - 1; i >= 0; i--) { final JobStatus job = jobs.valueAt(i); @@ -3712,6 +3712,26 @@ public class JobSchedulerService extends com.android.server.SystemService } @Override + public boolean isNotificationAssociatedWithAnyUserInitiatedJobs(int notificationId, + int userId, @NonNull String packageName) { + if (packageName == null) { + return false; + } + return mConcurrencyManager.isNotificationAssociatedWithAnyUserInitiatedJobs( + notificationId, userId, packageName); + } + + @Override + public boolean isNotificationChannelAssociatedWithAnyUserInitiatedJobs( + @NonNull String notificationChannel, int userId, @NonNull String packageName) { + if (packageName == null || notificationChannel == null) { + return false; + } + return mConcurrencyManager.isNotificationChannelAssociatedWithAnyUserInitiatedJobs( + notificationChannel, userId, packageName); + } + + @Override public JobStorePersistStats getPersistStats() { synchronized (mLock) { return new JobStorePersistStats(mJobs.getPersistStats()); 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 44700c86efef..fb36cdec490f 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -1464,7 +1464,8 @@ public final class JobServiceContext implements ServiceConnection { JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT, String.valueOf(mRunningJob.getJobId())); } - mNotificationCoordinator.removeNotificationAssociation(this, reschedulingStopReason); + mNotificationCoordinator.removeNotificationAssociation(this, + reschedulingStopReason, completedJob); if (mWakeLock != null) { mWakeLock.release(); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java index fc6022859f5f..ba62e96b2a32 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java @@ -31,7 +31,7 @@ import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.expresslog.Counter; +import com.android.modules.expresslog.Counter; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateControllerProto; diff --git a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java index eb43c38f76a3..ef634b565b65 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java +++ b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java @@ -92,13 +92,17 @@ public class ThermalStatusRestriction extends JobRestriction { final int priority = job.getEffectivePriority(); if (mThermalStatus >= HIGHER_PRIORITY_THRESHOLD) { // For moderate throttling: - // Only let expedited & user-initiated jobs run if: + // Let all user-initiated jobs run. + // Only let expedited jobs run if: // 1. They haven't previously run // 2. They're already running and aren't yet in overtime // Only let high priority jobs run if: // They are already running and aren't yet in overtime // Don't let any other job run. - if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob()) { + if (job.shouldTreatAsUserInitiatedJob()) { + return false; + } + if (job.shouldTreatAsExpeditedJob()) { return job.getNumPreviousAttempts() > 0 || (mService.isCurrentlyRunningLocked(job) && mService.isJobInOvertimeLocked(job)); diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java index 7f6a75e75397..c7070695ecc2 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java @@ -1351,6 +1351,11 @@ public class InternalResourceService extends SystemService { } @Override + public int getEnabledMode() { + return InternalResourceService.this.getEnabledMode(); + } + + @Override public int handleShellCommand(@NonNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args) { diff --git a/boot/boot-image-profile.txt b/boot/boot-image-profile.txt index 996c3882701d..aebace57aa2c 100644 --- a/boot/boot-image-profile.txt +++ b/boot/boot-image-profile.txt @@ -33583,8 +33583,8 @@ Lcom/android/internal/dynamicanimation/animation/DynamicAnimation; Lcom/android/internal/dynamicanimation/animation/Force; Lcom/android/internal/dynamicanimation/animation/SpringAnimation; Lcom/android/internal/dynamicanimation/animation/SpringForce; -Lcom/android/internal/expresslog/Counter; -Lcom/android/internal/expresslog/Utils; +Lcom/android/modules/expresslog/Counter; +Lcom/android/modules/expresslog/Utils; Lcom/android/internal/graphics/ColorUtils$ContrastCalculator; Lcom/android/internal/graphics/ColorUtils; Lcom/android/internal/graphics/SfVsyncFrameCallbackProvider; diff --git a/boot/preloaded-classes b/boot/preloaded-classes index 21ae13474d84..4293caf57aea 100644 --- a/boot/preloaded-classes +++ b/boot/preloaded-classes @@ -10784,8 +10784,8 @@ com.android.internal.dynamicanimation.animation.DynamicAnimation com.android.internal.dynamicanimation.animation.Force com.android.internal.dynamicanimation.animation.SpringAnimation com.android.internal.dynamicanimation.animation.SpringForce -com.android.internal.expresslog.Counter -com.android.internal.expresslog.Utils +com.android.modules.expresslog.Counter +com.android.modules.expresslog.Utils com.android.internal.graphics.ColorUtils$ContrastCalculator com.android.internal.graphics.ColorUtils com.android.internal.graphics.SfVsyncFrameCallbackProvider diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index 699808156033..b6dc32a29f04 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -21,6 +21,7 @@ import android.annotation.UserIdInt; import android.app.backup.BackupManager; import android.app.backup.BackupManagerMonitor; import android.app.backup.BackupProgress; +import android.app.backup.BackupRestoreEventLogger; import android.app.backup.BackupTransport; import android.app.backup.IBackupManager; import android.app.backup.IBackupManagerMonitor; @@ -821,14 +822,22 @@ public class Bmgr { doRestorePackage(arg); } else { try { + @Monitor int monitor = Monitor.OFF; + long token = Long.parseLong(arg, 16); HashSet<String> filter = null; while ((arg = nextArg()) != null) { - if (filter == null) filter = new HashSet<String>(); - filter.add(arg); + if (arg.equals("--monitor")) { + monitor = Monitor.NORMAL; + } else if (arg.equals("--monitor-verbose")) { + monitor = Monitor.VERBOSE; + } else { + if (filter == null) filter = new HashSet<String>(); + filter.add(arg); + } } - doRestoreAll(userId, token, filter); + doRestoreAll(userId, token, filter, monitor); } catch (NumberFormatException e) { showUsage(); return; @@ -841,7 +850,8 @@ public class Bmgr { System.err.println("'restore <token> <package>'."); } - private void doRestoreAll(@UserIdInt int userId, long token, HashSet<String> filter) { + private void doRestoreAll(@UserIdInt int userId, long token, HashSet<String> filter, + @Monitor int monitorState) { RestoreObserver observer = new RestoreObserver(); try { @@ -852,8 +862,11 @@ public class Bmgr { return; } RestoreSet[] sets = null; - // TODO implement monitor here - int err = mRestore.getAvailableRestoreSets(observer, null); + BackupMonitor monitor = + (monitorState != Monitor.OFF) + ? new BackupMonitor(monitorState == Monitor.VERBOSE) + : null; + int err = mRestore.getAvailableRestoreSets(observer, monitor); if (err == 0) { observer.waitForCompletion(); sets = observer.sets; @@ -862,12 +875,12 @@ public class Bmgr { if (s.token == token) { System.out.println("Scheduling restore: " + s.name); if (filter == null) { - didRestore = (mRestore.restoreAll(token, observer, null) == 0); + didRestore = (mRestore.restoreAll(token, observer, monitor) == 0); } else { String[] names = new String[filter.size()]; filter.toArray(names); didRestore = (mRestore.restorePackages(token, observer, names, - null) == 0); + monitor) == 0); } break; } @@ -958,8 +971,8 @@ public class Bmgr { System.err.println(" bmgr list transports [-c]"); System.err.println(" bmgr list sets"); System.err.println(" bmgr transport WHICH|-c WHICH_COMPONENT"); - System.err.println(" bmgr restore TOKEN"); - System.err.println(" bmgr restore TOKEN PACKAGE..."); + System.err.println(" bmgr restore TOKEN [--monitor|--monitor-verbose]"); + System.err.println(" bmgr restore TOKEN PACKAGE... [--monitor|--monitor-verbose]"); System.err.println(" bmgr run"); System.err.println(" bmgr wipe TRANSPORT PACKAGE"); System.err.println(" bmgr fullbackup PACKAGE..."); @@ -1005,12 +1018,18 @@ public class Bmgr { System.err.println("restore operation from the currently active transport. It will deliver"); System.err.println("the restore set designated by the TOKEN argument to each application"); System.err.println("that had contributed data to that restore set."); + System.err.println(" --monitor flag prints monitor events (important events and errors"); + System.err.println(" encountered during restore)."); + System.err.println(" --monitor-verbose flag prints monitor events with all keys."); System.err.println(""); System.err.println("The 'restore' command when given a token and one or more package names"); System.err.println("initiates a restore operation of just those given packages from the restore"); System.err.println("set designated by the TOKEN argument. It is effectively the same as the"); System.err.println("'restore' operation supplying only a token, but applies a filter to the"); System.err.println("set of applications to be restored."); + System.err.println(" --monitor flag prints monitor events (important events and errors"); + System.err.println(" encountered during restore)."); + System.err.println(" --monitor-verbose flag prints monitor events with all keys."); System.err.println(""); System.err.println("The 'run' command causes any scheduled backup operation to be initiated"); System.err.println("immediately, without the usual waiting period for batching together"); @@ -1026,7 +1045,8 @@ public class Bmgr { System.err.println(""); System.err.println("The 'backupnow' command runs an immediate backup for one or more packages."); System.err.println(" --all flag runs backup for all eligible packages."); - System.err.println(" --monitor flag prints monitor events."); + System.err.println(" --monitor flag prints monitor events (important events and errors"); + System.err.println(" encountered during backup)."); System.err.println(" --monitor-verbose flag prints monitor events with all keys."); System.err.println("For each package it will run key/value or full data backup "); System.err.println("depending on the package's manifest declarations."); @@ -1076,6 +1096,37 @@ public class Bmgr { out.append("(v").append(version).append(")"); } } + if (event.containsKey(BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS)) { + ArrayList<BackupRestoreEventLogger.DataTypeResult> results = + event.getParcelableArrayList( + BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS, + BackupRestoreEventLogger.DataTypeResult.class); + out.append(", results = ["); + for (BackupRestoreEventLogger.DataTypeResult result : results) { + out.append("\n{\n\tdataType: "); + out.append(result.getDataType()); + out.append("\n\tsuccessCount: "); + out.append(result.getSuccessCount()); + out.append("\n\tfailCount: "); + out.append(result.getFailCount()); + out.append("\n\tmetadataHash: "); + out.append(Arrays.toString(result.getMetadataHash())); + + if (!result.getErrors().isEmpty()) { + out.append("\n\terrors: ["); + for (String error : result.getErrors().keySet()) { + out.append(error); + out.append(": "); + out.append(result.getErrors().get(error)); + out.append(";"); + } + out.append("]"); + } + out.append("\n}"); + + } + out.append("]"); + } if (mVerbose) { Set<String> remainingKeys = new ArraySet<>(event.keySet()); remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_ID); @@ -1083,6 +1134,7 @@ public class Bmgr { remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME); remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION); remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION); + remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS); if (!remainingKeys.isEmpty()) { out.append(", other keys ="); for (String key : remainingKeys) { @@ -1192,6 +1244,8 @@ public class Bmgr { return "NO_PACKAGES"; case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL: return "TRANSPORT_IS_NULL"; + case BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS: + return "AGENT_LOGGING_RESULTS"; default: return "UNKNOWN_ID"; } diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index c4e8b0e49af3..a8b6c0b70804 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -105,6 +105,7 @@ static const char PROGRESS_PROP_NAME[] = "service.bootanim.progress"; static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays"; static const char CLOCK_ENABLED_PROP_NAME[] = "persist.sys.bootanim.clock.enabled"; static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1; +static const int MAX_CHECK_EXIT_INTERVAL_US = 50000; static constexpr size_t TEXT_POS_LEN_MAX = 16; static const int DYNAMIC_COLOR_COUNT = 4; static const char U_TEXTURE[] = "uTexture"; @@ -1678,7 +1679,17 @@ bool BootAnimation::playAnimation(const Animation& animation) { checkExit(); } - usleep(part.pause * ns2us(frameDuration)); + int pauseDuration = part.pause * ns2us(frameDuration); + while(pauseDuration > 0 && !exitPending()){ + if (pauseDuration > MAX_CHECK_EXIT_INTERVAL_US) { + usleep(MAX_CHECK_EXIT_INTERVAL_US); + pauseDuration -= MAX_CHECK_EXIT_INTERVAL_US; + } else { + usleep(pauseDuration); + break; + } + checkExit(); + } if (exitPending() && !part.count && mCurrentInset >= mTargetInset && !part.hasFadingPhase()) { diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index 3cc990873c87..bb0748764cc8 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -43717,8 +43717,8 @@ Lcom/android/internal/dynamicanimation/animation/DynamicAnimation; Lcom/android/internal/dynamicanimation/animation/Force; Lcom/android/internal/dynamicanimation/animation/SpringAnimation; Lcom/android/internal/dynamicanimation/animation/SpringForce; -Lcom/android/internal/expresslog/Counter; -Lcom/android/internal/expresslog/Utils; +Lcom/android/modules/expresslog/Counter; +Lcom/android/modules/expresslog/Utils; Lcom/android/internal/graphics/ColorUtils$ContrastCalculator; Lcom/android/internal/graphics/ColorUtils; Lcom/android/internal/graphics/SfVsyncFrameCallbackProvider; diff --git a/config/preloaded-classes b/config/preloaded-classes index 8e50fe8e4e0f..1812c2bb61d6 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -10815,8 +10815,8 @@ com.android.internal.dynamicanimation.animation.DynamicAnimation com.android.internal.dynamicanimation.animation.Force com.android.internal.dynamicanimation.animation.SpringAnimation com.android.internal.dynamicanimation.animation.SpringForce -com.android.internal.expresslog.Counter -com.android.internal.expresslog.Utils +com.android.modules.expresslog.Counter +com.android.modules.expresslog.Utils com.android.internal.graphics.ColorUtils$ContrastCalculator com.android.internal.graphics.ColorUtils com.android.internal.graphics.SfVsyncFrameCallbackProvider diff --git a/core/api/current.txt b/core/api/current.txt index 80abd84733d7..288ab479c0fb 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -377,7 +377,7 @@ package android { public static final class R.attr { ctor public R.attr(); field public static final int absListViewStyle = 16842858; // 0x101006a - field public static final int accessibilityDataSensitive; + field public static final int accessibilityDataSensitive = 16844407; // 0x1010677 field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 field public static final int accessibilityFlags = 16843652; // 0x1010384 @@ -445,12 +445,12 @@ package android { field public static final int allowGameFpsOverride = 16844378; // 0x101065a field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612 field public static final int allowParallelSyncs = 16843570; // 0x1010332 - field public static final int allowSharedIsolatedProcess; + field public static final int allowSharedIsolatedProcess = 16844413; // 0x101067d field public static final int allowSingleTap = 16843353; // 0x1010259 field public static final int allowTaskReparenting = 16843268; // 0x1010204 field public static final int allowUndo = 16843999; // 0x10104df field public static final int allowUntrustedActivityEmbedding = 16844393; // 0x1010669 - field public static final int allowUpdateOwnership; + field public static final int allowUpdateOwnership = 16844416; // 0x1010680 field public static final int alpha = 16843551; // 0x101031f field public static final int alphabeticModifiers = 16844110; // 0x101054e field public static final int alphabeticShortcut = 16843235; // 0x10101e3 @@ -556,7 +556,7 @@ package android { field public static final int canTakeScreenshot = 16844303; // 0x101060f field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230 field public static final int cantSaveState = 16844142; // 0x101056e - field public static final int capability; + field public static final int capability = 16844423; // 0x1010687 field @Deprecated public static final int capitalize = 16843113; // 0x1010169 field public static final int category = 16843752; // 0x10103e8 field public static final int centerBright = 16842956; // 0x10100cc @@ -741,7 +741,7 @@ package android { field public static final int ellipsize = 16842923; // 0x10100ab field public static final int ems = 16843096; // 0x1010158 field public static final int enableOnBackInvokedCallback = 16844396; // 0x101066c - field public static final int enableTextStylingShortcuts; + field public static final int enableTextStylingShortcuts = 16844408; // 0x1010678 field public static final int enableVrMode = 16844069; // 0x1010525 field public static final int enabled = 16842766; // 0x101000e field public static final int end = 16843996; // 0x10104dc @@ -810,7 +810,7 @@ package android { field public static final int focusableInTouchMode = 16842971; // 0x10100db field public static final int focusedByDefault = 16844100; // 0x1010544 field @Deprecated public static final int focusedMonthDateColor = 16843587; // 0x1010343 - field public static final int focusedSearchResultHighlightColor; + field public static final int focusedSearchResultHighlightColor = 16844419; // 0x1010683 field public static final int font = 16844082; // 0x1010532 field public static final int fontFamily = 16843692; // 0x10103ac field public static final int fontFeatureSettings = 16843959; // 0x10104b7 @@ -896,10 +896,10 @@ package android { field public static final int hand_secondTintMode = 16844349; // 0x101063d field public static final int handle = 16843354; // 0x101025a field public static final int handleProfiling = 16842786; // 0x1010022 - field public static final int handwritingBoundsOffsetBottom; - field public static final int handwritingBoundsOffsetLeft; - field public static final int handwritingBoundsOffsetRight; - field public static final int handwritingBoundsOffsetTop; + field public static final int handwritingBoundsOffsetBottom = 16844406; // 0x1010676 + field public static final int handwritingBoundsOffsetLeft = 16844403; // 0x1010673 + field public static final int handwritingBoundsOffsetRight = 16844405; // 0x1010675 + field public static final int handwritingBoundsOffsetTop = 16844404; // 0x1010674 field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e field public static final int hardwareAccelerated = 16843475; // 0x10102d3 field public static final int hasCode = 16842764; // 0x101000c @@ -986,7 +986,7 @@ package android { field public static final int isAlwaysSyncable = 16843571; // 0x1010333 field public static final int isAsciiCapable = 16843753; // 0x10103e9 field public static final int isAuxiliary = 16843647; // 0x101037f - field public static final int isCredential; + field public static final int isCredential = 16844417; // 0x1010681 field public static final int isDefault = 16843297; // 0x1010221 field public static final int isFeatureSplit = 16844123; // 0x101055b field public static final int isGame = 16843764; // 0x10103f4 @@ -1021,8 +1021,8 @@ package android { field @Deprecated public static final int keyTextSize = 16843316; // 0x1010234 field @Deprecated public static final int keyWidth = 16843325; // 0x101023d field public static final int keyboardLayout = 16843691; // 0x10103ab - field public static final int keyboardLayoutType; - field public static final int keyboardLocale; + field public static final int keyboardLayoutType = 16844415; // 0x101067f + field public static final int keyboardLocale = 16844414; // 0x101067e field @Deprecated public static final int keyboardMode = 16843341; // 0x101024d field public static final int keyboardNavigationCluster = 16844096; // 0x1010540 field public static final int keycode = 16842949; // 0x10100c5 @@ -1263,8 +1263,8 @@ package android { field public static final int persistentDrawingCache = 16842990; // 0x10100ee field public static final int persistentWhenFeatureAvailable = 16844131; // 0x1010563 field @Deprecated public static final int phoneNumber = 16843111; // 0x1010167 - field public static final int physicalKeyboardHintLanguageTag; - field public static final int physicalKeyboardHintLayoutType; + field public static final int physicalKeyboardHintLanguageTag = 16844411; // 0x101067b + field public static final int physicalKeyboardHintLayoutType = 16844412; // 0x101067c field public static final int pivotX = 16843189; // 0x10101b5 field public static final int pivotY = 16843190; // 0x10101b6 field public static final int pointerIcon = 16844041; // 0x1010509 @@ -1354,7 +1354,7 @@ package android { field public static final int requireDeviceUnlock = 16843756; // 0x10103ec field public static final int required = 16843406; // 0x101028e field public static final int requiredAccountType = 16843734; // 0x10103d6 - field public static final int requiredDisplayCategory; + field public static final int requiredDisplayCategory = 16844409; // 0x1010679 field public static final int requiredFeature = 16844116; // 0x1010554 field public static final int requiredForAllUsers = 16843728; // 0x10103d0 field public static final int requiredNotFeature = 16844117; // 0x1010555 @@ -1422,7 +1422,7 @@ package android { field public static final int searchHintIcon = 16843988; // 0x10104d4 field public static final int searchIcon = 16843907; // 0x1010483 field public static final int searchMode = 16843221; // 0x10101d5 - field public static final int searchResultHighlightColor; + field public static final int searchResultHighlightColor = 16844418; // 0x1010682 field public static final int searchSettingsDescription = 16843402; // 0x101028a field public static final int searchSuggestAuthority = 16843222; // 0x10101d6 field public static final int searchSuggestIntentAction = 16843225; // 0x10101d9 @@ -1449,7 +1449,7 @@ package android { field public static final int sessionService = 16843837; // 0x101043d field public static final int settingsActivity = 16843301; // 0x1010225 field public static final int settingsSliceUri = 16844179; // 0x1010593 - field public static final int settingsSubtitle; + field public static final int settingsSubtitle = 16844422; // 0x1010686 field public static final int setupActivity = 16843766; // 0x10103f6 field public static final int shadowColor = 16843105; // 0x1010161 field public static final int shadowDx = 16843106; // 0x1010162 @@ -1555,7 +1555,7 @@ package android { field public static final int strokeLineJoin = 16843788; // 0x101040c field public static final int strokeMiterLimit = 16843789; // 0x101040d field public static final int strokeWidth = 16843783; // 0x1010407 - field public static final int stylusHandwritingSettingsActivity; + field public static final int stylusHandwritingSettingsActivity = 16844420; // 0x1010684 field public static final int subMenuArrow = 16844019; // 0x10104f3 field public static final int submitBackground = 16843912; // 0x1010488 field public static final int subtitle = 16843473; // 0x10102d1 @@ -1861,7 +1861,7 @@ package android { field public static final int windowMinWidthMajor = 16843606; // 0x1010356 field public static final int windowMinWidthMinor = 16843607; // 0x1010357 field public static final int windowNoDisplay = 16843294; // 0x101021e - field public static final int windowNoMoveAnimation; + field public static final int windowNoMoveAnimation = 16844421; // 0x1010685 field public static final int windowNoTitle = 16842838; // 0x1010056 field @Deprecated public static final int windowOverscan = 16843727; // 0x10103cf field public static final int windowReenterTransition = 16843951; // 0x10104af @@ -1966,18 +1966,18 @@ package android { field public static final int system_accent3_700 = 17170522; // 0x106005a field public static final int system_accent3_800 = 17170523; // 0x106005b field public static final int system_accent3_900 = 17170524; // 0x106005c - field public static final int system_background_dark; - field public static final int system_background_light; - field public static final int system_control_activated_dark; - field public static final int system_control_activated_light; - field public static final int system_control_highlight_dark; - field public static final int system_control_highlight_light; - field public static final int system_control_normal_dark; - field public static final int system_control_normal_light; - field public static final int system_error_container_dark; - field public static final int system_error_container_light; - field public static final int system_error_dark; - field public static final int system_error_light; + field public static final int system_background_dark = 17170581; // 0x1060095 + field public static final int system_background_light = 17170538; // 0x106006a + field public static final int system_control_activated_dark = 17170599; // 0x10600a7 + field public static final int system_control_activated_light = 17170556; // 0x106007c + field public static final int system_control_highlight_dark = 17170601; // 0x10600a9 + field public static final int system_control_highlight_light = 17170558; // 0x106007e + field public static final int system_control_normal_dark = 17170600; // 0x10600a8 + field public static final int system_control_normal_light = 17170557; // 0x106007d + field public static final int system_error_container_dark = 17170597; // 0x10600a5 + field public static final int system_error_container_light = 17170554; // 0x106007a + field public static final int system_error_dark = 17170595; // 0x10600a3 + field public static final int system_error_light = 17170552; // 0x1060078 field public static final int system_neutral1_0 = 17170461; // 0x106001d field public static final int system_neutral1_10 = 17170462; // 0x106001e field public static final int system_neutral1_100 = 17170464; // 0x1060020 @@ -2004,94 +2004,94 @@ package android { field public static final int system_neutral2_700 = 17170483; // 0x1060033 field public static final int system_neutral2_800 = 17170484; // 0x1060034 field public static final int system_neutral2_900 = 17170485; // 0x1060035 - field public static final int system_on_background_dark; - field public static final int system_on_background_light; - field public static final int system_on_error_container_dark; - field public static final int system_on_error_container_light; - field public static final int system_on_error_dark; - field public static final int system_on_error_light; - field public static final int system_on_primary_container_dark; - field public static final int system_on_primary_container_light; - field public static final int system_on_primary_dark; - field public static final int system_on_primary_fixed; - field public static final int system_on_primary_fixed_variant; - field public static final int system_on_primary_light; - field public static final int system_on_secondary_container_dark; - field public static final int system_on_secondary_container_light; - field public static final int system_on_secondary_dark; - field public static final int system_on_secondary_fixed; - field public static final int system_on_secondary_fixed_variant; - field public static final int system_on_secondary_light; - field public static final int system_on_surface_dark; - field public static final int system_on_surface_light; - field public static final int system_on_surface_variant_dark; - field public static final int system_on_surface_variant_light; - field public static final int system_on_tertiary_container_dark; - field public static final int system_on_tertiary_container_light; - field public static final int system_on_tertiary_dark; - field public static final int system_on_tertiary_fixed; - field public static final int system_on_tertiary_fixed_variant; - field public static final int system_on_tertiary_light; - field public static final int system_outline_dark; - field public static final int system_outline_light; - field public static final int system_outline_variant_dark; - field public static final int system_outline_variant_light; - field public static final int system_palette_key_color_neutral_dark; - field public static final int system_palette_key_color_neutral_light; - field public static final int system_palette_key_color_neutral_variant_dark; - field public static final int system_palette_key_color_neutral_variant_light; - field public static final int system_palette_key_color_primary_dark; - field public static final int system_palette_key_color_primary_light; - field public static final int system_palette_key_color_secondary_dark; - field public static final int system_palette_key_color_secondary_light; - field public static final int system_palette_key_color_tertiary_dark; - field public static final int system_palette_key_color_tertiary_light; - field public static final int system_primary_container_dark; - field public static final int system_primary_container_light; - field public static final int system_primary_dark; - field public static final int system_primary_fixed; - field public static final int system_primary_fixed_dim; - field public static final int system_primary_light; - field public static final int system_secondary_container_dark; - field public static final int system_secondary_container_light; - field public static final int system_secondary_dark; - field public static final int system_secondary_fixed; - field public static final int system_secondary_fixed_dim; - field public static final int system_secondary_light; - field public static final int system_surface_bright_dark; - field public static final int system_surface_bright_light; - field public static final int system_surface_container_dark; - field public static final int system_surface_container_high_dark; - field public static final int system_surface_container_high_light; - field public static final int system_surface_container_highest_dark; - field public static final int system_surface_container_highest_light; - field public static final int system_surface_container_light; - field public static final int system_surface_container_low_dark; - field public static final int system_surface_container_low_light; - field public static final int system_surface_container_lowest_dark; - field public static final int system_surface_container_lowest_light; - field public static final int system_surface_dark; - field public static final int system_surface_dim_dark; - field public static final int system_surface_dim_light; - field public static final int system_surface_light; - field public static final int system_surface_variant_dark; - field public static final int system_surface_variant_light; - field public static final int system_tertiary_container_dark; - field public static final int system_tertiary_container_light; - field public static final int system_tertiary_dark; - field public static final int system_tertiary_fixed; - field public static final int system_tertiary_fixed_dim; - field public static final int system_tertiary_light; - field public static final int system_text_hint_inverse_dark; - field public static final int system_text_hint_inverse_light; - field public static final int system_text_primary_inverse_dark; - field public static final int system_text_primary_inverse_disable_only_dark; - field public static final int system_text_primary_inverse_disable_only_light; - field public static final int system_text_primary_inverse_light; - field public static final int system_text_secondary_and_tertiary_inverse_dark; - field public static final int system_text_secondary_and_tertiary_inverse_disabled_dark; - field public static final int system_text_secondary_and_tertiary_inverse_disabled_light; - field public static final int system_text_secondary_and_tertiary_inverse_light; + field public static final int system_on_background_dark = 17170582; // 0x1060096 + field public static final int system_on_background_light = 17170539; // 0x106006b + field public static final int system_on_error_container_dark = 17170598; // 0x10600a6 + field public static final int system_on_error_container_light = 17170555; // 0x106007b + field public static final int system_on_error_dark = 17170596; // 0x10600a4 + field public static final int system_on_error_light = 17170553; // 0x1060079 + field public static final int system_on_primary_container_dark = 17170570; // 0x106008a + field public static final int system_on_primary_container_light = 17170527; // 0x106005f + field public static final int system_on_primary_dark = 17170572; // 0x106008c + field public static final int system_on_primary_fixed = 17170614; // 0x10600b6 + field public static final int system_on_primary_fixed_variant = 17170615; // 0x10600b7 + field public static final int system_on_primary_light = 17170529; // 0x1060061 + field public static final int system_on_secondary_container_dark = 17170574; // 0x106008e + field public static final int system_on_secondary_container_light = 17170531; // 0x1060063 + field public static final int system_on_secondary_dark = 17170576; // 0x1060090 + field public static final int system_on_secondary_fixed = 17170618; // 0x10600ba + field public static final int system_on_secondary_fixed_variant = 17170619; // 0x10600bb + field public static final int system_on_secondary_light = 17170533; // 0x1060065 + field public static final int system_on_surface_dark = 17170584; // 0x1060098 + field public static final int system_on_surface_light = 17170541; // 0x106006d + field public static final int system_on_surface_variant_dark = 17170593; // 0x10600a1 + field public static final int system_on_surface_variant_light = 17170550; // 0x1060076 + field public static final int system_on_tertiary_container_dark = 17170578; // 0x1060092 + field public static final int system_on_tertiary_container_light = 17170535; // 0x1060067 + field public static final int system_on_tertiary_dark = 17170580; // 0x1060094 + field public static final int system_on_tertiary_fixed = 17170622; // 0x10600be + field public static final int system_on_tertiary_fixed_variant = 17170623; // 0x10600bf + field public static final int system_on_tertiary_light = 17170537; // 0x1060069 + field public static final int system_outline_dark = 17170594; // 0x10600a2 + field public static final int system_outline_light = 17170551; // 0x1060077 + field public static final int system_outline_variant_dark = 17170625; // 0x10600c1 + field public static final int system_outline_variant_light = 17170624; // 0x10600c0 + field public static final int system_palette_key_color_neutral_dark = 17170610; // 0x10600b2 + field public static final int system_palette_key_color_neutral_light = 17170567; // 0x1060087 + field public static final int system_palette_key_color_neutral_variant_dark = 17170611; // 0x10600b3 + field public static final int system_palette_key_color_neutral_variant_light = 17170568; // 0x1060088 + field public static final int system_palette_key_color_primary_dark = 17170607; // 0x10600af + field public static final int system_palette_key_color_primary_light = 17170564; // 0x1060084 + field public static final int system_palette_key_color_secondary_dark = 17170608; // 0x10600b0 + field public static final int system_palette_key_color_secondary_light = 17170565; // 0x1060085 + field public static final int system_palette_key_color_tertiary_dark = 17170609; // 0x10600b1 + field public static final int system_palette_key_color_tertiary_light = 17170566; // 0x1060086 + field public static final int system_primary_container_dark = 17170569; // 0x1060089 + field public static final int system_primary_container_light = 17170526; // 0x106005e + field public static final int system_primary_dark = 17170571; // 0x106008b + field public static final int system_primary_fixed = 17170612; // 0x10600b4 + field public static final int system_primary_fixed_dim = 17170613; // 0x10600b5 + field public static final int system_primary_light = 17170528; // 0x1060060 + field public static final int system_secondary_container_dark = 17170573; // 0x106008d + field public static final int system_secondary_container_light = 17170530; // 0x1060062 + field public static final int system_secondary_dark = 17170575; // 0x106008f + field public static final int system_secondary_fixed = 17170616; // 0x10600b8 + field public static final int system_secondary_fixed_dim = 17170617; // 0x10600b9 + field public static final int system_secondary_light = 17170532; // 0x1060064 + field public static final int system_surface_bright_dark = 17170590; // 0x106009e + field public static final int system_surface_bright_light = 17170547; // 0x1060073 + field public static final int system_surface_container_dark = 17170587; // 0x106009b + field public static final int system_surface_container_high_dark = 17170588; // 0x106009c + field public static final int system_surface_container_high_light = 17170545; // 0x1060071 + field public static final int system_surface_container_highest_dark = 17170589; // 0x106009d + field public static final int system_surface_container_highest_light = 17170546; // 0x1060072 + field public static final int system_surface_container_light = 17170544; // 0x1060070 + field public static final int system_surface_container_low_dark = 17170585; // 0x1060099 + field public static final int system_surface_container_low_light = 17170542; // 0x106006e + field public static final int system_surface_container_lowest_dark = 17170586; // 0x106009a + field public static final int system_surface_container_lowest_light = 17170543; // 0x106006f + field public static final int system_surface_dark = 17170583; // 0x1060097 + field public static final int system_surface_dim_dark = 17170591; // 0x106009f + field public static final int system_surface_dim_light = 17170548; // 0x1060074 + field public static final int system_surface_light = 17170540; // 0x106006c + field public static final int system_surface_variant_dark = 17170592; // 0x10600a0 + field public static final int system_surface_variant_light = 17170549; // 0x1060075 + field public static final int system_tertiary_container_dark = 17170577; // 0x1060091 + field public static final int system_tertiary_container_light = 17170534; // 0x1060066 + field public static final int system_tertiary_dark = 17170579; // 0x1060093 + field public static final int system_tertiary_fixed = 17170620; // 0x10600bc + field public static final int system_tertiary_fixed_dim = 17170621; // 0x10600bd + field public static final int system_tertiary_light = 17170536; // 0x1060068 + field public static final int system_text_hint_inverse_dark = 17170606; // 0x10600ae + field public static final int system_text_hint_inverse_light = 17170563; // 0x1060083 + field public static final int system_text_primary_inverse_dark = 17170602; // 0x10600aa + field public static final int system_text_primary_inverse_disable_only_dark = 17170604; // 0x10600ac + field public static final int system_text_primary_inverse_disable_only_light = 17170561; // 0x1060081 + field public static final int system_text_primary_inverse_light = 17170559; // 0x106007f + field public static final int system_text_secondary_and_tertiary_inverse_dark = 17170603; // 0x10600ab + field public static final int system_text_secondary_and_tertiary_inverse_disabled_dark = 17170605; // 0x10600ad + field public static final int system_text_secondary_and_tertiary_inverse_disabled_light = 17170562; // 0x1060082 + field public static final int system_text_secondary_and_tertiary_inverse_light = 17170560; // 0x1060080 field public static final int tab_indicator_text = 17170441; // 0x1060009 field @Deprecated public static final int tertiary_text_dark = 17170448; // 0x1060010 field @Deprecated public static final int tertiary_text_light = 17170449; // 0x1060011 @@ -2310,7 +2310,7 @@ package android { field public static final int accessibilityActionPageUp = 16908358; // 0x1020046 field public static final int accessibilityActionPressAndHold = 16908362; // 0x102004a field public static final int accessibilityActionScrollDown = 16908346; // 0x102003a - field public static final int accessibilityActionScrollInDirection; + field public static final int accessibilityActionScrollInDirection = 16908382; // 0x102005e field public static final int accessibilityActionScrollLeft = 16908345; // 0x1020039 field public static final int accessibilityActionScrollRight = 16908347; // 0x102003b field public static final int accessibilityActionScrollToPosition = 16908343; // 0x1020037 @@ -2331,7 +2331,7 @@ package android { field public static final int addToDictionary = 16908330; // 0x102002a field public static final int autofill = 16908355; // 0x1020043 field public static final int background = 16908288; // 0x1020000 - field public static final int bold; + field public static final int bold = 16908379; // 0x102005b field public static final int button1 = 16908313; // 0x1020019 field public static final int button2 = 16908314; // 0x102001a field public static final int button3 = 16908315; // 0x102001b @@ -2357,7 +2357,7 @@ package android { field public static final int inputExtractAccessories = 16908378; // 0x102005a field public static final int inputExtractAction = 16908377; // 0x1020059 field public static final int inputExtractEditText = 16908325; // 0x1020025 - field public static final int italic; + field public static final int italic = 16908380; // 0x102005c field @Deprecated public static final int keyboardView = 16908326; // 0x1020026 field public static final int list = 16908298; // 0x102000a field public static final int list_container = 16908351; // 0x102003f @@ -2389,7 +2389,7 @@ package android { field public static final int textAssist = 16908353; // 0x1020041 field public static final int title = 16908310; // 0x1020016 field public static final int toggle = 16908311; // 0x1020017 - field public static final int underline; + field public static final int underline = 16908381; // 0x102005d field public static final int undo = 16908338; // 0x1020032 field public static final int widget_frame = 16908312; // 0x1020018 } @@ -13662,7 +13662,6 @@ package android.credentials { } public final class CredentialOption implements android.os.Parcelable { - ctor @Deprecated public CredentialOption(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.Bundle, boolean); method public int describeContents(); method @NonNull public java.util.Set<android.content.ComponentName> getAllowedProviders(); method @NonNull public android.os.Bundle getCandidateQueryData(); @@ -32653,7 +32652,7 @@ package android.os { field public static final int S = 31; // 0x1f field public static final int S_V2 = 32; // 0x20 field public static final int TIRAMISU = 33; // 0x21 - field public static final int UPSIDE_DOWN_CAKE = 10000; // 0x2710 + field public static final int UPSIDE_DOWN_CAKE = 34; // 0x22 } public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index fbc69e34a644..ace7d59c9a45 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -410,14 +410,14 @@ package android { field public static final int sdkVersion = 16844304; // 0x1010610 field public static final int supportsAmbientMode = 16844173; // 0x101058d field public static final int userRestriction = 16844164; // 0x1010584 - field public static final int visualQueryDetectionService; + field public static final int visualQueryDetectionService = 16844410; // 0x101067a } public static final class R.bool { - field public static final int config_enableDefaultNotes; - field public static final int config_enableDefaultNotesForWorkProfile; + field public static final int config_enableDefaultNotes = 17891338; // 0x111000a + field public static final int config_enableDefaultNotesForWorkProfile = 17891339; // 0x111000b field public static final int config_enableQrCodeScannerOnLockScreen = 17891336; // 0x1110008 - field public static final int config_safetyProtectionEnabled; + field public static final int config_safetyProtectionEnabled = 17891337; // 0x1110009 field public static final int config_sendPackageName = 17891328; // 0x1110000 field public static final int config_showDefaultAssistant = 17891329; // 0x1110001 field public static final int config_showDefaultEmergency = 17891330; // 0x1110002 @@ -430,7 +430,7 @@ package android { public static final class R.dimen { field public static final int config_restrictedIconSize = 17104903; // 0x1050007 - field public static final int config_viewConfigurationHandwritingGestureLineMargin; + field public static final int config_viewConfigurationHandwritingGestureLineMargin = 17104906; // 0x105000a } public static final class R.drawable { @@ -452,7 +452,7 @@ package android { field public static final int config_defaultCallRedirection = 17039397; // 0x1040025 field public static final int config_defaultCallScreening = 17039398; // 0x1040026 field public static final int config_defaultDialer = 17039395; // 0x1040023 - field public static final int config_defaultNotes; + field public static final int config_defaultNotes = 17039429; // 0x1040045 field public static final int config_defaultSms = 17039396; // 0x1040024 field public static final int config_devicePolicyManagement = 17039421; // 0x104003d field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f @@ -468,10 +468,10 @@ package android { field public static final int config_systemAutomotiveCalendarSyncManager = 17039423; // 0x104003f field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028 field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029 - field public static final int config_systemCallStreaming; + field public static final int config_systemCallStreaming = 17039431; // 0x1040047 field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039 field public static final int config_systemContacts = 17039403; // 0x104002b - field public static final int config_systemFinancedDeviceController; + field public static final int config_systemFinancedDeviceController = 17039430; // 0x1040046 field public static final int config_systemGallery = 17039399; // 0x1040027 field public static final int config_systemNotificationIntelligence = 17039413; // 0x1040035 field public static final int config_systemSettingsIntelligence = 17039426; // 0x1040042 @@ -483,7 +483,7 @@ package android { field public static final int config_systemUi = 17039418; // 0x104003a field public static final int config_systemUiIntelligence = 17039410; // 0x1040032 field public static final int config_systemVisualIntelligence = 17039415; // 0x1040037 - field public static final int config_systemWearHealthService; + field public static final int config_systemWearHealthService = 17039428; // 0x1040044 field public static final int config_systemWellbeing = 17039408; // 0x1040030 field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f field public static final int safety_protection_display_text = 17039425; // 0x1040041 @@ -10117,7 +10117,7 @@ package android.net.wifi.sharedconnectivity.app { public final class NetworkProviderInfo implements android.os.Parcelable { method public int describeContents(); method @IntRange(from=0, to=100) public int getBatteryPercentage(); - method @IntRange(from=0, to=3) public int getConnectionStrength(); + method @IntRange(from=0, to=4) public int getConnectionStrength(); method @NonNull public String getDeviceName(); method public int getDeviceType(); method @NonNull public android.os.Bundle getExtras(); @@ -10136,7 +10136,7 @@ package android.net.wifi.sharedconnectivity.app { ctor public NetworkProviderInfo.Builder(@NonNull String, @NonNull String); method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo build(); method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setBatteryPercentage(@IntRange(from=0, to=100) int); - method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setConnectionStrength(@IntRange(from=0, to=3) int); + method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setConnectionStrength(@IntRange(from=0, to=4) int); method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceName(@NonNull String); method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceType(int); method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setExtras(@NonNull android.os.Bundle); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 873234a04460..2d9a99cf0d8c 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -8,8 +8,6 @@ package android { 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"; @@ -338,10 +336,12 @@ package android.app { } public class Notification implements android.os.Parcelable { + method public boolean isUserInitiatedJob(); method public boolean shouldShowForegroundImmediately(); field public static final String EXTRA_MEDIA_REMOTE_DEVICE = "android.mediaRemoteDevice"; field public static final String EXTRA_MEDIA_REMOTE_ICON = "android.mediaRemoteIcon"; field public static final String EXTRA_MEDIA_REMOTE_INTENT = "android.mediaRemoteIntent"; + field public static final int FLAG_USER_INITIATED_JOB = 32768; // 0x8000 } public final class NotificationChannel implements android.os.Parcelable { @@ -351,10 +351,10 @@ package android.app { method public void setDeleted(boolean); method public void setDeletedTimeMs(long); method public void setDemoted(boolean); - method public void setFgServiceShown(boolean); method public void setImportanceLockedByCriticalDeviceFunction(boolean); method public void setImportantConversation(boolean); method public void setOriginalImportance(int); + method public void setUserVisibleTaskShown(boolean); } public final class NotificationChannelGroup implements android.os.Parcelable { @@ -777,6 +777,17 @@ package android.app.prediction { } +package android.app.tare { + + public class EconomyManager { + method public int getEnabledMode(); + field public static final int ENABLED_MODE_OFF = 0; // 0x0 + field public static final int ENABLED_MODE_SHADOW = 2; // 0x2 + field public static final String KEY_ENABLE_TARE_MODE = "enable_tare_mode"; + } + +} + package android.app.usage { public class StorageStatsManager { @@ -1649,6 +1660,11 @@ package android.hardware.soundtrigger { field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.KeyphraseMetadata> CREATOR; } + public class SoundTrigger { + field public static final int MODEL_PARAM_INVALID = -1; // 0xffffffff + field public static final int MODEL_PARAM_THRESHOLD_FACTOR = 0; // 0x0 + } + public static final class SoundTrigger.KeyphraseRecognitionExtra implements android.os.Parcelable { ctor public SoundTrigger.KeyphraseRecognitionExtra(int, int, int); } @@ -1661,6 +1677,19 @@ package android.hardware.soundtrigger { ctor public SoundTrigger.ModuleProperties(int, @NonNull String, @NonNull String, @NonNull String, int, @NonNull String, int, int, int, int, boolean, int, boolean, int, boolean, int); } + public static final class SoundTrigger.RecognitionConfig implements android.os.Parcelable { + ctor public SoundTrigger.RecognitionConfig(boolean, boolean, @Nullable android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra[], @Nullable byte[], int); + ctor public SoundTrigger.RecognitionConfig(boolean, boolean, @Nullable android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra[], @Nullable byte[]); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.RecognitionConfig> CREATOR; + field public final boolean allowMultipleTriggers; + field public final int audioCapabilities; + field public final boolean captureRequested; + field @NonNull public final byte[] data; + field @NonNull public final android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra[] keyphrases; + } + public static class SoundTrigger.RecognitionEvent { ctor public SoundTrigger.RecognitionEvent(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], long); } @@ -1998,6 +2027,57 @@ package android.media.metrics { } +package android.media.soundtrigger { + + public final class SoundTriggerInstrumentation { + method public void setResourceContention(boolean); + method public void triggerOnResourcesAvailable(); + method public void triggerRestart(); + } + + public static interface SoundTriggerInstrumentation.GlobalCallback { + method public default void onClientAttached(); + method public default void onClientDetached(); + method public default void onFrameworkDetached(); + method public void onModelLoaded(@NonNull android.media.soundtrigger.SoundTriggerInstrumentation.ModelSession); + method public default void onPreempted(); + method public default void onRestarted(); + } + + public static interface SoundTriggerInstrumentation.ModelCallback { + method public default void onModelUnloaded(); + method public default void onParamSet(int, int); + method public void onRecognitionStarted(@NonNull android.media.soundtrigger.SoundTriggerInstrumentation.RecognitionSession); + } + + public class SoundTriggerInstrumentation.ModelSession { + method public void clearModelCallback(); + method @NonNull public java.util.List<android.hardware.soundtrigger.SoundTrigger.Keyphrase> getPhrases(); + method @NonNull public android.media.soundtrigger.SoundTriggerManager.Model getSoundModel(); + method public boolean isKeyphrase(); + method public void setModelCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.soundtrigger.SoundTriggerInstrumentation.ModelCallback); + method public void triggerUnloadModel(); + } + + public static interface SoundTriggerInstrumentation.RecognitionCallback { + method public void onRecognitionStopped(); + } + + public class SoundTriggerInstrumentation.RecognitionSession { + method public void clearRecognitionCallback(); + method public int getAudioSession(); + method @NonNull public android.hardware.soundtrigger.SoundTrigger.RecognitionConfig getRecognitionConfig(); + method public void setRecognitionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.soundtrigger.SoundTriggerInstrumentation.RecognitionCallback); + method public void triggerAbortRecognition(); + method public void triggerRecognitionEvent(@NonNull byte[], @Nullable java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>); + } + + public final class SoundTriggerManager { + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public static android.media.soundtrigger.SoundTriggerInstrumentation attachInstrumentation(@NonNull java.util.concurrent.Executor, @NonNull android.media.soundtrigger.SoundTriggerInstrumentation.GlobalCallback); + } + +} + package android.media.tv { public final class TvInputManager { @@ -2022,6 +2102,14 @@ package android.media.tv.tuner { } +package android.media.voice { + + public final class KeyphraseModelManager { + method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void setModelDatabaseForTestEnabled(boolean); + } + +} + package android.net { public class NetworkPolicyManager { @@ -2275,12 +2363,12 @@ package android.os { method public int getMainDisplayIdAssignedToUser(); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.Set<java.lang.String> getPreInstallableSystemPackages(@NonNull String); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public String getUserType(); - method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean); + method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isUserTypeEnabled(@NonNull String); method public boolean isVisibleBackgroundUsersOnDefaultDisplaySupported(); method public boolean isVisibleBackgroundUsersSupported(); - method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo preCreateUser(@NonNull String) throws android.os.UserManager.UserOperationException; + method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo preCreateUser(@NonNull String) throws android.os.UserManager.UserOperationException; } public final class VibrationAttributes implements android.os.Parcelable { @@ -2942,6 +3030,7 @@ package android.service.voice { method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetectorForTest(@NonNull String, @NonNull java.util.Locale, @NonNull android.hardware.soundtrigger.SoundTrigger.ModuleProperties, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.AlwaysOnHotwordDetector.Callback); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetectorForTest(@NonNull String, @NonNull java.util.Locale, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.hardware.soundtrigger.SoundTrigger.ModuleProperties, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.AlwaysOnHotwordDetector.Callback); method @NonNull public final java.util.List<android.hardware.soundtrigger.SoundTrigger.ModuleProperties> listModuleProperties(); + method public final void setTestModuleForAlwaysOnHotwordDetectorEnabled(boolean); } public static class VoiceInteractionSession.ActivityId { @@ -3349,8 +3438,14 @@ package android.view { method @NonNull public android.hardware.input.InputDeviceIdentifier getIdentifier(); } + public abstract class InputEvent implements android.os.Parcelable { + method public abstract int getDisplayId(); + method public abstract void setDisplayId(int); + } + public class KeyEvent extends android.view.InputEvent implements android.os.Parcelable { method public static String actionToString(int); + method public final int getDisplayId(); method public final void setDisplayId(int); field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800 field public static final int LAST_KEYCODE = 316; // 0x13c diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 3615435b7d75..08a1af47ee64 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -2878,9 +2878,7 @@ public abstract class AccessibilityService extends Service { public IAccessibilityServiceClientWrapper(Context context, Looper looper, Callbacks callback) { - mCallback = callback; - mContext = context; - mExecutor = new HandlerExecutor(new Handler(looper)); + this(context, new HandlerExecutor(new Handler(looper)), callback); } public void init(IAccessibilityServiceConnection connection, int connectionId, diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 0293bb53d3f0..95e446dde4da 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -343,7 +343,170 @@ public abstract class ActivityManagerInternal { */ public abstract boolean hasRunningActivity(int uid, @Nullable String packageName); - public abstract void updateOomAdj(); + /** + * Oom Adj Reason: none - internal use only, do not use it. + * @hide + */ + public static final int OOM_ADJ_REASON_NONE = 0; + + /** + * Oom Adj Reason: activity changes. + * @hide + */ + public static final int OOM_ADJ_REASON_ACTIVITY = 1; + + /** + * Oom Adj Reason: finishing a broadcast receiver. + * @hide + */ + public static final int OOM_ADJ_REASON_FINISH_RECEIVER = 2; + + /** + * Oom Adj Reason: starting a broadcast receiver. + * @hide + */ + public static final int OOM_ADJ_REASON_START_RECEIVER = 3; + + /** + * Oom Adj Reason: binding to a service. + * @hide + */ + public static final int OOM_ADJ_REASON_BIND_SERVICE = 4; + + /** + * Oom Adj Reason: unbinding from a service. + * @hide + */ + public static final int OOM_ADJ_REASON_UNBIND_SERVICE = 5; + + /** + * Oom Adj Reason: starting a service. + * @hide + */ + public static final int OOM_ADJ_REASON_START_SERVICE = 6; + + /** + * Oom Adj Reason: connecting to a content provider. + * @hide + */ + public static final int OOM_ADJ_REASON_GET_PROVIDER = 7; + + /** + * Oom Adj Reason: disconnecting from a content provider. + * @hide + */ + public static final int OOM_ADJ_REASON_REMOVE_PROVIDER = 8; + + /** + * Oom Adj Reason: UI visibility changes. + * @hide + */ + public static final int OOM_ADJ_REASON_UI_VISIBILITY = 9; + + /** + * Oom Adj Reason: device power allowlist changes. + * @hide + */ + public static final int OOM_ADJ_REASON_ALLOWLIST = 10; + + /** + * Oom Adj Reason: starting a process. + * @hide + */ + public static final int OOM_ADJ_REASON_PROCESS_BEGIN = 11; + + /** + * Oom Adj Reason: ending a process. + * @hide + */ + public static final int OOM_ADJ_REASON_PROCESS_END = 12; + + /** + * Oom Adj Reason: short FGS timeout. + * @hide + */ + public static final int OOM_ADJ_REASON_SHORT_FGS_TIMEOUT = 13; + + /** + * Oom Adj Reason: system initialization. + * @hide + */ + public static final int OOM_ADJ_REASON_SYSTEM_INIT = 14; + + /** + * Oom Adj Reason: backup/restore. + * @hide + */ + public static final int OOM_ADJ_REASON_BACKUP = 15; + + /** + * Oom Adj Reason: instrumented by the SHELL. + * @hide + */ + public static final int OOM_ADJ_REASON_SHELL = 16; + + /** + * Oom Adj Reason: task stack is being removed. + */ + public static final int OOM_ADJ_REASON_REMOVE_TASK = 17; + + /** + * Oom Adj Reason: uid idle. + */ + public static final int OOM_ADJ_REASON_UID_IDLE = 18; + + /** + * Oom Adj Reason: stop service. + */ + public static final int OOM_ADJ_REASON_STOP_SERVICE = 19; + + /** + * Oom Adj Reason: executing service. + */ + public static final int OOM_ADJ_REASON_EXECUTING_SERVICE = 20; + + /** + * Oom Adj Reason: background restriction changes. + */ + public static final int OOM_ADJ_REASON_RESTRICTION_CHANGE = 21; + + /** + * Oom Adj Reason: A package or its component is disabled. + */ + public static final int OOM_ADJ_REASON_COMPONENT_DISABLED = 22; + + @IntDef(prefix = {"OOM_ADJ_REASON_"}, value = { + OOM_ADJ_REASON_NONE, + OOM_ADJ_REASON_ACTIVITY, + OOM_ADJ_REASON_FINISH_RECEIVER, + OOM_ADJ_REASON_START_RECEIVER, + OOM_ADJ_REASON_BIND_SERVICE, + OOM_ADJ_REASON_UNBIND_SERVICE, + OOM_ADJ_REASON_START_SERVICE, + OOM_ADJ_REASON_GET_PROVIDER, + OOM_ADJ_REASON_REMOVE_PROVIDER, + OOM_ADJ_REASON_UI_VISIBILITY, + OOM_ADJ_REASON_ALLOWLIST, + OOM_ADJ_REASON_PROCESS_BEGIN, + OOM_ADJ_REASON_PROCESS_END, + OOM_ADJ_REASON_SHORT_FGS_TIMEOUT, + OOM_ADJ_REASON_SYSTEM_INIT, + OOM_ADJ_REASON_BACKUP, + OOM_ADJ_REASON_SHELL, + OOM_ADJ_REASON_REMOVE_TASK, + OOM_ADJ_REASON_UID_IDLE, + OOM_ADJ_REASON_STOP_SERVICE, + OOM_ADJ_REASON_EXECUTING_SERVICE, + OOM_ADJ_REASON_RESTRICTION_CHANGE, + OOM_ADJ_REASON_COMPONENT_DISABLED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface OomAdjReason {} + + /** + * Request to update oom adj. + */ + public abstract void updateOomAdj(@OomAdjReason int oomAdjReason); public abstract void updateCpuStats(); /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7b4aeeca2855..29e135f8b0e9 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -41,6 +41,7 @@ import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.RemoteServiceException.BadForegroundServiceNotificationException; +import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException; import android.app.RemoteServiceException.CannotPostForegroundServiceNotificationException; import android.app.RemoteServiceException.CrashedByAdbException; import android.app.RemoteServiceException.ForegroundServiceDidNotStartInTimeException; @@ -2078,6 +2079,9 @@ public final class ActivityThread extends ClientTransactionHandler case BadForegroundServiceNotificationException.TYPE_ID: throw new BadForegroundServiceNotificationException(message); + case BadUserInitiatedJobNotificationException.TYPE_ID: + throw new BadUserInitiatedJobNotificationException(message); + case MissingRequestPasswordComplexityPermissionException.TYPE_ID: throw new MissingRequestPasswordComplexityPermissionException(message); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index b48a8fb73832..3312294865d6 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1450,9 +1450,8 @@ public class AppOpsManager { public static final int OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD = AppProtoEnums.APP_OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD; - /** @hide Access to wrist temperature sensors. */ - public static final int OP_BODY_SENSORS_WRIST_TEMPERATURE = - AppProtoEnums.APP_OP_BODY_SENSORS_WRIST_TEMPERATURE; + // App op deprecated/removed. + private static final int OP_DEPRECATED_2 = AppProtoEnums.APP_OP_BODY_SENSORS_WRIST_TEMPERATURE; /** * Send an intent to launch instead of posting the notification to the status bar. @@ -1461,9 +1460,25 @@ public class AppOpsManager { */ public static final int OP_USE_FULL_SCREEN_INTENT = AppProtoEnums.APP_OP_USE_FULL_SCREEN_INTENT; + /** + * Hides camera indicator for sandboxed detection apps that directly access the service. + * + * @hide + */ + public static final int OP_CAMERA_SANDBOXED = + AppProtoEnums.APP_OP_CAMERA_SANDBOXED; + + /** + * Hides microphone indicator for sandboxed detection apps that directly access the service. + * + * @hide + */ + public static final int OP_RECORD_AUDIO_SANDBOXED = + AppProtoEnums.APP_OP_RECORD_AUDIO_SANDBOXED; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 134; + public static final int _NUM_OP = 136; /** * All app ops represented as strings. @@ -1603,8 +1618,9 @@ public class AppOpsManager { OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION, OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION, OPSTR_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD, - OPSTR_BODY_SENSORS_WRIST_TEMPERATURE, OPSTR_USE_FULL_SCREEN_INTENT, + OPSTR_CAMERA_SANDBOXED, + OPSTR_RECORD_AUDIO_SANDBOXED }) public @interface AppOpString {} @@ -2013,6 +2029,20 @@ public class AppOpsManager { public static final String OPSTR_COARSE_LOCATION_SOURCE = "android:coarse_location_source"; /** + * Camera is being recorded in sandboxed detection process. + * + * @hide + */ + public static final String OPSTR_CAMERA_SANDBOXED = "android:camera_sandboxed"; + + /** + * Audio is being recorded in sandboxed detection process. + * + * @hide + */ + public static final String OPSTR_RECORD_AUDIO_SANDBOXED = "android:record_audio_sandboxed"; + + /** * Allow apps to create the requests to manage the media files without user confirmation. * * @see android.Manifest.permission#MANAGE_MEDIA @@ -2189,11 +2219,10 @@ public class AppOpsManager { "android:capture_consentless_bugreport_on_userdebug_build"; /** - * Access to wrist temperature body sensors. + * App op deprecated/removed. * @hide */ - public static final String OPSTR_BODY_SENSORS_WRIST_TEMPERATURE = - "android:body_sensors_wrist_temperature"; + public static final String OPSTR_DEPRECATED_2 = "android:deprecated_2"; /** * Send an intent to launch instead of posting the notification to the status bar. @@ -2311,7 +2340,6 @@ public class AppOpsManager { OP_READ_MEDIA_VISUAL_USER_SELECTED, OP_FOREGROUND_SERVICE_SPECIAL_USE, OP_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD, - OP_BODY_SENSORS_WRIST_TEMPERATURE, OP_USE_FULL_SCREEN_INTENT }; @@ -2731,14 +2759,15 @@ public class AppOpsManager { "CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD") .setPermission(Manifest.permission.CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD) .build(), - new AppOpInfo.Builder(OP_BODY_SENSORS_WRIST_TEMPERATURE, - OPSTR_BODY_SENSORS_WRIST_TEMPERATURE, - "BODY_SENSORS_WRIST_TEMPERATURE") - .setPermission(Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE) - .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), + new AppOpInfo.Builder(OP_DEPRECATED_2, OPSTR_DEPRECATED_2, "DEPRECATED_2") + .setDefaultMode(AppOpsManager.MODE_IGNORED).build(), new AppOpInfo.Builder(OP_USE_FULL_SCREEN_INTENT, OPSTR_USE_FULL_SCREEN_INTENT, "USE_FULL_SCREEN_INTENT").setPermission(Manifest.permission.USE_FULL_SCREEN_INTENT) - .build() + .build(), + new AppOpInfo.Builder(OP_CAMERA_SANDBOXED, OPSTR_CAMERA_SANDBOXED, + "CAMERA_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), + new AppOpInfo.Builder(OP_RECORD_AUDIO_SANDBOXED, OPSTR_RECORD_AUDIO_SANDBOXED, + "RECORD_AUDIO_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build() }; // The number of longs needed to form a full bitmask of app ops diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java index be012cf8e202..c0c59a24dd8d 100644 --- a/core/java/android/app/ForegroundServiceTypePolicy.java +++ b/core/java/android/app/ForegroundServiceTypePolicy.java @@ -473,7 +473,6 @@ public abstract class ForegroundServiceTypePolicy { new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { new RegularPermission(Manifest.permission.ACTIVITY_RECOGNITION), new RegularPermission(Manifest.permission.BODY_SENSORS), - new RegularPermission(Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE), new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS), }, false), FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH /* permissionEnforcementFlag */, diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 746b8f70b6af..0b4862176040 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -24,6 +24,7 @@ import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationHistory; import android.app.NotificationManager; +import android.content.AttributionSource; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ParceledListSlice; @@ -225,6 +226,7 @@ interface INotificationManager void setNotificationDelegate(String callingPkg, String delegate); String getNotificationDelegate(String callingPkg); boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId); + boolean canUseFullScreenIntent(in AttributionSource attributionSource); void setPrivateNotificationsAllowed(boolean allow); boolean getPrivateNotificationsAllowed(); diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index ee242635bfb2..2b1558937d21 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -220,6 +220,20 @@ interface IWallpaperManager { void notifyGoingToSleep(int x, int y, in Bundle extras); /** + * Called when the screen has been fully turned on and is visible. + * + * @hide + */ + void notifyScreenTurnedOn(int displayId); + + /** + * Called when the screen starts turning on. + * + * @hide + */ + void notifyScreenTurningOn(int displayId); + + /** * Sets the wallpaper dim amount between [0f, 1f] which would be blended with the system default * dimming. 0f doesn't add any additional dimming and 1f makes the wallpaper fully black. * diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index c131ce574d2c..e31486f18dbf 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -2354,8 +2354,7 @@ public class Instrumentation { return mUiAutomation; } if (mustCreateNewAutomation) { - mUiAutomation = new UiAutomation(getTargetContext().getMainLooper(), - mUiAutomationConnection); + mUiAutomation = new UiAutomation(getTargetContext(), mUiAutomationConnection); } else { mUiAutomation.disconnect(); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 96d785f0df9c..63da0a231286 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -722,6 +722,16 @@ public class Notification implements Parcelable */ public static final int FLAG_FSI_REQUESTED_BUT_DENIED = 0x00004000; + /** + * Bit to be bitwise-ored into the {@link #flags} field that should be + * set if this notification represents a currently running user-initiated job. + * + * This flag is for internal use only; applications cannot set this flag directly. + * @hide + */ + @TestApi + public static final int FLAG_USER_INITIATED_JOB = 0x00008000; + private static final List<Class<? extends Style>> PLATFORM_STYLE_CLASSES = Arrays.asList( BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class, DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class, @@ -731,7 +741,8 @@ public class Notification implements Parcelable @IntDef(flag = true, prefix = { "FLAG_" }, value = {FLAG_SHOW_LIGHTS, FLAG_ONGOING_EVENT, FLAG_INSISTENT, FLAG_ONLY_ALERT_ONCE, FLAG_AUTO_CANCEL, FLAG_NO_CLEAR, FLAG_FOREGROUND_SERVICE, FLAG_HIGH_PRIORITY, - FLAG_LOCAL_ONLY, FLAG_GROUP_SUMMARY, FLAG_AUTOGROUP_SUMMARY, FLAG_BUBBLE}) + FLAG_LOCAL_ONLY, FLAG_GROUP_SUMMARY, FLAG_AUTOGROUP_SUMMARY, FLAG_BUBBLE, + FLAG_USER_INITIATED_JOB}) @Retention(RetentionPolicy.SOURCE) public @interface NotificationFlags{}; @@ -5727,7 +5738,8 @@ public class Notification implements Parcelable } private void bindSnoozeAction(RemoteViews big, StandardTemplateParams p) { - boolean hideSnoozeButton = mN.isForegroundService() || mN.fullScreenIntent != null + boolean hideSnoozeButton = mN.isFgsOrUij() + || mN.fullScreenIntent != null || isBackgroundColorized(p) || p.mViewType != StandardTemplateParams.VIEW_TYPE_BIG; big.setBoolean(R.id.snooze_button, "setEnabled", !hideSnoozeButton); @@ -6868,6 +6880,24 @@ public class Notification implements Parcelable } /** + * @return whether this notification is associated with a user initiated job + * @hide + */ + @TestApi + public boolean isUserInitiatedJob() { + return (flags & Notification.FLAG_USER_INITIATED_JOB) != 0; + } + + /** + * @return whether this notification is associated with either a foreground service or + * a user initiated job + * @hide + */ + public boolean isFgsOrUij() { + return isForegroundService() || isUserInitiatedJob(); + } + + /** * Describe whether this notification's content such that it should always display * immediately when tied to a foreground service, even if the system might generally * avoid showing the notifications for short-lived foreground service lifetimes. @@ -6986,6 +7016,22 @@ public class Notification implements Parcelable } /** + * @return true for custom notifications, including notifications + * with DecoratedCustomViewStyle or DecoratedMediaCustomViewStyle, + * and other notifications with user-provided custom views. + * + * @hide + */ + public Boolean isCustomNotification() { + if (contentView == null + && bigContentView == null + && headsUpContentView == null) { + return false; + } + return true; + } + + /** * @return true if this notification is showing as a bubble * * @hide diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 9615b684ee4b..746dcb6f2e13 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -32,7 +32,6 @@ import android.os.Parcelable; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.text.TextUtils; -import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.util.Preconditions; @@ -150,6 +149,10 @@ public final class NotificationChannel implements Parcelable { private static final String ATT_CONTENT_TYPE = "content_type"; private static final String ATT_SHOW_BADGE = "show_badge"; private static final String ATT_USER_LOCKED = "locked"; + /** + * This attribute represents both foreground services and user initiated jobs in U+. + * It was not renamed in U on purpose, in order to avoid creating an unnecessary migration path. + */ private static final String ATT_FG_SERVICE_SHOWN = "fgservice"; private static final String ATT_GROUP = "group"; private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system"; @@ -249,7 +252,7 @@ public final class NotificationChannel implements Parcelable { // Bitwise representation of fields that have been changed by the user, preventing the app from // making changes to these fields. private int mUserLockedFields; - private boolean mFgServiceShown; + private boolean mUserVisibleTaskShown; private boolean mVibrationEnabled; private boolean mShowBadge = DEFAULT_SHOW_BADGE; private boolean mDeleted = DEFAULT_DELETED; @@ -317,7 +320,7 @@ public final class NotificationChannel implements Parcelable { mVibration = Arrays.copyOf(mVibration, MAX_VIBRATION_LENGTH); } mUserLockedFields = in.readInt(); - mFgServiceShown = in.readByte() != 0; + mUserVisibleTaskShown = in.readByte() != 0; mVibrationEnabled = in.readByte() != 0; mShowBadge = in.readByte() != 0; mDeleted = in.readByte() != 0; @@ -371,7 +374,7 @@ public final class NotificationChannel implements Parcelable { dest.writeByte(mLights ? (byte) 1 : (byte) 0); dest.writeLongArray(mVibration); dest.writeInt(mUserLockedFields); - dest.writeByte(mFgServiceShown ? (byte) 1 : (byte) 0); + dest.writeByte(mUserVisibleTaskShown ? (byte) 1 : (byte) 0); dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0); dest.writeByte(mShowBadge ? (byte) 1 : (byte) 0); dest.writeByte(mDeleted ? (byte) 1 : (byte) 0); @@ -418,8 +421,8 @@ public final class NotificationChannel implements Parcelable { * @hide */ @TestApi - public void setFgServiceShown(boolean shown) { - mFgServiceShown = shown; + public void setUserVisibleTaskShown(boolean shown) { + mUserVisibleTaskShown = shown; } /** @@ -845,8 +848,8 @@ public final class NotificationChannel implements Parcelable { /** * @hide */ - public boolean isFgServiceShown() { - return mFgServiceShown; + public boolean isUserVisibleTaskShown() { + return mUserVisibleTaskShown; } /** @@ -965,7 +968,7 @@ public final class NotificationChannel implements Parcelable { parser, ATT_DELETED_TIME_MS, DEFAULT_DELETION_TIME_MS)); setGroup(parser.getAttributeValue(null, ATT_GROUP)); lockFields(safeInt(parser, ATT_USER_LOCKED, 0)); - setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false)); + setUserVisibleTaskShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false)); setBlockable(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false)); setAllowBubbles(safeInt(parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE)); setOriginalImportance(safeInt(parser, ATT_ORIG_IMP, DEFAULT_IMPORTANCE)); @@ -1072,8 +1075,8 @@ public final class NotificationChannel implements Parcelable { if (getUserLockedFields() != 0) { out.attributeInt(null, ATT_USER_LOCKED, getUserLockedFields()); } - if (isFgServiceShown()) { - out.attributeBoolean(null, ATT_FG_SERVICE_SHOWN, isFgServiceShown()); + if (isUserVisibleTaskShown()) { + out.attributeBoolean(null, ATT_FG_SERVICE_SHOWN, isUserVisibleTaskShown()); } if (canShowBadge()) { out.attributeBoolean(null, ATT_SHOW_BADGE, canShowBadge()); @@ -1147,7 +1150,7 @@ public final class NotificationChannel implements Parcelable { record.put(ATT_LIGHT_COLOR, Integer.toString(getLightColor())); record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate())); record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields())); - record.put(ATT_FG_SERVICE_SHOWN, Boolean.toString(isFgServiceShown())); + record.put(ATT_FG_SERVICE_SHOWN, Boolean.toString(isUserVisibleTaskShown())); record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern())); record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge())); record.put(ATT_DELETED, Boolean.toString(isDeleted())); @@ -1239,7 +1242,7 @@ public final class NotificationChannel implements Parcelable { && mLights == that.mLights && getLightColor() == that.getLightColor() && getUserLockedFields() == that.getUserLockedFields() - && isFgServiceShown() == that.isFgServiceShown() + && isUserVisibleTaskShown() == that.isUserVisibleTaskShown() && mVibrationEnabled == that.mVibrationEnabled && mShowBadge == that.mShowBadge && isDeleted() == that.isDeleted() @@ -1265,8 +1268,8 @@ public final class NotificationChannel implements Parcelable { public int hashCode() { int result = Objects.hash(getId(), getName(), mDesc, getImportance(), mBypassDnd, getLockscreenVisibility(), getSound(), mLights, getLightColor(), - getUserLockedFields(), - isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getDeletedTimeMs(), + getUserLockedFields(), isUserVisibleTaskShown(), + mVibrationEnabled, mShowBadge, isDeleted(), getDeletedTimeMs(), getGroup(), getAudioAttributes(), isBlockable(), mAllowBubbles, mImportanceLockedDefaultApp, mOriginalImportance, mParentId, mConversationId, mDemoted, mImportantConvo); @@ -1304,7 +1307,7 @@ public final class NotificationChannel implements Parcelable { + ", mLightColor=" + mLightColor + ", mVibration=" + Arrays.toString(mVibration) + ", mUserLockedFields=" + Integer.toHexString(mUserLockedFields) - + ", mFgServiceShown=" + mFgServiceShown + + ", mUserVisibleTaskShown=" + mUserVisibleTaskShown + ", mVibrationEnabled=" + mVibrationEnabled + ", mShowBadge=" + mShowBadge + ", mDeleted=" + mDeleted @@ -1342,7 +1345,7 @@ public final class NotificationChannel implements Parcelable { } } proto.write(NotificationChannelProto.USER_LOCKED_FIELDS, mUserLockedFields); - proto.write(NotificationChannelProto.FG_SERVICE_SHOWN, mFgServiceShown); + proto.write(NotificationChannelProto.USER_VISIBLE_TASK_SHOWN, mUserVisibleTaskShown); proto.write(NotificationChannelProto.IS_VIBRATION_ENABLED, mVibrationEnabled); proto.write(NotificationChannelProto.SHOW_BADGE, mShowBadge); proto.write(NotificationChannelProto.IS_DELETED, mDeleted); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index d2f2c3c4e95a..785470f2f22e 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -31,7 +31,6 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.PermissionChecker; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.graphics.drawable.Icon; @@ -726,8 +725,9 @@ public class NotificationManager { * Cancels a previously posted notification. * * <p>If the notification does not currently represent a - * {@link Service#startForeground(int, Notification) foreground service}, it will be - * removed from the UI and live + * {@link Service#startForeground(int, Notification) foreground service} or a + * {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean) user-initiated job}, + * it will be removed from the UI and live * {@link android.service.notification.NotificationListenerService notification listeners} * will be informed so they can remove the notification from their UIs.</p> */ @@ -740,8 +740,9 @@ public class NotificationManager { * Cancels a previously posted notification. * * <p>If the notification does not currently represent a - * {@link Service#startForeground(int, Notification) foreground service}, it will be - * removed from the UI and live + * {@link Service#startForeground(int, Notification) foreground service} or a + * {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean) user-initiated job}, + * it will be removed from the UI and live * {@link android.service.notification.NotificationListenerService notification listeners} * will be informed so they can remove the notification from their UIs.</p> */ @@ -754,8 +755,9 @@ public class NotificationManager { * Cancels a previously posted notification. * * <p>If the notification does not currently represent a - * {@link Service#startForeground(int, Notification) foreground service}, it will be - * removed from the UI and live + * {@link Service#startForeground(int, Notification) foreground service} or a + * {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean) user-initiated job}, + * it will be removed from the UI and live * {@link android.service.notification.NotificationListenerService notification listeners} * will be informed so they can remove the notification from their UIs.</p> * @@ -874,19 +876,11 @@ public class NotificationManager { * {@link android.provider.Settings#ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT}. */ public boolean canUseFullScreenIntent() { - final int result = PermissionChecker.checkPermissionForPreflight(mContext, - android.Manifest.permission.USE_FULL_SCREEN_INTENT, - mContext.getAttributionSource()); - - switch (result) { - case PermissionChecker.PERMISSION_GRANTED: - return true; - case PermissionChecker.PERMISSION_SOFT_DENIED: - case PermissionChecker.PERMISSION_HARD_DENIED: - return false; - default: - if (localLOGV) Log.v(TAG, "Unknown PermissionChecker result: " + result); - return false; + INotificationManager service = getService(); + try { + return service.canUseFullScreenIntent(mContext.getAttributionSource()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 9bf56b374576..99a7fa21b911 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -841,7 +841,8 @@ public final class PendingIntent implements Parcelable { /** * Perform the operation associated with this PendingIntent. * - * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler) + * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler, String, + * Bundle) * * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. @@ -855,7 +856,8 @@ public final class PendingIntent implements Parcelable { * * @param code Result code to supply back to the PendingIntent's target. * - * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler) + * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler, String, + * Bundle) * * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. @@ -875,7 +877,8 @@ public final class PendingIntent implements Parcelable { * original Intent. If flag {@link #FLAG_IMMUTABLE} was set when this * pending intent was created, this argument will be ignored. * - * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler) + * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler, String, + * Bundle) * * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. @@ -892,6 +895,11 @@ public final class PendingIntent implements Parcelable { * @param options Additional options the caller would like to provide to modify the * sending behavior. May be built from an {@link ActivityOptions} to apply to an * activity start. + * + * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler, String) + * + * @throws CanceledException Throws CanceledException if the PendingIntent + * is no longer allowing more intents to be sent through it. */ public void send(@Nullable Bundle options) throws CanceledException { send(null, 0, null, null, null, null, options); @@ -908,7 +916,8 @@ public final class PendingIntent implements Parcelable { * should happen. If null, the callback will happen from the thread * pool of the process. * - * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler) + * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler, String, + * Bundle) * * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. @@ -942,11 +951,8 @@ public final class PendingIntent implements Parcelable { * should happen. If null, the callback will happen from the thread * pool of the process. * - * @see #send() - * @see #send(int) - * @see #send(Context, int, Intent) - * @see #send(int, android.app.PendingIntent.OnFinished, Handler) - * @see #send(Context, int, Intent, OnFinished, Handler, String) + * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler, String, + * Bundle) * * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. @@ -985,11 +991,8 @@ public final class PendingIntent implements Parcelable { * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}. * If null, no permission is required. * - * @see #send() - * @see #send(int) - * @see #send(Context, int, Intent) - * @see #send(int, android.app.PendingIntent.OnFinished, Handler) - * @see #send(Context, int, Intent, OnFinished, Handler) + * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler, String, + * Bundle) * * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. @@ -1032,12 +1035,6 @@ public final class PendingIntent implements Parcelable { * @param options Additional options the caller would like to provide to modify the sending * behavior. May be built from an {@link ActivityOptions} to apply to an activity start. * - * @see #send() - * @see #send(int) - * @see #send(Context, int, Intent) - * @see #send(int, android.app.PendingIntent.OnFinished, Handler) - * @see #send(Context, int, Intent, OnFinished, Handler) - * * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java index 620adbedc903..c5ad1105397e 100644 --- a/core/java/android/app/RemoteServiceException.java +++ b/core/java/android/app/RemoteServiceException.java @@ -102,6 +102,21 @@ public class RemoteServiceException extends AndroidRuntimeException { } /** + * Exception used to crash an app process when the system finds an error in a user-initiated job + * notification. + * + * @hide + */ + public static class BadUserInitiatedJobNotificationException extends RemoteServiceException { + /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ + public static final int TYPE_ID = 6; + + public BadUserInitiatedJobNotificationException(String msg) { + super(msg); + } + } + + /** * Exception used to crash an app process when it calls a setting activity that requires * the {@code REQUEST_PASSWORD_COMPLEXITY} permission. * diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index dbba0c6f5e50..4f5da99d539a 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -506,10 +506,10 @@ public final class SystemServiceRegistry { // InputManager stores its own static instance for historical purposes. registerService(Context.INPUT_SERVICE, InputManager.class, - new ServiceFetcher<InputManager>() { + new CachedServiceFetcher<InputManager>() { @Override - public InputManager getService(ContextImpl ctx) { - return InputManager.getInstance(ctx.getOuterContext()); + public InputManager createService(ContextImpl ctx) { + return new InputManager(ctx.getOuterContext()); }}); registerService(Context.DISPLAY_SERVICE, DisplayManager.class, diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING index 1df860258d82..bc5f7f411af5 100644 --- a/core/java/android/app/TEST_MAPPING +++ b/core/java/android/app/TEST_MAPPING @@ -110,6 +110,9 @@ "options": [ { "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-filter": "android.voiceinteraction.cts.HotwordDetectionServiceStressTest" } ], "file_patterns": ["(/|^)VoiceInteract[^/]*"] diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 86f6a93ede1e..247d5bc77ffb 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -16,6 +16,8 @@ package android.app; +import static android.view.Display.DEFAULT_DISPLAY; + import android.accessibilityservice.AccessibilityGestureEvent; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityService.Callbacks; @@ -30,6 +32,7 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; @@ -45,7 +48,9 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.os.UserManager; import android.util.ArraySet; +import android.util.DebugUtils; import android.util.Log; import android.util.SparseArray; import android.view.Display; @@ -68,8 +73,10 @@ import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.inputmethod.EditorInfo; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback; import com.android.internal.inputmethod.RemoteAccessibilityInputConnection; +import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledLambda; import libcore.io.IoUtils; @@ -111,6 +118,7 @@ public final class UiAutomation { private static final String LOG_TAG = UiAutomation.class.getSimpleName(); private static final boolean DEBUG = false; + private static final boolean VERBOSE = false; private static final int CONNECTION_ID_UNDEFINED = -1; @@ -200,6 +208,8 @@ public final class UiAutomation { private final IUiAutomationConnection mUiAutomationConnection; + private final int mDisplayId; + private HandlerThread mRemoteCallbackThread; private IAccessibilityServiceClient mClient; @@ -259,24 +269,49 @@ public final class UiAutomation { /** * Creates a new instance that will handle callbacks from the accessibility + * layer on the thread of the provided context main looper and perform requests for privileged + * operations on the provided connection, and filtering display-related features to the display + * associated with the context (or the user running the test, on devices that + * {@link UserManager#isVisibleBackgroundUsersSupported() support visible background users}). + * + * @param context the context associated with the automation + * @param connection The connection for performing privileged operations. + * + * @hide + */ + public UiAutomation(Context context, IUiAutomationConnection connection) { + this(getDisplayId(context), context.getMainLooper(), connection); + } + + /** + * Creates a new instance that will handle callbacks from the accessibility * layer on the thread of the provided looper and perform requests for privileged * operations on the provided connection. * * @param looper The looper on which to execute accessibility callbacks. * @param connection The connection for performing privileged operations. * + * @deprecated use {@link #UiAutomation(Context, IUiAutomationConnection)} instead + * * @hide */ + @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public UiAutomation(Looper looper, IUiAutomationConnection connection) { - if (looper == null) { - throw new IllegalArgumentException("Looper cannot be null!"); - } - if (connection == null) { - throw new IllegalArgumentException("Connection cannot be null!"); - } + this(DEFAULT_DISPLAY, looper, connection); + Log.w(LOG_TAG, "Created with deprecatead constructor, assumes DEFAULT_DISPLAY"); + } + + private UiAutomation(int displayId, Looper looper, IUiAutomationConnection connection) { + Preconditions.checkArgument(looper != null, "Looper cannot be null!"); + Preconditions.checkArgument(connection != null, "Connection cannot be null!"); + mLocalCallbackHandler = new Handler(looper); mUiAutomationConnection = connection; + mDisplayId = displayId; + + Log.i(LOG_TAG, "Initialized for user " + Process.myUserHandle().getIdentifier() + + " on display " + mDisplayId); } /** @@ -321,11 +356,18 @@ public final class UiAutomation { * @hide */ public void connectWithTimeout(int flags, long timeoutMillis) throws TimeoutException { + if (DEBUG) { + Log.d(LOG_TAG, "connectWithTimeout: user=" + Process.myUserHandle().getIdentifier() + + ", flags=" + DebugUtils.flagsToString(UiAutomation.class, "FLAG_", flags) + + ", timeout=" + timeoutMillis + "ms"); + } synchronized (mLock) { throwIfConnectedLocked(); if (mConnectionState == ConnectionState.CONNECTING) { + if (DEBUG) Log.d(LOG_TAG, "already connecting"); return; } + if (DEBUG) Log.d(LOG_TAG, "setting state to CONNECTING"); mConnectionState = ConnectionState.CONNECTING; mRemoteCallbackThread = new HandlerThread("UiAutomation"); mRemoteCallbackThread.start(); @@ -341,6 +383,7 @@ public final class UiAutomation { // If UiAutomation is not allowed to use the accessibility subsystem, the // connection state should keep disconnected and not to start the client connection. if (!useAccessibility()) { + if (DEBUG) Log.d(LOG_TAG, "setting state to DISCONNECTED"); mConnectionState = ConnectionState.DISCONNECTED; return; } @@ -357,6 +400,7 @@ public final class UiAutomation { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis; if (remainingTimeMillis <= 0) { + if (DEBUG) Log.d(LOG_TAG, "setting state to FAILED"); mConnectionState = ConnectionState.FAILED; throw new TimeoutException("Timeout while connecting " + this); } @@ -708,8 +752,14 @@ public final class UiAutomation { } /** - * Gets the windows on the screen of the default display. This method returns only the windows - * that a sighted user can interact with, as opposed to all windows. + * Gets the windows on the screen associated with the {@link UiAutomation} context (usually the + * {@link android.view.Display#DEFAULT_DISPLAY default display). + * + * <p> + * This method returns only the windows that a sighted user can interact with, as opposed to + * all windows. + + * <p> * For example, if there is a modal dialog shown and the user cannot touch * anything behind it, then only the modal window will be reported * (assuming it is the top one). For convenience the returned windows @@ -719,21 +769,23 @@ public final class UiAutomation { * <strong>Note:</strong> In order to access the windows you have to opt-in * to retrieve the interactive windows by setting the * {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag. - * </p> * * @return The windows if there are windows such, otherwise an empty list. * @throws IllegalStateException If the connection to the accessibility subsystem is not * established. */ public List<AccessibilityWindowInfo> getWindows() { + if (DEBUG) { + Log.d(LOG_TAG, "getWindows(): returning windows for display " + mDisplayId); + } final int connectionId; synchronized (mLock) { throwIfNotConnectedLocked(); connectionId = mConnectionId; } // Calling out without a lock held. - return AccessibilityInteractionClient.getInstance() - .getWindows(connectionId); + return AccessibilityInteractionClient.getInstance().getWindowsOnDisplay(connectionId, + mDisplayId); } /** @@ -1101,8 +1153,10 @@ public final class UiAutomation { * @return The screenshot bitmap on success, null otherwise. */ public Bitmap takeScreenshot() { - Display display = DisplayManagerGlobal.getInstance() - .getRealDisplay(Display.DEFAULT_DISPLAY); + if (DEBUG) { + Log.d(LOG_TAG, "Taking screenshot of display " + mDisplayId); + } + Display display = DisplayManagerGlobal.getInstance().getRealDisplay(mDisplayId); Point displaySize = new Point(); display.getRealSize(displaySize); @@ -1115,10 +1169,12 @@ public final class UiAutomation { screenShot = mUiAutomationConnection.takeScreenshot( new Rect(0, 0, displaySize.x, displaySize.y)); if (screenShot == null) { + Log.e(LOG_TAG, "mUiAutomationConnection.takeScreenshot() returned null for display " + + mDisplayId); return null; } } catch (RemoteException re) { - Log.e(LOG_TAG, "Error while taking screenshot!", re); + Log.e(LOG_TAG, "Error while taking screenshot of display " + mDisplayId, re); return null; } @@ -1367,7 +1423,8 @@ public final class UiAutomation { UserHandle userHandle) { try { if (DEBUG) { - Log.i(LOG_TAG, "Granting runtime permission"); + Log.i(LOG_TAG, "Granting runtime permission (" + permission + ") to package " + + packageName + " on user " + userHandle); } // Calling out without a lock held. mUiAutomationConnection.grantRuntimePermission(packageName, @@ -1497,6 +1554,14 @@ public final class UiAutomation { return executeShellCommandInternal(command, true /* includeStderr */); } + /** + * @hide + */ + @VisibleForTesting + public int getDisplayId() { + return mDisplayId; + } + private ParcelFileDescriptor[] executeShellCommandInternal( String command, boolean includeStderr) { warnIfBetterCommand(command); @@ -1552,6 +1617,7 @@ public final class UiAutomation { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("UiAutomation@").append(Integer.toHexString(hashCode())); stringBuilder.append("[id=").append(mConnectionId); + stringBuilder.append(", displayId=").append(mDisplayId); stringBuilder.append(", flags=").append(mFlags); stringBuilder.append("]"); return stringBuilder.toString(); @@ -1589,10 +1655,59 @@ public final class UiAutomation { return (mFlags & UiAutomation.FLAG_DONT_USE_ACCESSIBILITY) == 0; } + /** + * Gets the display id associated with the UiAutomation context. + * + * <p><b>NOTE: </b> must be a static method because it's called from a constructor to call + * another one. + */ + private static int getDisplayId(Context context) { + Preconditions.checkArgument(context != null, "Context cannot be null!"); + + UserManager userManager = context.getSystemService(UserManager.class); + // TODO(b/255426725): given that this is a temporary solution until a11y supports multiple + // users, the display is only set on devices that support that + if (!userManager.isVisibleBackgroundUsersSupported()) { + return DEFAULT_DISPLAY; + } + + int displayId = context.getDisplayId(); + if (displayId == Display.INVALID_DISPLAY) { + // Shouldn't happen, but we better handle it + Log.e(LOG_TAG, "UiAutomation created UI context with invalid display id, assuming it's" + + " running in the display assigned to the user"); + return getMainDisplayIdAssignedToUser(context, userManager); + } + + if (displayId != DEFAULT_DISPLAY) { + if (DEBUG) { + Log.d(LOG_TAG, "getDisplayId(): returning context's display (" + displayId + ")"); + } + // Context is explicitly setting the display, so we respect that... + return displayId; + } + // ...otherwise, we need to get the display the test's user is running on + int userDisplayId = getMainDisplayIdAssignedToUser(context, userManager); + if (DEBUG) { + Log.d(LOG_TAG, "getDisplayId(): returning user's display (" + userDisplayId + ")"); + } + return userDisplayId; + } + + private static int getMainDisplayIdAssignedToUser(Context context, UserManager userManager) { + if (!userManager.isUserVisible()) { + // Should also not happen, but ... + Log.e(LOG_TAG, "User (" + context.getUserId() + ") is not visible, using " + + "DEFAULT_DISPLAY"); + return DEFAULT_DISPLAY; + } + return userManager.getMainDisplayIdAssignedToUser(); + } + private class IAccessibilityServiceClientImpl extends IAccessibilityServiceClientWrapper { public IAccessibilityServiceClientImpl(Looper looper, int generationId) { - super(null, looper, new Callbacks() { + super(/* context= */ null, looper, new Callbacks() { private final int mGenerationId = generationId; /** @@ -1606,10 +1721,22 @@ public final class UiAutomation { @Override public void init(int connectionId, IBinder windowToken) { + if (DEBUG) { + Log.d(LOG_TAG, "init(): connectionId=" + connectionId + ", windowToken=" + + windowToken + ", user=" + Process.myUserHandle() + + ", UiAutomation.mDisplay=" + UiAutomation.this.mDisplayId + + ", mGenerationId=" + mGenerationId + + ", UiAutomation.mGenerationId=" + + UiAutomation.this.mGenerationId); + } synchronized (mLock) { if (isGenerationChangedLocked()) { + if (DEBUG) { + Log.d(LOG_TAG, "init(): returning because generation id changed"); + } return; } + if (DEBUG) Log.d(LOG_TAG, "setting state to CONNECTED"); mConnectionState = ConnectionState.CONNECTED; mConnectionId = connectionId; mLock.notifyAll(); @@ -1662,9 +1789,20 @@ public final class UiAutomation { @Override public void onAccessibilityEvent(AccessibilityEvent event) { + if (VERBOSE) { + Log.v(LOG_TAG, "onAccessibilityEvent(" + Process.myUserHandle() + "): " + + event); + } + final OnAccessibilityEventListener listener; synchronized (mLock) { if (isGenerationChangedLocked()) { + if (VERBOSE) { + Log.v(LOG_TAG, "onAccessibilityEvent(): returning because " + + "generation id changed (from " + + UiAutomation.this.mGenerationId + " to " + + mGenerationId + ")"); + } return; } // It is not guaranteed that the accessibility framework sends events by the diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index 3a32f2362c0d..d96a9d104ec2 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -22,6 +22,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceClient; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Bitmap; @@ -103,6 +104,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public UiAutomationConnection() { + Log.d(TAG, "Created on user " + Process.myUserHandle()); } @Override @@ -116,7 +118,8 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { throw new IllegalStateException("Already connected."); } mOwningUid = Binder.getCallingUid(); - registerUiTestAutomationServiceLocked(client, flags); + registerUiTestAutomationServiceLocked(client, + Binder.getCallingUserHandle().getIdentifier(), flags); storeRotationStateLocked(); } } @@ -552,7 +555,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } private void registerUiTestAutomationServiceLocked(IAccessibilityServiceClient client, - int flags) { + @UserIdInt int userId, int flags) { IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); final AccessibilityServiceInfo info = new AccessibilityServiceInfo(); @@ -570,10 +573,11 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { try { // Calling out with a lock held is fine since if the system // process is gone the client calling in will be killed. - manager.registerUiTestAutomationService(mToken, client, info, flags); + manager.registerUiTestAutomationService(mToken, client, info, userId, flags); mClient = client; } catch (RemoteException re) { - throw new IllegalStateException("Error while registering UiTestAutomationService.", re); + throw new IllegalStateException("Error while registering UiTestAutomationService for " + + "user " + userId + ".", re); } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 7dabe60e3ba8..4d3338beded5 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -9634,7 +9634,8 @@ public class DevicePolicyManager { * @see #isProfileOwnerApp * @see #isDeviceOwnerApp * @param admin Which {@link DeviceAdminReceiver} this request is associate with. - * @param profileName The name of the profile. + * @param profileName The name of the profile. If the name is longer than 200 characters + * it will be truncated. * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setProfileName(@NonNull ComponentName admin, String profileName) { diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java index 593f73635617..052f670b71bd 100644 --- a/core/java/android/app/admin/DevicePolicyResources.java +++ b/core/java/android/app/admin/DevicePolicyResources.java @@ -1802,14 +1802,6 @@ public final class DevicePolicyResources { PREFIX + "UNLAUNCHABLE_APP_WORK_PAUSED_TITLE"; /** - * Text for dialog shown when user tries to open a work app when the work profile is - * turned off, confirming that the user wants to turn on access to their - * work apps. - */ - public static final String UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE = - PREFIX + "UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE"; - - /** * Notification title shown when work profile is credential encrypted and requires * the user to unlock before it's usable. */ diff --git a/core/java/android/app/admin/IntentFilterPolicyKey.java b/core/java/android/app/admin/IntentFilterPolicyKey.java index 30aad965c008..7526a7b2c934 100644 --- a/core/java/android/app/admin/IntentFilterPolicyKey.java +++ b/core/java/android/app/admin/IntentFilterPolicyKey.java @@ -28,7 +28,9 @@ import android.content.IntentFilter; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; +import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -45,6 +47,10 @@ import java.util.Objects; */ @SystemApi public final class IntentFilterPolicyKey extends PolicyKey { + + private static final String TAG = "IntentFilterPolicyKey"; + + private static final String TAG_INTENT_FILTER_ENTRY = "filter"; private final IntentFilter mFilter; /** @@ -83,7 +89,9 @@ public final class IntentFilterPolicyKey extends PolicyKey { @Override public void saveToXml(TypedXmlSerializer serializer) throws IOException { serializer.attribute(/* namespace= */ null, ATTR_POLICY_IDENTIFIER, getIdentifier()); + serializer.startTag(/* namespace= */ null, TAG_INTENT_FILTER_ENTRY); mFilter.writeToXml(serializer); + serializer.endTag(/* namespace= */ null, TAG_INTENT_FILTER_ENTRY); } /** @@ -93,11 +101,27 @@ public final class IntentFilterPolicyKey extends PolicyKey { public IntentFilterPolicyKey readFromXml(TypedXmlPullParser parser) throws XmlPullParserException, IOException { String identifier = parser.getAttributeValue(/* namespace= */ null, ATTR_POLICY_IDENTIFIER); - IntentFilter filter = new IntentFilter(); - filter.readFromXml(parser); + IntentFilter filter = readIntentFilterFromXml(parser); return new IntentFilterPolicyKey(identifier, filter); } + @Nullable + private IntentFilter readIntentFilterFromXml(TypedXmlPullParser parser) + throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, outerDepth)) { + String tag = parser.getName(); + if (tag.equals(TAG_INTENT_FILTER_ENTRY)) { + IntentFilter filter = new IntentFilter(); + filter.readFromXml(parser); + return filter; + } + Log.e(TAG, "Unknown tag: " + tag); + } + Log.e(TAG, "Error parsing IntentFilterPolicyKey, IntentFilter not found"); + return null; + } + /** * @hide */ diff --git a/core/java/android/app/search/SearchTarget.java b/core/java/android/app/search/SearchTarget.java index a3874f7cb007..8132b813cba0 100644 --- a/core/java/android/app/search/SearchTarget.java +++ b/core/java/android/app/search/SearchTarget.java @@ -186,16 +186,6 @@ public final class SearchTarget implements Parcelable { mAppWidgetProviderInfo = appWidgetProviderInfo; mSliceUri = sliceUri; mExtras = extras != null ? extras : new Bundle(); - - int published = 0; - if (mSearchAction != null) published++; - if (mShortcutInfo != null) published++; - if (mAppWidgetProviderInfo != null) published++; - if (mSliceUri != null) published++; - if (published > 1) { - throw new IllegalStateException("Only one of SearchAction, ShortcutInfo," - + " AppWidgetProviderInfo, SliceUri can be assigned in a SearchTarget."); - } } /** diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index 96a42e24bc1a..563ed7dd6e7a 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -38,6 +38,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.UserHandle; import android.os.ParcelFileDescriptor; +import android.window.IDumpCallback; import com.android.internal.infra.AndroidFuture; @@ -116,4 +117,10 @@ interface ILauncherApps { String getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId); Map<String, LauncherActivityInfoInternal> getActivityOverrides(String callingPackage, int userId); + + /** Register a callback to be called right before the wmtrace data is moved to the bugreport. */ + void registerDumpCallback(IDumpCallback cb); + + /** Unregister a callback, so that it won't be called when LauncherApps dumps. */ + void unRegisterDumpCallback(IDumpCallback cb); } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 8989006a7e83..27270d9f378f 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -17,6 +17,7 @@ package android.content.pm; import static android.Manifest.permission; +import static android.Manifest.permission.READ_FRAME_BUFFER; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -68,6 +69,7 @@ import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; +import android.window.IDumpCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AndroidFuture; @@ -1172,6 +1174,32 @@ public class LauncherApps { } /** + * Register a callback to be called right before the wmtrace data is moved to the bugreport. + * @hide + */ + @RequiresPermission(READ_FRAME_BUFFER) + public void registerDumpCallback(IDumpCallback cb) { + try { + mService.registerDumpCallback(cb); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Unregister a callback, so that it won't be called when LauncherApps dumps. + * @hide + */ + @RequiresPermission(READ_FRAME_BUFFER) + public void unRegisterDumpCallback(IDumpCallback cb) { + try { + mService.unRegisterDumpCallback(cb); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** * Returns {@link ShortcutInfo}s that match {@code query}. * * <p>Callers must be allowed to access the shortcut information, as defined in {@link diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 81fc0293b685..23ba33698739 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -261,14 +261,17 @@ public class UserInfo implements Parcelable { public boolean guestToRemove; /** - * This is used to optimize the creation of an user, i.e. OEMs might choose to pre-create a + * This is used to optimize the creation of a user, i.e. OEMs might choose to pre-create a * number of users at the first boot, so the actual creation later is faster. * * <p>A {@code preCreated} user is not a real user yet, so it should not show up on regular * user operations (other than user creation per se). * - * <p>Once the pre-created is used to create a "real" user later on, {@code preCreate} is set to - * {@code false}. + * <p>Once the pre-created is used to create a "real" user later on, {@code preCreated} is set + * to {@code false}. + * + * <p><b>NOTE: Pre-created users are deprecated. This field remains to be able to recognize + * pre-created users in older versions, but will eventually be removed. */ public boolean preCreated; @@ -277,6 +280,9 @@ public class UserInfo implements Parcelable { * user. * * <p><b>NOTE: </b>only used for debugging purposes, it's not set when marshalled to a parcel. + * + * <p><b>NOTE: Pre-created users are deprecated. This field remains to be able to recognize + * pre-created users in older versions, but will eventually ve removed. */ public boolean convertedFromPreCreated; diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java index 269bec256282..408f7ed9f766 100644 --- a/core/java/android/content/pm/parsing/ApkLite.java +++ b/core/java/android/content/pm/parsing/ApkLite.java @@ -138,6 +138,11 @@ public class ApkLite { */ private final boolean mIsSdkLibrary; + /** + * Indicates if this package allows an installer to declare update ownership of it. + */ + private final boolean mAllowUpdateOwnership; + public ApkLite(String path, String packageName, String splitName, boolean isFeatureSplit, String configForSplit, String usesSplitName, boolean isSplitRequired, int versionCode, int versionCodeMajor, int revisionCode, int installLocation, @@ -148,7 +153,7 @@ public class ApkLite { String requiredSystemPropertyName, String requiredSystemPropertyValue, int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy, Set<String> requiredSplitTypes, Set<String> splitTypes, - boolean hasDeviceAdminReceiver, boolean isSdkLibrary) { + boolean hasDeviceAdminReceiver, boolean isSdkLibrary, boolean allowUpdateOwnership) { mPath = path; mPackageName = packageName; mSplitName = splitName; @@ -182,6 +187,7 @@ public class ApkLite { mRollbackDataPolicy = rollbackDataPolicy; mHasDeviceAdminReceiver = hasDeviceAdminReceiver; mIsSdkLibrary = isSdkLibrary; + mAllowUpdateOwnership = allowUpdateOwnership; } /** @@ -474,6 +480,9 @@ public class ApkLite { return mRollbackDataPolicy; } + /** + * Indicates if this app contains a {@link android.app.admin.DeviceAdminReceiver}. + */ @DataClass.Generated.Member public boolean isHasDeviceAdminReceiver() { return mHasDeviceAdminReceiver; @@ -487,11 +496,19 @@ public class ApkLite { return mIsSdkLibrary; } + /** + * Indicates if this package allows an installer to declare update ownership of it. + */ + @DataClass.Generated.Member + public boolean isAllowUpdateOwnership() { + return mAllowUpdateOwnership; + } + @DataClass.Generated( - time = 1643063342990L, + time = 1680122754650L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java", - inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") + inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final boolean mAllowUpdateOwnership\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 64fed63c7159..a4339d41dfd2 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -127,7 +127,8 @@ public class ApkLiteParseUtils { null /* isFeatureSplits */, null /* usesSplitNames */, null /* configForSplit */, null /* splitApkPaths */, null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(), - null /* requiredSplitTypes */, null /* splitTypes */)); + null /* requiredSplitTypes */, null, /* splitTypes */ + baseApk.isAllowUpdateOwnership())); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -273,7 +274,8 @@ public class ApkLiteParseUtils { return input.success( new PackageLite(codePath, baseCodePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes, - baseApk.getTargetSdkVersion(), requiredSplitTypes, splitTypes)); + baseApk.getTargetSdkVersion(), requiredSplitTypes, splitTypes, + baseApk.isAllowUpdateOwnership())); } /** @@ -400,6 +402,8 @@ public class ApkLiteParseUtils { "isFeatureSplit", false); boolean isSplitRequired = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "isSplitRequired", false); + boolean allowUpdateOwnership = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, + "allowUpdateOwnership", true); String configForSplit = parser.getAttributeValue(null, "configForSplit"); int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION; @@ -583,7 +587,7 @@ public class ApkLiteParseUtils { overlayIsStatic, overlayPriority, requiredSystemPropertyName, requiredSystemPropertyValue, minSdkVersion, targetSdkVersion, rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second, - hasDeviceAdminReceiver, isSdkLibrary)); + hasDeviceAdminReceiver, isSdkLibrary, allowUpdateOwnership)); } private static boolean isDeviceAdminReceiver( diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java index e2789c93516f..e24b9320110e 100644 --- a/core/java/android/content/pm/parsing/PackageLite.java +++ b/core/java/android/content/pm/parsing/PackageLite.java @@ -110,10 +110,16 @@ public class PackageLite { */ private final boolean mIsSdkLibrary; + /** + * Indicates if this package allows an installer to declare update ownership of it. + */ + private final boolean mAllowUpdateOwnership; + public PackageLite(String path, String baseApkPath, ApkLite baseApk, String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, String[] splitApkPaths, int[] splitRevisionCodes, - int targetSdk, Set<String>[] requiredSplitTypes, Set<String>[] splitTypes) { + int targetSdk, Set<String>[] requiredSplitTypes, Set<String>[] splitTypes, + boolean allowUpdateOwnership) { // The following paths may be different from the path in ApkLite because we // move or rename the APK files. Use parameters to indicate the correct paths. mPath = path; @@ -144,6 +150,7 @@ public class PackageLite { mSplitApkPaths = splitApkPaths; mSplitRevisionCodes = splitRevisionCodes; mTargetSdk = targetSdk; + mAllowUpdateOwnership = allowUpdateOwnership; } /** @@ -414,12 +421,19 @@ public class PackageLite { return mIsSdkLibrary; } + /** + * Indicates if this package allows an installer to declare update ownership of it. + */ + @DataClass.Generated.Member + public boolean isAllowUpdateOwnership() { + return mAllowUpdateOwnership; + } + @DataClass.Generated( - time = 1643132127068L, + time = 1680125514341L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java", - inputSignatures = - "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") + inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\nprivate final boolean mAllowUpdateOwnership\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java index d2a6f03cc1a1..ac65933db136 100644 --- a/core/java/android/content/res/AssetFileDescriptor.java +++ b/core/java/android/content/res/AssetFileDescriptor.java @@ -21,20 +21,12 @@ import android.os.Bundle; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; -import android.system.ErrnoException; -import android.system.Os; import java.io.Closeable; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; /** * File descriptor of an entry in the AssetManager. This provides your own @@ -211,26 +203,19 @@ public class AssetFileDescriptor implements Parcelable, Closeable { */ public static class AutoCloseInputStream extends ParcelFileDescriptor.AutoCloseInputStream { - /** Size of current file. */ - private long mTotalSize; - /** The absolute position of current file start point. */ - private final long mFileOffset; - /** The relative position where input stream is against mFileOffset. */ - private long mOffset; - private OffsetCorrectFileChannel mOffsetCorrectFileChannel; + private long mRemaining; public AutoCloseInputStream(AssetFileDescriptor fd) throws IOException { super(fd.getParcelFileDescriptor()); - mTotalSize = fd.getLength(); - mFileOffset = fd.getStartOffset(); + super.skip(fd.getStartOffset()); + mRemaining = (int) fd.getLength(); } @Override public int available() throws IOException { - long available = mTotalSize - mOffset; - return available >= 0 - ? (available < 0x7fffffff ? (int) available : 0x7fffffff) - : 0; + return mRemaining >= 0 + ? (mRemaining < 0x7fffffff ? (int) mRemaining : 0x7fffffff) + : super.available(); } @Override @@ -242,24 +227,15 @@ public class AssetFileDescriptor implements Parcelable, Closeable { @Override public int read(byte[] buffer, int offset, int count) throws IOException { - int available = available(); - if (available <= 0) { - return -1; - } - - if (count > available) count = available; - try { - int res = Os.pread(getFD(), buffer, offset, count, mFileOffset + mOffset); - // pread returns 0 at end of file, while java's InputStream interface requires -1 - if (res == 0) res = -1; - if (res > 0) { - mOffset += res; - updateChannelPosition(mOffset + mFileOffset); - } + if (mRemaining >= 0) { + if (mRemaining == 0) return -1; + if (count > mRemaining) count = (int) mRemaining; + int res = super.read(buffer, offset, count); + if (res >= 0) mRemaining -= res; return res; - } catch (ErrnoException e) { - throw new IOException(e); } + + return super.read(buffer, offset, count); } @Override @@ -269,185 +245,41 @@ public class AssetFileDescriptor implements Parcelable, Closeable { @Override public long skip(long count) throws IOException { - int available = available(); - if (available <= 0) { - return -1; + if (mRemaining >= 0) { + if (mRemaining == 0) return -1; + if (count > mRemaining) count = mRemaining; + long res = super.skip(count); + if (res >= 0) mRemaining -= res; + return res; } - if (count > available) count = available; - mOffset += count; - updateChannelPosition(mOffset + mFileOffset); - return count; + return super.skip(count); } @Override public void mark(int readlimit) { - // Not supported. - return; + if (mRemaining >= 0) { + // Not supported. + return; + } + super.mark(readlimit); } @Override public boolean markSupported() { - return false; + if (mRemaining >= 0) { + return false; + } + return super.markSupported(); } @Override public synchronized void reset() throws IOException { - // Not supported. - return; - } - - @Override - public FileChannel getChannel() { - if (mOffsetCorrectFileChannel == null) { - mOffsetCorrectFileChannel = new OffsetCorrectFileChannel(super.getChannel()); - } - try { - updateChannelPosition(mOffset + mFileOffset); - } catch (IOException e) { - throw new RuntimeException(e); - } - return mOffsetCorrectFileChannel; - } - - /** - * Update the position of mOffsetCorrectFileChannel only after it is constructed. - * - * @param newPosition The absolute position mOffsetCorrectFileChannel needs to be moved to. - */ - private void updateChannelPosition(long newPosition) throws IOException { - if (mOffsetCorrectFileChannel != null) { - mOffsetCorrectFileChannel.position(newPosition); - } - } - - /** - * A FileChannel wrapper that will update mOffset of the AutoCloseInputStream - * to correct position when using FileChannel to read. All occurrence of position - * should be using absolute solution and each override method just do Delegation - * besides additional check. All methods related to write mode have been disabled - * and will throw UnsupportedOperationException with customized message. - */ - private class OffsetCorrectFileChannel extends FileChannel { - private final FileChannel mDelegate; - private static final String METHOD_NOT_SUPPORTED_MESSAGE = - "This Method is not supported in AutoCloseInputStream FileChannel."; - - OffsetCorrectFileChannel(FileChannel fc) { - mDelegate = fc; - } - - @Override - public int read(ByteBuffer dst) throws IOException { - if (available() <= 0) return -1; - int bytesRead = mDelegate.read(dst); - if (bytesRead != -1) mOffset += bytesRead; - return bytesRead; - } - - @Override - public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { - if (available() <= 0) return -1; - if (mOffset + length > mTotalSize) { - length = (int) (mTotalSize - mOffset); - } - long bytesRead = mDelegate.read(dsts, offset, length); - if (bytesRead != -1) mOffset += bytesRead; - return bytesRead; - } - - @Override - /**The only read method that does not move channel position*/ - public int read(ByteBuffer dst, long position) throws IOException { - if (position - mFileOffset > mTotalSize) return -1; - return mDelegate.read(dst, position); - } - - @Override - public long position() throws IOException { - return mDelegate.position(); - } - - @Override - public FileChannel position(long newPosition) throws IOException { - mOffset = newPosition - mFileOffset; - return mDelegate.position(newPosition); - } - - @Override - public long size() throws IOException { - return mTotalSize; - } - - @Override - public long transferTo(long position, long count, WritableByteChannel target) - throws IOException { - if (position - mFileOffset > mTotalSize) { - return 0; - } - if (position - mFileOffset + count > mTotalSize) { - count = mTotalSize - (position - mFileOffset); - } - return mDelegate.transferTo(position, count, target); - } - - @Override - public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException { - if (position - mFileOffset > mTotalSize) { - throw new IOException( - "Cannot map to buffer because position exceed current file size."); - } - if (position - mFileOffset + size > mTotalSize) { - size = mTotalSize - (position - mFileOffset); - } - return mDelegate.map(mode, position, size); - } - - @Override - protected void implCloseChannel() throws IOException { - mDelegate.close(); - } - - @Override - public int write(ByteBuffer src) throws IOException { - throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE); - } - - @Override - public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { - throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE); - } - - @Override - public int write(ByteBuffer src, long position) throws IOException { - throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE); - } - - @Override - public long transferFrom(ReadableByteChannel src, long position, long count) - throws IOException { - throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE); - } - - @Override - public FileChannel truncate(long size) throws IOException { - throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE); - } - - @Override - public void force(boolean metaData) throws IOException { - throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE); - } - - @Override - public FileLock lock(long position, long size, boolean shared) throws IOException { - throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE); - } - - @Override - public FileLock tryLock(long position, long size, boolean shared) throws IOException { - throw new UnsupportedOperationException(METHOD_NOT_SUPPORTED_MESSAGE); + if (mRemaining >= 0) { + // Not supported. + return; } + super.reset(); } } diff --git a/core/java/android/credentials/CredentialOption.java b/core/java/android/credentials/CredentialOption.java index e933123d08b8..df948f17d6e0 100644 --- a/core/java/android/credentials/CredentialOption.java +++ b/core/java/android/credentials/CredentialOption.java @@ -37,8 +37,7 @@ import java.util.Set; /** * Information about a specific type of credential to be requested during a {@link - * CredentialManager#getCredential(GetCredentialRequest, Activity, CancellationSignal, Executor, - * OutcomeReceiver)} operation. + * CredentialManager#getCredential} operation. */ public final class CredentialOption implements Parcelable { @@ -196,9 +195,8 @@ public final class CredentialOption implements Parcelable { * @throws NullPointerException If {@code credentialRetrievalData}, or * {@code candidateQueryData} is null. * - * @deprecated replaced by Builder + * @hide */ - @Deprecated public CredentialOption( @NonNull String type, @NonNull Bundle credentialRetrievalData, diff --git a/core/java/android/credentials/ui/CreateCredentialProviderData.java b/core/java/android/credentials/ui/CreateCredentialProviderData.java index 852934a808e2..629d578c7358 100644 --- a/core/java/android/credentials/ui/CreateCredentialProviderData.java +++ b/core/java/android/credentials/ui/CreateCredentialProviderData.java @@ -19,6 +19,7 @@ package android.credentials.ui; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; +import android.content.pm.ParceledListSlice; import android.os.Parcel; import android.os.Parcelable; @@ -35,7 +36,7 @@ import java.util.List; @TestApi public final class CreateCredentialProviderData extends ProviderData implements Parcelable { @NonNull - private final List<Entry> mSaveEntries; + private final ParceledListSlice<Entry> mSaveEntries; @Nullable private final Entry mRemoteEntry; @@ -43,13 +44,13 @@ public final class CreateCredentialProviderData extends ProviderData implements @NonNull String providerFlattenedComponentName, @NonNull List<Entry> saveEntries, @Nullable Entry remoteEntry) { super(providerFlattenedComponentName); - mSaveEntries = saveEntries; + mSaveEntries = new ParceledListSlice<>(saveEntries); mRemoteEntry = remoteEntry; } @NonNull public List<Entry> getSaveEntries() { - return mSaveEntries; + return mSaveEntries.getList(); } @Nullable @@ -60,9 +61,7 @@ public final class CreateCredentialProviderData extends ProviderData implements private CreateCredentialProviderData(@NonNull Parcel in) { super(in); - List<Entry> credentialEntries = new ArrayList<>(); - in.readTypedList(credentialEntries, Entry.CREATOR); - mSaveEntries = credentialEntries; + mSaveEntries = in.readParcelable(null, android.content.pm.ParceledListSlice.class); AnnotationValidations.validate(NonNull.class, null, mSaveEntries); Entry remoteEntry = in.readTypedObject(Entry.CREATOR); @@ -72,7 +71,7 @@ public final class CreateCredentialProviderData extends ProviderData implements @Override public void writeToParcel(@NonNull Parcel dest, int flags) { super.writeToParcel(dest, flags); - dest.writeTypedList(mSaveEntries); + dest.writeParcelable(mSaveEntries, flags); dest.writeTypedObject(mRemoteEntry, flags); } diff --git a/core/java/android/credentials/ui/GetCredentialProviderData.java b/core/java/android/credentials/ui/GetCredentialProviderData.java index e4688a84a3fb..773dee97f7fe 100644 --- a/core/java/android/credentials/ui/GetCredentialProviderData.java +++ b/core/java/android/credentials/ui/GetCredentialProviderData.java @@ -19,6 +19,7 @@ package android.credentials.ui; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; +import android.content.pm.ParceledListSlice; import android.os.Parcel; import android.os.Parcelable; @@ -35,11 +36,11 @@ import java.util.List; @TestApi public final class GetCredentialProviderData extends ProviderData implements Parcelable { @NonNull - private final List<Entry> mCredentialEntries; + private final ParceledListSlice<Entry> mCredentialEntries; @NonNull - private final List<Entry> mActionChips; + private final ParceledListSlice<Entry> mActionChips; @NonNull - private final List<AuthenticationEntry> mAuthenticationEntries; + private final ParceledListSlice<AuthenticationEntry> mAuthenticationEntries; @Nullable private final Entry mRemoteEntry; @@ -49,25 +50,25 @@ public final class GetCredentialProviderData extends ProviderData implements Par @NonNull List<AuthenticationEntry> authenticationEntries, @Nullable Entry remoteEntry) { super(providerFlattenedComponentName); - mCredentialEntries = credentialEntries; - mActionChips = actionChips; - mAuthenticationEntries = authenticationEntries; + mCredentialEntries = new ParceledListSlice<>(credentialEntries); + mActionChips = new ParceledListSlice<>(actionChips); + mAuthenticationEntries = new ParceledListSlice<>(authenticationEntries); mRemoteEntry = remoteEntry; } @NonNull public List<Entry> getCredentialEntries() { - return mCredentialEntries; + return mCredentialEntries.getList(); } @NonNull public List<Entry> getActionChips() { - return mActionChips; + return mActionChips.getList(); } @NonNull public List<AuthenticationEntry> getAuthenticationEntries() { - return mAuthenticationEntries; + return mAuthenticationEntries.getList(); } @Nullable @@ -77,20 +78,16 @@ public final class GetCredentialProviderData extends ProviderData implements Par private GetCredentialProviderData(@NonNull Parcel in) { super(in); - - List<Entry> credentialEntries = new ArrayList<>(); - in.readTypedList(credentialEntries, Entry.CREATOR); - mCredentialEntries = credentialEntries; + mCredentialEntries = in.readParcelable(null, + android.content.pm.ParceledListSlice.class); AnnotationValidations.validate(NonNull.class, null, mCredentialEntries); - List<Entry> actionChips = new ArrayList<>(); - in.readTypedList(actionChips, Entry.CREATOR); - mActionChips = actionChips; + mActionChips = in.readParcelable(null, + android.content.pm.ParceledListSlice.class); AnnotationValidations.validate(NonNull.class, null, mActionChips); - List<AuthenticationEntry> authenticationEntries = new ArrayList<>(); - in.readTypedList(authenticationEntries, AuthenticationEntry.CREATOR); - mAuthenticationEntries = authenticationEntries; + mAuthenticationEntries = in.readParcelable(null, + android.content.pm.ParceledListSlice.class); AnnotationValidations.validate(NonNull.class, null, mAuthenticationEntries); Entry remoteEntry = in.readTypedObject(Entry.CREATOR); @@ -100,9 +97,9 @@ public final class GetCredentialProviderData extends ProviderData implements Par @Override public void writeToParcel(@NonNull Parcel dest, int flags) { super.writeToParcel(dest, flags); - dest.writeTypedList(mCredentialEntries); - dest.writeTypedList(mActionChips); - dest.writeTypedList(mAuthenticationEntries); + dest.writeParcelable(mCredentialEntries, flags); + dest.writeParcelable(mActionChips, flags); + dest.writeParcelable(mAuthenticationEntries, flags); dest.writeTypedObject(mRemoteEntry, flags); } diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index 6d8c4a93b44e..c2aebd7cfaca 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -450,6 +450,27 @@ public abstract class SensorManager { } /** + * Returns the {@link Sensor} object identified by the given sensor handle. + * + * The raw sensor handle integer is an implementation detail and as such this method should only + * be used by internal system components. + * + * @param sensorHandle The integer handle uniquely identifying the sensor. + * @return A Sensor object identified by the given {@code sensorHandle}, if such a sensor + * exists, {@code null} otherwise. + * + * @hide + */ + public @Nullable Sensor getSensorByHandle(int sensorHandle) { + for (final Sensor sensor : getFullSensorList()) { + if (sensor.getHandle() == sensorHandle) { + return sensor; + } + } + return null; + } + + /** * Use this method to get a list of available dynamic sensors of a certain type. * Make multiple calls to get sensors of different types or use * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all dynamic sensors. diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index 73157e62cb56..d8ab6f7da82d 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -222,6 +222,12 @@ public class SystemSensorManager extends SensorManager { /** @hide */ @Override + public Sensor getSensorByHandle(int sensorHandle) { + return mHandleToSensor.get(sensorHandle); + } + + /** @hide */ + @Override protected List<Sensor> getFullDynamicSensorList() { // only set up broadcast receiver if the application tries to find dynamic sensors or // explicitly register a DynamicSensorCallback diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index fa678fc5ee1a..2e40f6096ccb 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -142,6 +142,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private PromptInfo mPromptInfo; private ButtonInfo mNegativeButtonInfo; private Context mContext; + private IAuthService mService; /** * Creates a builder for a {@link BiometricPrompt} dialog. @@ -212,6 +213,18 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } /** + * @param service + * @return This builder. + * @hide + */ + @RequiresPermission(TEST_BIOMETRIC) + @NonNull + public Builder setService(@NonNull IAuthService service) { + mService = service; + return this; + } + + /** * Sets an optional title, subtitle, and/or description that will override other text when * the user is authenticating with PIN/pattern/password. Currently for internal use only. * @return This builder. @@ -472,7 +485,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan throw new IllegalArgumentException("Can't have both negative button behavior" + " and device credential enabled"); } - return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo); + mService = (mService == null) ? IAuthService.Stub.asInterface( + ServiceManager.getService(Context.AUTH_SERVICE)) : mService; + return new BiometricPrompt(mContext, mPromptInfo, mNegativeButtonInfo, mService); } } @@ -521,7 +536,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan public void onAuthenticationFailed() { mExecutor.execute(() -> { mAuthenticationCallback.onAuthenticationFailed(); - mIsPromptShowing = false; }); } @@ -604,12 +618,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan private boolean mIsPromptShowing; - private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo) { + private BiometricPrompt(Context context, PromptInfo promptInfo, ButtonInfo negativeButtonInfo, + IAuthService service) { mContext = context; mPromptInfo = promptInfo; mNegativeButtonInfo = negativeButtonInfo; - mService = IAuthService.Stub.asInterface( - ServiceManager.getService(Context.AUTH_SERVICE)); + mService = service; mIsPromptShowing = false; } diff --git a/core/java/android/hardware/biometrics/ComponentInfoInternal.java b/core/java/android/hardware/biometrics/ComponentInfoInternal.java index 3b61a56bd9f1..2e708de21762 100644 --- a/core/java/android/hardware/biometrics/ComponentInfoInternal.java +++ b/core/java/android/hardware/biometrics/ComponentInfoInternal.java @@ -19,6 +19,8 @@ package android.hardware.biometrics; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; +import android.util.IndentingPrintWriter; /** * The internal class for storing the component info for a subsystem of the biometric sensor, @@ -90,12 +92,19 @@ public class ComponentInfoInternal implements Parcelable { dest.writeString(softwareVersion); } - @Override - public String toString() { - return "ComponentId: " + componentId - + ", HardwareVersion: " + hardwareVersion - + ", FirmwareVersion: " + firmwareVersion - + ", SerialNumber " + serialNumber - + ", SoftwareVersion: " + softwareVersion; + /** + * Print the component info into the given stream. + * + * @param pw The stream to dump the info into. + * @hide + */ + public void dump(@NonNull IndentingPrintWriter pw) { + pw.println(TextUtils.formatSimple("componentId: %s", componentId)); + pw.increaseIndent(); + pw.println(TextUtils.formatSimple("hardwareVersion: %s", hardwareVersion)); + pw.println(TextUtils.formatSimple("firmwareVersion: %s", firmwareVersion)); + pw.println(TextUtils.formatSimple("serialNumber: %s", serialNumber)); + pw.println(TextUtils.formatSimple("softwareVersion: %s", softwareVersion)); + pw.decreaseIndent(); } } diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl index c88af5aad738..1a38c8897b76 100644 --- a/core/java/android/hardware/biometrics/IBiometricService.aidl +++ b/core/java/android/hardware/biometrics/IBiometricService.aidl @@ -58,10 +58,10 @@ interface IBiometricService { boolean hasEnrolledBiometrics(int userId, String opPackageName); // Registers an authenticator (e.g. face, fingerprint, iris). - // Id must be unique, whereas strength and modality don't need to be. + // Sensor Id in sensor props must be unique, whereas modality doesn't need to be. // TODO(b/123321528): Turn strength and modality into enums. @EnforcePermission("USE_BIOMETRIC_INTERNAL") - void registerAuthenticator(int id, int modality, int strength, + void registerAuthenticator(int modality, in SensorPropertiesInternal props, IBiometricAuthenticator authenticator); // Register callback for when keyguard biometric eligibility changes. diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 5feda785ece3..ad68866571e3 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -1310,6 +1310,10 @@ public abstract class CameraDevice implements AutoCloseable { * {@link Surface}, submitting a reprocess {@link CaptureRequest} with multiple * output targets will result in a {@link CaptureFailure}. * + * From Android 14 onward, {@link CaptureRequest#CONTROL_CAPTURE_INTENT} will be set to + * {@link CameraMetadata#CONTROL_CAPTURE_INTENT_STILL_CAPTURE} by default. Prior to Android 14, + * apps will need to explicitly set this key themselves. + * * @param inputResult The capture result of the output image or one of the output images used * to generate the reprocess input image for this capture request. * diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index cb1efe8c2b55..f2d8caaab0e7 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -26,6 +26,7 @@ import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraExtensionCharacteristics; +import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CameraOfflineSession; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; @@ -861,8 +862,13 @@ public class CameraDeviceImpl extends CameraDevice CameraMetadataNative resultMetadata = new CameraMetadataNative(inputResult.getNativeCopy()); - return new CaptureRequest.Builder(resultMetadata, /*reprocess*/true, - inputResult.getSessionId(), getId(), /*physicalCameraIdSet*/ null); + CaptureRequest.Builder builder = new CaptureRequest.Builder(resultMetadata, + /*reprocess*/true, inputResult.getSessionId(), getId(), + /*physicalCameraIdSet*/ null); + builder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, + CameraMetadata.CONTROL_CAPTURE_INTENT_STILL_CAPTURE); + + return builder; } } diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 2aead3c22deb..72a3f6c0bc88 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -51,9 +51,11 @@ import android.view.Display; import android.view.Surface; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; @@ -81,8 +83,10 @@ public final class DisplayManager { private final DisplayManagerGlobal mGlobal; private final Object mLock = new Object(); - private final SparseArray<Display> mDisplays = new SparseArray<Display>(); + @GuardedBy("mLock") + private final WeakDisplayCache mDisplayCache = new WeakDisplayCache(); + @GuardedBy("mLock") private final ArrayList<Display> mTempDisplays = new ArrayList<Display>(); /** @@ -684,6 +688,7 @@ public final class DisplayManager { } } + @GuardedBy("mLock") private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) { for (int i = 0; i < displayIds.length; i++) { Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); @@ -693,6 +698,7 @@ public final class DisplayManager { } } + @GuardedBy("mLock") private void addDisplaysLocked( ArrayList<Display> displays, int[] displayIds, int matchType, int flagMask) { for (int displayId : displayIds) { @@ -709,8 +715,9 @@ public final class DisplayManager { } } + @GuardedBy("mLock") private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) { - Display display = mDisplays.get(displayId); + Display display = mDisplayCache.get(displayId); if (display == null) { // TODO: We cannot currently provide any override configurations for metrics on displays // other than the display the context is associated with. @@ -719,7 +726,7 @@ public final class DisplayManager { display = mGlobal.getCompatibleDisplay(displayId, resources); if (display != null) { - mDisplays.put(displayId, display); + mDisplayCache.put(display); } } else if (!assumeValid && !display.isValid()) { display = null; @@ -1767,4 +1774,57 @@ public final class DisplayManager { */ String KEY_BRIGHTNESS_THROTTLING_DATA = "brightness_throttling_data"; } + + /** + * Helper class to maintain cache of weak references to Display instances. + * + * Note this class is not thread-safe, so external synchronization is needed if accessed + * concurrently. + */ + private static final class WeakDisplayCache { + private final SparseArray<WeakReference<Display>> mDisplayCache = new SparseArray<>(); + + /** + * Return cached {@link Display} instance for the provided display id. + * + * @param displayId - display id of the requested {@link Display} instance. + * @return cached {@link Display} instance or null + */ + Display get(int displayId) { + WeakReference<Display> wrDisplay = mDisplayCache.get(displayId); + if (wrDisplay == null) { + return null; + } + return wrDisplay.get(); + } + + /** + * Insert new {@link Display} instance in the cache. This replaced the previously cached + * {@link Display} instance, if there's already one with the same display id. + * + * @param display - Display instance to cache. + */ + void put(Display display) { + removeStaleEntries(); + mDisplayCache.put(display.getDisplayId(), new WeakReference<>(display)); + } + + /** + * Evict gc-ed entries from the cache. + */ + private void removeStaleEntries() { + ArrayList<Integer> staleEntriesIndices = new ArrayList(); + for (int i = 0; i < mDisplayCache.size(); i++) { + if (mDisplayCache.valueAt(i).get() == null) { + staleEntriesIndices.add(i); + } + } + + for (int i = 0; i < staleEntriesIndices.size(); i++) { + // removeAt call to SparseArray doesn't compact the underlying array + // so the indices stay valid even after removal. + mDisplayCache.removeAt(staleEntriesIndices.get(i)); + } + } + } } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 9cacfff4b33a..2fec02f91e39 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -53,11 +53,8 @@ import android.view.WindowManager.LayoutParams; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; -import com.android.internal.annotations.VisibleForTesting; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -73,20 +70,10 @@ public final class InputManager { // To enable these logs, run: 'adb shell setprop log.tag.InputManager DEBUG' (requires restart) private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static InputManager sInstance; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final IInputManager mIm; /** - * We hold a weak reference to the context to avoid leaking it indefinitely, - * since we currently store the input manager instance as a static variable that - * will outlive any context. - */ - @Nullable - private WeakReference<Context> mWeakContext; - - /** * Whether a PointerIcon is shown for stylus pointers. * Obtain using {@link #isStylusPointerIconEnabled()}. */ @@ -255,99 +242,43 @@ public final class InputManager { */ public static final int SWITCH_STATE_ON = 1; - private static String sVelocityTrackerStrategy; - - private InputManagerGlobal mGlobal; + private final InputManagerGlobal mGlobal; + private final Context mContext; - private InputManager() { + /** @hide */ + public InputManager(Context context) { mGlobal = InputManagerGlobal.getInstance(); mIm = mGlobal.getInputManagerService(); - try { - sVelocityTrackerStrategy = mIm.getVelocityTrackerStrategy(); - } catch (RemoteException ex) { - Log.w(TAG, "Could not get VelocityTracker strategy: " + ex); - } + mContext = context; } /** * Gets an instance of the input manager. * - * @return The input manager instance. + * Warning: The usage of this method is not supported! * - * @hide - */ - @VisibleForTesting - public static InputManager resetInstance(IInputManager inputManagerService) { - synchronized (InputManager.class) { - InputManagerGlobal.resetInstance(inputManagerService); - sInstance = new InputManager(); - return sInstance; - } - } - - /** - * Clear the instance of the input manager. + * @return The input manager instance. + * Use {@link Context#getSystemService(Class)} + * to obtain the InputManager instance. * - * @hide - */ - @VisibleForTesting - public static void clearInstance() { - synchronized (InputManager.class) { - InputManagerGlobal.clearInstance(); - sInstance = null; - } - } - - /** - * Gets an instance of the input manager. + * TODO (b/277717573): Soft remove this API in version V. + * TODO (b/277039664): Migrate app usage off this API. * - * @return The input manager instance. - * @deprecated Use {@link Context#getSystemService(Class)} or {@link #getInstance(Context)} - * to obtain the InputManager instance. * @hide */ @Deprecated @UnsupportedAppUsage public static InputManager getInstance() { - return getInstance(ActivityThread.currentApplication()); + return Objects.requireNonNull(ActivityThread.currentApplication()) + .getSystemService(InputManager.class); } /** - * Gets an instance of the input manager. - * - * @return The input manager instance. - * @hide - */ - public static InputManager getInstance(Context context) { - synchronized (InputManager.class) { - if (sInstance == null) { - sInstance = new InputManager(); - } - if (sInstance.mWeakContext == null || sInstance.mWeakContext.get() == null) { - sInstance.mWeakContext = new WeakReference(context); - } - return sInstance; - } - } - - @NonNull - private Context getContext() { - WeakReference<Context> weakContext = Objects.requireNonNull(mWeakContext, - "A context is required for InputManager. Get the InputManager instance using " - + "Context#getSystemService before calling this method."); - // If we get at this point, an app calling this function could potentially expect a - // Context that has disappeared due to garbage collection. Holding a weak reference - // is a temporary solution that should be resolved before the release of a - // production version. This is being tracked in b/267758905 - return Objects.requireNonNull(weakContext.get(), "missing Context"); - } - - /** - * Get the current VelocityTracker strategy. Only works when the system has fully booted up. + * Get the current VelocityTracker strategy. * @hide */ public String getVelocityTrackerStrategy() { - return sVelocityTrackerStrategy; + return mGlobal.getVelocityTrackerStrategy(); } /** @@ -584,11 +515,7 @@ public final class InputManager { @NonNull public KeyboardLayout[] getKeyboardLayoutsForInputDevice( @NonNull InputDeviceIdentifier identifier) { - try { - return mIm.getKeyboardLayoutsForInputDevice(identifier); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } + return mGlobal.getKeyboardLayoutsForInputDevice(identifier); } /** @@ -647,19 +574,8 @@ public final class InputManager { @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT) public void setCurrentKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier, @NonNull String keyboardLayoutDescriptor) { - if (identifier == null) { - throw new IllegalArgumentException("identifier must not be null"); - } - if (keyboardLayoutDescriptor == null) { - throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); - } - - try { - mIm.setCurrentKeyboardLayoutForInputDevice(identifier, - keyboardLayoutDescriptor); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } + mGlobal.setCurrentKeyboardLayoutForInputDevice(identifier, + keyboardLayoutDescriptor); } /** @@ -956,8 +872,7 @@ public final class InputManager { */ @FloatRange(from = 0, to = 1) public float getMaximumObscuringOpacityForTouch() { - Context context = ActivityThread.currentApplication(); - return InputSettings.getMaximumObscuringOpacityForTouch(context); + return InputSettings.getMaximumObscuringOpacityForTouch(mContext); } /** @@ -1123,7 +1038,7 @@ public final class InputManager { */ public boolean isStylusPointerIconEnabled() { if (mIsStylusPointerIconEnabled == null) { - mIsStylusPointerIconEnabled = getContext().getResources() + mIsStylusPointerIconEnabled = mContext.getResources() .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon) || InputProperties.force_enable_stylus_pointer_icon().orElse(false); } diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java index 701980d5f6f3..5462171be7e1 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -102,17 +102,26 @@ public final class InputManagerGlobal { private static InputManagerGlobal sInstance; + private final String mVelocityTrackerStrategy; + private final IInputManager mIm; public InputManagerGlobal(IInputManager im) { mIm = im; + String strategy = null; + try { + strategy = mIm.getVelocityTrackerStrategy(); + } catch (RemoteException ex) { + Log.w(TAG, "Could not get VelocityTracker strategy: " + ex); + } + mVelocityTrackerStrategy = strategy; } /** * Gets an instance of the input manager global singleton. * - * @return The display manager instance, may be null early in system startup - * before the display manager has been fully initialized. + * @return The input manager instance, may be null early in system startup + * before the input manager has been fully initialized. */ public static InputManagerGlobal getInstance() { synchronized (InputManagerGlobal.class) { @@ -152,6 +161,14 @@ public final class InputManagerGlobal { } /** + * Get the current VelocityTracker strategy. + * Only works when the system has fully booted up. + */ + public String getVelocityTrackerStrategy() { + return mVelocityTrackerStrategy; + } + + /** * @see InputManager#getInputDevice(int) */ @Nullable @@ -309,9 +326,7 @@ public final class InputManagerGlobal { * @see InputManager#registerInputDeviceListener */ public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + Objects.requireNonNull(listener, "listener must not be null"); synchronized (mInputDeviceListeners) { populateInputDevicesLocked(); @@ -407,9 +422,7 @@ public final class InputManagerGlobal { * @see InputManager#getInputDeviceByDescriptor */ InputDevice getInputDeviceByDescriptor(String descriptor) { - if (descriptor == null) { - throw new IllegalArgumentException("descriptor must not be null."); - } + Objects.requireNonNull(descriptor, "descriptor must not be null."); synchronized (mInputDeviceListeners) { populateInputDevicesLocked(); @@ -526,9 +539,8 @@ public final class InputManagerGlobal { */ void registerOnTabletModeChangedListener( OnTabletModeChangedListener listener, Handler handler) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + Objects.requireNonNull(listener, "listener must not be null"); + synchronized (mOnTabletModeChangedListeners) { if (mOnTabletModeChangedListeners == null) { initializeTabletModeListenerLocked(); @@ -546,9 +558,8 @@ public final class InputManagerGlobal { * @see InputManager#unregisterOnTabletModeChangedListener(OnTabletModeChangedListener) */ void unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + Objects.requireNonNull(listener, "listener must not be null"); + synchronized (mOnTabletModeChangedListeners) { int idx = findOnTabletModeChangedListenerLocked(listener); if (idx >= 0) { @@ -603,7 +614,7 @@ public final class InputManagerGlobal { /** * @see InputManager#addInputDeviceBatteryListener(int, Executor, InputDeviceBatteryListener) */ - void addInputDeviceBatteryListener(int deviceId, @NonNull Executor executor, + public void addInputDeviceBatteryListener(int deviceId, @NonNull Executor executor, @NonNull InputDeviceBatteryListener listener) { Objects.requireNonNull(executor, "executor should not be null"); Objects.requireNonNull(listener, "listener should not be null"); @@ -714,7 +725,7 @@ public final class InputManagerGlobal { } /** - * @see InputManager#getInputDeviceBatteryState(int, boolean) + * @see #getInputDeviceBatteryState(int, boolean) */ @NonNull public BatteryState getInputDeviceBatteryState(int deviceId, boolean hasBattery) { @@ -877,6 +888,38 @@ public final class InputManagerGlobal { } /** + * @see InputManager#getKeyboardLayoutsForInputDevice(InputDeviceIdentifier) + */ + @NonNull + public KeyboardLayout[] getKeyboardLayoutsForInputDevice( + @NonNull InputDeviceIdentifier identifier) { + try { + return mIm.getKeyboardLayoutsForInputDevice(identifier); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * @see InputManager#setCurrentKeyboardLayoutForInputDevice + * (InputDeviceIdentifier, String) + */ + @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT) + public void setCurrentKeyboardLayoutForInputDevice( + @NonNull InputDeviceIdentifier identifier, + @NonNull String keyboardLayoutDescriptor) { + Objects.requireNonNull(identifier, "identifier must not be null"); + Objects.requireNonNull(keyboardLayoutDescriptor, + "keyboardLayoutDescriptor must not be null"); + try { + mIm.setCurrentKeyboardLayoutForInputDevice(identifier, + keyboardLayoutDescriptor); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * @see InputDevice#getSensorManager() */ @NonNull @@ -1162,9 +1205,8 @@ public final class InputManagerGlobal { */ public boolean injectInputEvent(InputEvent event, int mode, int targetUid) { - if (event == null) { - throw new IllegalArgumentException("event must not be null"); - } + Objects.requireNonNull(event , "event must not be null"); + if (mode != InputEventInjectionSync.NONE && mode != InputEventInjectionSync.WAIT_FOR_FINISHED && mode != InputEventInjectionSync.WAIT_FOR_RESULT) { diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl index dcc336966810..466373030c78 100644 --- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl +++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl @@ -42,12 +42,6 @@ oneway interface IRecognitionStatusCallback { void onGenericSoundTriggerDetected(in SoundTrigger.GenericRecognitionEvent recognitionEvent); /** - * Called when the detection fails due to an error. - * - * @param status The error code that was seen. - */ - void onError(int status); - /** * Called when the recognition is paused temporarily for some reason. */ void onRecognitionPaused(); @@ -55,4 +49,28 @@ oneway interface IRecognitionStatusCallback { * Called when the recognition is resumed after it was temporarily paused. */ void onRecognitionResumed(); + + // Error callbacks to follow + /** + * Called when this recognition has been preempted by another. + */ + void onPreempted(); + + /** + * Called when the underlying ST module service has died. + */ + void onModuleDied(); + + /** + * Called when the service failed to gracefully resume recognition following a pause. + * @param status - The received error code. + */ + void onResumeFailed(int status); + + /** + * Called when the service failed to pause recognition when required. + * TODO(b/276507281) Remove. This should never happen, so we should abort instead. + * @param status - The received error code. + */ + void onPauseFailed(int status); } diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index fa16e167f7d1..6d43ddf7fe94 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -1051,6 +1051,29 @@ public class SoundTrigger { return "ModelParamRange [start=" + mStart + ", end=" + mEnd + "]"; } } + /** + * SoundTrigger model parameter types. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "MODEL_PARAM" }, value = { + MODEL_PARAM_INVALID, + MODEL_PARAM_THRESHOLD_FACTOR + }) + public @interface ModelParamTypes {} + + /** + * See {@link ModelParams.INVALID} + * @hide + */ + @TestApi + public static final int MODEL_PARAM_INVALID = ModelParams.INVALID; + /** + * See {@link ModelParams.THRESHOLD_FACTOR} + * @hide + */ + @TestApi + public static final int MODEL_PARAM_THRESHOLD_FACTOR = ModelParams.THRESHOLD_FACTOR; /** * Modes for key phrase recognition @@ -1450,7 +1473,8 @@ public class SoundTrigger { * * @hide */ - public static class RecognitionConfig implements Parcelable { + @TestApi + public static final class RecognitionConfig implements Parcelable { /** True if the DSP should capture the trigger sound and make it available for further * capture. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -1464,6 +1488,7 @@ public class SoundTrigger { * options for each keyphrase. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @NonNull + @SuppressLint("ArrayReturn") public final KeyphraseRecognitionExtra keyphrases[]; /** Opaque data for use by system applications who know about voice engine internals, * typically during enrollment. */ @@ -1479,8 +1504,8 @@ public class SoundTrigger { public final int audioCapabilities; public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers, - @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data, - int audioCapabilities) { + @SuppressLint("ArrayReturn") @Nullable KeyphraseRecognitionExtra[] keyphrases, + @Nullable byte[] data, int audioCapabilities) { this.captureRequested = captureRequested; this.allowMultipleTriggers = allowMultipleTriggers; this.keyphrases = keyphrases != null ? keyphrases : new KeyphraseRecognitionExtra[0]; @@ -1490,7 +1515,8 @@ public class SoundTrigger { @UnsupportedAppUsage public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers, - @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data) { + @SuppressLint("ArrayReturn") @Nullable KeyphraseRecognitionExtra[] keyphrases, + @Nullable byte[] data) { this(captureRequested, allowMultipleTriggers, keyphrases, data, 0); } @@ -1517,7 +1543,7 @@ public class SoundTrigger { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeByte((byte) (captureRequested ? 1 : 0)); dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0)); dest.writeTypedArray(keyphrases, flags); diff --git a/core/java/android/inputmethodservice/InkWindow.java b/core/java/android/inputmethodservice/InkWindow.java index 15ed45041d32..24d1c9577f82 100644 --- a/core/java/android/inputmethodservice/InkWindow.java +++ b/core/java/android/inputmethodservice/InkWindow.java @@ -195,6 +195,7 @@ final class InkWindow extends PhoneWindow { Objects.requireNonNull(decor); final ViewRootImpl viewRoot = decor.getViewRootImpl(); Objects.requireNonNull(viewRoot); - viewRoot.enqueueInputEvent(event); + // The view root will own the event that we enqueue, so provide a copy of the event. + viewRoot.enqueueInputEvent(MotionEvent.obtain(event)); } } diff --git a/core/java/android/nfc/tech/NdefFormatable.java b/core/java/android/nfc/tech/NdefFormatable.java index f19d30258393..2240fe7f7d3b 100644 --- a/core/java/android/nfc/tech/NdefFormatable.java +++ b/core/java/android/nfc/tech/NdefFormatable.java @@ -124,6 +124,9 @@ public final class NdefFormatable extends BasicTagTechnology { try { int serviceHandle = mTag.getServiceHandle(); INfcTag tagService = mTag.getTagService(); + if (tagService == null) { + throw new IOException(); + } int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT); switch (errorCode) { case ErrorCodes.SUCCESS: diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 244632a87593..7383e633fb93 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -493,7 +493,7 @@ public class Build { * @hide */ @TestApi - public static final int RESOURCES_SDK_INT = SDK_INT + ACTIVE_CODENAMES.length; + public static final int RESOURCES_SDK_INT = SDK_INT; /** * The current lowest supported value of app target SDK. Applications targeting @@ -1222,7 +1222,7 @@ public class Build { /** * Upside Down Cake. */ - public static final int UPSIDE_DOWN_CAKE = CUR_DEVELOPMENT; + public static final int UPSIDE_DOWN_CAKE = 34; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index b2208d19d9ee..bf3d52d358ed 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -1499,6 +1499,15 @@ public class Process { public static final native int killProcessGroup(int uid, int pid); /** + * Send a signal to all processes in a group under the given PID, but do not wait for the + * processes to be fully cleaned up, or for the cgroup to be removed before returning. + * Callers should also ensure that killProcessGroup is called later to ensure the cgroup is + * fully removed, otherwise system resources may leak. + * @hide + */ + public static final native int sendSignalToProcessGroup(int uid, int pid, int signal); + + /** * Freeze the cgroup for the given UID. * This cgroup may contain child cgroups which will also be frozen. If this cgroup or its * children contain processes with Binder interfaces, those interfaces should be frozen before diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index b3604da49f5e..24e28e95cd98 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -3706,17 +3706,24 @@ public class UserManager { * {@link android.Manifest.permission#CREATE_USERS} suffices if flags are in * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION. * + * * @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_GUEST}. * @return the {@link UserInfo} object for the created user. * * @throws UserOperationException if the user could not be created. + * + * @deprecated Pre-created users are deprecated. This method should no longer be used, and will + * be removed once all the callers are removed. + * * @hide */ + @Deprecated @TestApi @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, Manifest.permission.CREATE_USERS}) public @NonNull UserInfo preCreateUser(@NonNull String userType) throws UserOperationException { + Log.w(TAG, "preCreateUser(): Pre-created user is deprecated."); try { return mService.preCreateUserWithThrow(userType); } catch (ServiceSpecificException e) { @@ -4296,8 +4303,12 @@ public class UserManager { /** * Returns information for all users on this device, based on the filtering parameters. * + * @deprecated Pre-created users are deprecated and no longer supported. + * Use {@link #getUsers()}, {@link #getUsers(boolean)}, or {@link #getAliveUsers()} + * instead. * @hide */ + @Deprecated @TestApi @RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_USERS, diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java index 63259edeae7d..218ecc8c5571 100644 --- a/core/java/android/os/image/DynamicSystemClient.java +++ b/core/java/android/os/image/DynamicSystemClient.java @@ -202,6 +202,13 @@ public class DynamicSystemClient { public static final String ACTION_NOTIFY_IF_IN_USE = "android.os.image.action.NOTIFY_IF_IN_USE"; + /** + * Intent action: hide notifications about the status of {@code DynamicSystem}. + * @hide + */ + public static final String ACTION_HIDE_NOTIFICATION = + "android.os.image.action.HIDE_NOTIFICATION"; + /* * Intent Keys */ @@ -217,6 +224,28 @@ public class DynamicSystemClient { */ public static final String KEY_USERDATA_SIZE = "KEY_USERDATA_SIZE"; + /** + * Intent key: Whether to enable DynamicSystem immediately after installation is done. + * Note this will reboot the device automatically. + * @hide + */ + public static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED"; + + /** + * Intent key: Whether to leave DynamicSystem on device reboot. + * False indicates a sticky mode where device stays in DynamicSystem across reboots. + * @hide + */ + public static final String KEY_ONE_SHOT = "KEY_ONE_SHOT"; + + /** + * Intent key: Whether to use default strings when showing the dialog that prompts + * user for device credentials. + * False indicates using the custom strings provided by {@code DynamicSystem}. + * @hide + */ + public static final String KEY_KEYGUARD_USE_DEFAULT_STRINGS = + "KEY_KEYGUARD_USE_DEFAULT_STRINGS"; private static class IncomingHandler extends Handler { private final WeakReference<DynamicSystemClient> mWeakClient; diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS index d34b45bf1ff1..4603e43fd164 100644 --- a/core/java/android/permission/OWNERS +++ b/core/java/android/permission/OWNERS @@ -1,18 +1,19 @@ # Bug component: 137825 -evanseverson@google.com -evanxinchen@google.com ashfall@google.com -guojing@google.com +augale@google.com +evanseverson@google.com +fayey@google.com jaysullivan@google.com +joecastro@google.com kvakil@google.com mrulhania@google.com narayan@google.com ntmyren@google.com olekarg@google.com pyuli@google.com -raphk@google.com rmacgregor@google.com sergeynv@google.com theianchen@google.com +yutingfang@google.com zhanghai@google.com diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c473d3f81823..d75d18643d9e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1748,6 +1748,21 @@ public final class Settings { public static final String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"; /** + * Activity Action: Show Communal settings. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_COMMUNAL_SETTING = "android.settings.COMMUNAL_SETTINGS"; + + /** * Activity Action: Show Notification assistant settings. * <p> * In some cases, a matching Activity may not exist, so ensure you @@ -2585,7 +2600,7 @@ public final class Settings { * <p> * To start an activity with this intent, apps should set the wellbeing package explicitly in * the intent together with this action. The wellbeing package is defined in - * {@code com.android.internal.R.string.config_defaultWellbeingPackage}. + * {@code com.android.internal.R.string.config_systemWellbeing}. * <p> * Output: Nothing * @@ -3431,7 +3446,7 @@ public final class Settings { + " type:" + mUri.getPath() + " in package:" + cr.getPackageName()); } - for (int i = 0; i < mValues.size(); ++i) { + for (int i = mValues.size() - 1; i >= 0; i--) { String key = mValues.keyAt(i); if (key.startsWith(prefix)) { mValues.remove(key); @@ -18125,12 +18140,6 @@ public final class Settings { public static final String WEAR_OS_VERSION_STRING = "wear_os_version_string"; /** - * Whether the physical button has been set. - * @hide - */ - public static final String BUTTON_SET = "button_set"; - - /** * Whether there is a side button. * @hide */ @@ -18302,6 +18311,12 @@ public final class Settings { public static final int COMPANION_OS_VERSION_UNDEFINED = -1; /** + * The companion App name. + * @hide + */ + public static final String COMPANION_APP_NAME = "wear_companion_app_name"; + + /** * A boolean value to indicate if we want to support all languages in LE edition on * wear. 1 for supporting, 0 for not supporting. * @hide @@ -18413,10 +18428,13 @@ public final class Settings { public static final String BURN_IN_PROTECTION_ENABLED = "burn_in_protection"; /** - * Whether the device has combined location setting enabled. + * + * @deprecated Use LocationManager as the source of truth for all location states. + * * @hide */ + @Deprecated public static final String COMBINED_LOCATION_ENABLED = "combined_location_enable"; /** @@ -18482,67 +18500,36 @@ public final class Settings { public static final String CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED = "clockwork_long_press_to_assistant_enabled"; - /* + /** * Whether the device has Cooldown Mode enabled. * @hide */ public static final String COOLDOWN_MODE_ON = "cooldown_mode_on"; - /* + /** * Whether the device has Wet Mode/ Touch Lock Mode enabled. * @hide */ public static final String WET_MODE_ON = "wet_mode_on"; - /* + /** * Whether the RSB wake feature is enabled. * @hide */ public static final String RSB_WAKE_ENABLED = "rsb_wake_enabled"; - /* + /** * Whether the screen-unlock (keyguard) sound is enabled. * @hide */ public static final String SCREEN_UNLOCK_SOUND_ENABLED = "screen_unlock_sound_enabled"; - /* + /** * Whether charging sounds are enabled. * @hide */ public static final String CHARGING_SOUNDS_ENABLED = "wear_charging_sounds_enabled"; - /** The status of the early updates process. - * @hide - */ - public static final String EARLY_UPDATES_STATUS = "early_updates_status"; - - /** - * Early updates not started - * @hide - */ - public static final int EARLY_UPDATES_STATUS_NOT_STARTED = 0; - /** - * Early updates started and in progress - * @hide - */ - public static final int EARLY_UPDATES_STATUS_STARTED = 1; - /** - * Early updates completed and was successful - * @hide - */ - public static final int EARLY_UPDATES_STATUS_SUCCESS = 2; - /** - * Early updates skipped - * @hide - */ - public static final int EARLY_UPDATES_STATUS_SKIPPED = 3; - /** - * Early updates aborted due to timeout - * @hide - */ - public static final int EARLY_UPDATES_STATUS_ABORTED = 4; - /** * Whether dynamic color theming (e.g. Material You) is enabled for apps which support * it. @@ -18669,6 +18656,174 @@ public final class Settings { * @hide */ public static final int UPGRADE_DATA_MIGRATION_DONE = 2; + + /** + * Whether to disable AOD while plugged. + * (0 = false, 1 = true) + * @hide + */ + public static final String DISABLE_AOD_WHILE_PLUGGED = "disable_aod_while_plugged"; + + /** + * Whether the user has consented for network location provider (NLP). + * This setting key will only be used once during OOBE to set NLP initial value through + * the companion app ToS. This setting key will be synced over from Companion and + * corresponding toggle in GMS will be enabled. + * @hide + */ + public static final String NETWORK_LOCATION_OPT_IN = "network_location_opt_in"; + + /** + * The custom foreground color. + * @hide + */ + public static final String CUSTOM_COLOR_FOREGROUND = "custom_foreground_color"; + + /** + * The custom background color. + * @hide + */ + public static final String CUSTOM_COLOR_BACKGROUND = "custom_background_color"; + + /** The status of the phone switching process. + * @hide + */ + public static final String PHONE_SWITCHING_STATUS = "phone_switching_status"; + + /** + * Phone switching not started + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_NOT_STARTED = 0; + + /** + * Phone switching started + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_STARTED = 1; + + /** + * Phone switching completed and was successful + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_SUCCESS = 2; + + /** + * Phone switching was cancelled + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_CANCELLED = 3; + + /** + * Phone switching failed + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_FAILED = 4; + + /** + * Phone switching is in progress of advertising to new companion device. + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_IN_PROGRESS_ADVERTISING = 5; + + /** + * Phone switching successfully bonded with new companion device. + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_IN_PROGRESS_BONDED = 6; + + /** + * Phone switching successfully completed on phone side. + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_IN_PROGRESS_PHONE_COMPLETE = 7; + + /** + * Connection config migration in progress. + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_IN_PROGRESS_MIGRATION = 8; + + /** + * Connection config migration failed. + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_IN_PROGRESS_MIGRATION_FAILED = 9; + + /** + * Connection config migration cancellation in progress. + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_IN_PROGRESS_MIGRATION_CANCELLED = 10; + + /** + * Connection config migration success. + * @hide + */ + public static final int PHONE_SWITCHING_STATUS_IN_PROGRESS_MIGRATION_SUCCESS = 11; + + + /** + * Whether the device has enabled the feature to reduce motion and animation + * (0 = false, 1 = true) + * @hide + */ + public static final String REDUCE_MOTION = "reduce_motion"; + + /** + * Whether RTL swipe-to-dismiss is enabled by developer options. + * (0 = false, 1 = true) + * @hide + */ + public static final String RTL_SWIPE_TO_DISMISS_ENABLED_DEV = + "rtl_swipe_to_dismiss_enabled_dev"; + + /** + * Tethered Configuration state. + * @hide + */ + public static final String TETHER_CONFIG_STATE = "tethered_config_state"; + + /** + * Tethered configuration state is unknown. + * @hide + */ + public static final int TETHERED_CONFIG_UNKNOWN = 0; + + /** + * Device is set into standalone mode. + * @hide + */ + public static final int TETHERED_CONFIG_STANDALONE = 1; + + /** + * Device is set in tethered mode. + * @hide + */ + public static final int TETHERED_CONFIG_TETHERED = 2; + + + /** + * Whether phone switching is supported. + * + * (0 = false, 1 = true) + * @hide + */ + public static final String PHONE_SWITCHING_SUPPORTED = "phone_switching_supported"; + + /** + * Setting indicating the name of the Wear OS package that hosts the Media Controls UI. + * + * @hide + */ + public static final String WEAR_MEDIA_CONTROLS_PACKAGE = "wear_media_controls_package"; + + /** + * Setting indicating the name of the Wear OS package responsible for bridging media. + * + * @hide + */ + public static final String WEAR_MEDIA_SESSIONS_PACKAGE = "wear_media_sessions_package"; } } diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index d2f9ff01ca98..59b945c9c9a4 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -2051,6 +2051,14 @@ public final class Telephony { * <P>Type: TEXT</P> */ public static final String ADDRESS = "address"; + + /** + * The subscription to which the message belongs to. Its value will be less than 0 + * if the sub id cannot be determined. + * <p>Type: INTEGER (long) </p> + * @hide + */ + public static final String SUBSCRIPTION_ID = "sub_id"; } /** @@ -2119,6 +2127,14 @@ public final class Telephony { * <P>Type: INTEGER (boolean)</P> */ public static final String ARCHIVED = "archived"; + + /** + * The subscription to which the message belongs to. Its value will be less than 0 + * if the sub id cannot be determined. + * <p>Type: INTEGER (long) </p> + * @hide + */ + public static final String SUBSCRIPTION_ID = "sub_id"; } /** @@ -2477,6 +2493,14 @@ public final class Telephony { public static final String CHARSET = "charset"; /** + * The subscription to which the message belongs to. Its value will be less than 0 + * if the sub id cannot be determined. + * <p>Type: INTEGER (long) </p> + * @hide + */ + public static final String SUBSCRIPTION_ID = "sub_id"; + + /** * Generates a Addr {@link Uri} for message, used to perform Addr table operation * for mms. * @@ -2597,6 +2621,14 @@ public final class Telephony { public static final String TEXT = "text"; /** + * The subscription to which the message belongs to. Its value will be less than 0 + * if the sub id cannot be determined. + * <p>Type: INTEGER (long) </p> + * @hide + */ + public static final String SUBSCRIPTION_ID = "sub_id"; + + /** * Generates a Part {@link Uri} for message, used to perform Part table operation * for mms. * @@ -2635,6 +2667,14 @@ public final class Telephony { * <P>Type: INTEGER (long)</P> */ public static final String SENT_TIME = "sent_time"; + + /** + * The subscription to which the message belongs to. Its value will be less than 0 + * if the sub id cannot be determined. + * <p>Type: INTEGER (long) </p> + * @hide + */ + public static final String SUBSCRIPTION_ID = "sub_id"; } /** @@ -2868,6 +2908,14 @@ public final class Telephony { * <P>Type: TEXT</P> */ public static final String INDEXED_TEXT = "index_text"; + + /** + * The subscription to which the message belongs to. Its value will be less than 0 + * if the sub id cannot be determined. + * <p>Type: INTEGER (long) </p> + * @hide + */ + public static final String SUBSCRIPTION_ID = "sub_id"; } } diff --git a/core/java/android/security/net/config/ManifestConfigSource.java b/core/java/android/security/net/config/ManifestConfigSource.java index b885e726918d..0e20997d307f 100644 --- a/core/java/android/security/net/config/ManifestConfigSource.java +++ b/core/java/android/security/net/config/ManifestConfigSource.java @@ -25,7 +25,7 @@ import java.util.Set; /** @hide */ public class ManifestConfigSource implements ConfigSource { - private static final boolean DBG = true; + private static final boolean DBG = false; private static final String LOG_TAG = "NetworkSecurityConfig"; private final Object mLock = new Object(); diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java index cd53cb6afc71..df934335e49d 100644 --- a/core/java/android/service/credentials/BeginCreateCredentialResponse.java +++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.content.pm.ParceledListSlice; import android.os.Parcel; import android.os.Parcelable; @@ -33,7 +34,7 @@ import java.util.Objects; * Response to a {@link BeginCreateCredentialRequest}. */ public final class BeginCreateCredentialResponse implements Parcelable { - private final @NonNull List<CreateEntry> mCreateEntries; + private final @NonNull ParceledListSlice<CreateEntry> mCreateEntries; private final @Nullable RemoteEntry mRemoteCreateEntry; /** @@ -41,19 +42,19 @@ public final class BeginCreateCredentialResponse implements Parcelable { * to return. */ public BeginCreateCredentialResponse() { - this(/*createEntries=*/new ArrayList<>(), /*remoteCreateEntry=*/null); + this(/*createEntries=*/new ParceledListSlice<>(new ArrayList<>()), + /*remoteCreateEntry=*/null); } private BeginCreateCredentialResponse(@NonNull Parcel in) { - List<CreateEntry> createEntries = new ArrayList<>(); - in.readTypedList(createEntries, CreateEntry.CREATOR); - mCreateEntries = createEntries; + mCreateEntries = in.readParcelable( + null, android.content.pm.ParceledListSlice.class); mRemoteCreateEntry = in.readTypedObject(RemoteEntry.CREATOR); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeTypedList(mCreateEntries); + dest.writeParcelable(mCreateEntries, flags); dest.writeTypedObject(mRemoteCreateEntry, flags); } @@ -76,7 +77,7 @@ public final class BeginCreateCredentialResponse implements Parcelable { }; /* package-private */ BeginCreateCredentialResponse( - @NonNull List<CreateEntry> createEntries, + @NonNull ParceledListSlice<CreateEntry> createEntries, @Nullable RemoteEntry remoteCreateEntry) { this.mCreateEntries = createEntries; com.android.internal.util.AnnotationValidations.validate( @@ -86,7 +87,7 @@ public final class BeginCreateCredentialResponse implements Parcelable { /** Returns the list of create entries to be displayed on the UI. */ public @NonNull List<CreateEntry> getCreateEntries() { - return mCreateEntries; + return mCreateEntries.getList(); } /** Returns the remote create entry to be displayed on the UI. */ @@ -159,7 +160,9 @@ public final class BeginCreateCredentialResponse implements Parcelable { * Builds a new instance of {@link BeginCreateCredentialResponse}. */ public @NonNull BeginCreateCredentialResponse build() { - return new BeginCreateCredentialResponse(mCreateEntries, mRemoteCreateEntry); + return new BeginCreateCredentialResponse( + new ParceledListSlice<>(mCreateEntries), + mRemoteCreateEntry); } } } diff --git a/core/java/android/service/credentials/BeginGetCredentialResponse.java b/core/java/android/service/credentials/BeginGetCredentialResponse.java index e25b6869605d..5ed06ac1ade7 100644 --- a/core/java/android/service/credentials/BeginGetCredentialResponse.java +++ b/core/java/android/service/credentials/BeginGetCredentialResponse.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.content.pm.ParceledListSlice; import android.os.Parcel; import android.os.Parcelable; @@ -35,13 +36,13 @@ import java.util.Objects; */ public final class BeginGetCredentialResponse implements Parcelable { /** List of credential entries to be displayed on the UI. */ - private final @NonNull List<CredentialEntry> mCredentialEntries; + private final @NonNull ParceledListSlice<CredentialEntry> mCredentialEntries; /** List of authentication entries to be displayed on the UI. */ - private final @NonNull List<Action> mAuthenticationEntries; + private final @NonNull ParceledListSlice<Action> mAuthenticationEntries; /** List of provider actions to be displayed on the UI. */ - private final @NonNull List<Action> mActions; + private final @NonNull ParceledListSlice<Action> mActions; /** Remote credential entry to get the response from a different device. */ private final @Nullable RemoteEntry mRemoteCredentialEntry; @@ -51,31 +52,30 @@ public final class BeginGetCredentialResponse implements Parcelable { * or {@link Action} to return. */ public BeginGetCredentialResponse() { - this(/*credentialEntries=*/new ArrayList<>(), - /*authenticationActions=*/new ArrayList<>(), - /*actions=*/new ArrayList<>(), + this(/*credentialEntries=*/new ParceledListSlice<>(new ArrayList<>()), + /*authenticationEntries=*/new ParceledListSlice<>(new ArrayList<>()), + /*actions=*/new ParceledListSlice<>(new ArrayList<>()), /*remoteCredentialEntry=*/null); } - private BeginGetCredentialResponse(@NonNull List<CredentialEntry> credentialEntries, - @NonNull List<Action> authenticationEntries, @NonNull List<Action> actions, + private BeginGetCredentialResponse( + @NonNull ParceledListSlice<CredentialEntry> credentialEntries, + @NonNull ParceledListSlice<Action> authenticationEntries, + @NonNull ParceledListSlice<Action> actions, @Nullable RemoteEntry remoteCredentialEntry) { - mCredentialEntries = new ArrayList<>(credentialEntries); - mAuthenticationEntries = new ArrayList<>(authenticationEntries); - mActions = new ArrayList<>(actions); + mCredentialEntries = credentialEntries; + mAuthenticationEntries = authenticationEntries; + mActions = actions; mRemoteCredentialEntry = remoteCredentialEntry; } private BeginGetCredentialResponse(@NonNull Parcel in) { - List<CredentialEntry> credentialEntries = new ArrayList<>(); - in.readTypedList(credentialEntries, CredentialEntry.CREATOR); - mCredentialEntries = credentialEntries; - List<Action> authenticationEntries = new ArrayList<>(); - in.readTypedList(authenticationEntries, Action.CREATOR); - mAuthenticationEntries = authenticationEntries; - List<Action> actions = new ArrayList<>(); - in.readTypedList(actions, Action.CREATOR); - mActions = actions; + mCredentialEntries = in.readParcelable( + null, android.content.pm.ParceledListSlice.class); + mAuthenticationEntries = in.readParcelable( + null, android.content.pm.ParceledListSlice.class); + mActions = in.readParcelable( + null, android.content.pm.ParceledListSlice.class); mRemoteCredentialEntry = in.readTypedObject(RemoteEntry.CREATOR); } @@ -99,9 +99,9 @@ public final class BeginGetCredentialResponse implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeTypedList(mCredentialEntries, flags); - dest.writeTypedList(mAuthenticationEntries, flags); - dest.writeTypedList(mActions, flags); + dest.writeParcelable(mCredentialEntries, flags); + dest.writeParcelable(mAuthenticationEntries, flags); + dest.writeParcelable(mActions, flags); dest.writeTypedObject(mRemoteCredentialEntry, flags); } @@ -109,21 +109,22 @@ public final class BeginGetCredentialResponse implements Parcelable { * Returns the list of credential entries to be displayed on the UI. */ public @NonNull List<CredentialEntry> getCredentialEntries() { - return mCredentialEntries; + return mCredentialEntries.getList(); } /** * Returns the list of authentication entries to be displayed on the UI. */ public @NonNull List<Action> getAuthenticationActions() { - return mAuthenticationEntries; + return mAuthenticationEntries.getList(); } /** * Returns the list of actions to be displayed on the UI. */ public @NonNull List<Action> getActions() { - return mActions; + + return mActions.getList(); } /** @@ -268,8 +269,11 @@ public final class BeginGetCredentialResponse implements Parcelable { * Builds a {@link BeginGetCredentialResponse} instance. */ public @NonNull BeginGetCredentialResponse build() { - return new BeginGetCredentialResponse(mCredentialEntries, mAuthenticationEntries, - mActions, mRemoteCredentialEntry); + return new BeginGetCredentialResponse( + new ParceledListSlice<>(mCredentialEntries), + new ParceledListSlice<>(mAuthenticationEntries), + new ParceledListSlice<>(mActions), + mRemoteCredentialEntry); } } } diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java index d2a4a660452c..fb2f4ad2abe6 100644 --- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java +++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java @@ -42,7 +42,6 @@ import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.util.AttributeSet; -import android.util.Log; import android.util.Slog; import android.util.Xml; @@ -54,7 +53,6 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -181,7 +179,8 @@ public final class CredentialProviderInfoFactory { if (disableSystemAppVerificationForTests) { Bundle metadata = serviceInfo.metaData; if (metadata == null) { - Slog.e(TAG, "isValidSystemProvider - metadata is null: " + serviceInfo); + Slog.w(TAG, "metadata is null while reading " + + "TEST_SYSTEM_PROVIDER_META_DATA_KEY: " + serviceInfo); return false; } return metadata.getBoolean( @@ -200,7 +199,7 @@ public final class CredentialProviderInfoFactory { // 1. Get the metadata for the service. final Bundle metadata = serviceInfo.metaData; if (metadata == null) { - Log.i(TAG, "populateMetadata - metadata is null"); + Slog.w(TAG, "Metadata is null for provider: " + serviceInfo.getComponentName()); return builder; } @@ -209,12 +208,13 @@ public final class CredentialProviderInfoFactory { try { resources = pm.getResourcesForApplication(serviceInfo.applicationInfo); } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Failed to get app resources", e); + Slog.e(TAG, "Failed to get app resources", e); } // 3. Stop if we are missing data. - if (metadata == null || resources == null) { - Log.i(TAG, "populateMetadata - resources is null"); + if (resources == null) { + Slog.w(TAG, "Resources are null for the serviceInfo being processed: " + + serviceInfo.getComponentName()); return builder; } @@ -222,7 +222,7 @@ public final class CredentialProviderInfoFactory { try { builder = extractXmlMetadata(context, builder, serviceInfo, pm, resources); } catch (Exception e) { - Log.e(TAG, "Failed to get XML metadata", e); + Slog.e(TAG, "Failed to get XML metadata", e); } return builder; @@ -259,7 +259,7 @@ public final class CredentialProviderInfoFactory { afsAttributes.getString( R.styleable.CredentialProvider_settingsSubtitle)); } catch (Exception e) { - Log.e(TAG, "Failed to get XML attr", e); + Slog.e(TAG, "Failed to get XML attr", e); } finally { if (afsAttributes != null) { afsAttributes.recycle(); @@ -267,10 +267,10 @@ public final class CredentialProviderInfoFactory { } builder.addCapabilities(parseXmlProviderOuterCapabilities(parser, resources)); } else { - Log.e(TAG, "Meta-data does not start with credential-provider-service tag"); + Slog.w(TAG, "Meta-data does not start with credential-provider-service tag"); } } catch (IOException | XmlPullParserException e) { - Log.e(TAG, "Error parsing credential provider service meta-data", e); + Slog.e(TAG, "Error parsing credential provider service meta-data", e); } return builder; @@ -329,7 +329,7 @@ public final class CredentialProviderInfoFactory { return si; } } catch (RemoteException e) { - Slog.v(TAG, e.getMessage()); + Slog.e(TAG, "Unable to get serviceInfo", e); } throw new PackageManager.NameNotFoundException(serviceComponent.toString()); } @@ -377,10 +377,8 @@ public final class CredentialProviderInfoFactory { } services.add(serviceInfo); - } catch (SecurityException e) { - Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); - } catch (PackageManager.NameNotFoundException e) { - Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); + } catch (SecurityException | PackageManager.NameNotFoundException e) { + Slog.e(TAG, "Error getting info for " + serviceInfo, e); } } return services; @@ -432,7 +430,7 @@ public final class CredentialProviderInfoFactory { return pp; } catch (SecurityException e) { // If the current user is not enrolled in DPM then this can throw a security error. - Log.e(TAG, "Failed to get device policy: " + e); + Slog.e(TAG, "Failed to get device policy: " + e); } return null; @@ -593,7 +591,7 @@ public final class CredentialProviderInfoFactory { for (ResolveInfo resolveInfo : resolveInfos) { final ServiceInfo serviceInfo = resolveInfo.serviceInfo; if (serviceInfo == null) { - Log.i(TAG, "No serviceInfo found for resolveInfo so skipping this provider"); + Slog.d(TAG, "No serviceInfo found for resolveInfo, so skipping provider"); continue; } @@ -608,10 +606,8 @@ public final class CredentialProviderInfoFactory { if (!cpi.isSystemProvider()) { services.add(cpi); } - } catch (SecurityException e) { - Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); } catch (Exception e) { - Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e); + Slog.e(TAG, "Error getting info for " + serviceInfo, e); } } return services; diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java index b97760656059..53a5fd5c634d 100644 --- a/core/java/android/service/credentials/CredentialProviderService.java +++ b/core/java/android/service/credentials/CredentialProviderService.java @@ -226,17 +226,23 @@ public abstract class CredentialProviderService extends Service { if (SERVICE_INTERFACE.equals(intent.getAction())) { return mInterface.asBinder(); } - Log.i(TAG, "Failed to bind with intent: " + intent); + Log.d(TAG, "Failed to bind with intent: " + intent); return null; } private final ICredentialProviderService mInterface = new ICredentialProviderService.Stub() { - public ICancellationSignal onBeginGetCredential(BeginGetCredentialRequest request, + @Override + public void onBeginGetCredential(BeginGetCredentialRequest request, IBeginGetCredentialCallback callback) { Objects.requireNonNull(request); Objects.requireNonNull(callback); ICancellationSignal transport = CancellationSignal.createTransport(); + try { + callback.onCancellable(transport); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } mHandler.sendMessage(obtainMessage( CredentialProviderService::onBeginGetCredential, @@ -267,7 +273,6 @@ public abstract class CredentialProviderService extends Service { } } )); - return transport; } private void enforceRemoteEntryPermission() { String permission = @@ -280,12 +285,17 @@ public abstract class CredentialProviderService extends Service { } @Override - public ICancellationSignal onBeginCreateCredential(BeginCreateCredentialRequest request, + public void onBeginCreateCredential(BeginCreateCredentialRequest request, IBeginCreateCredentialCallback callback) { Objects.requireNonNull(request); Objects.requireNonNull(callback); ICancellationSignal transport = CancellationSignal.createTransport(); + try { + callback.onCancellable(transport); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } mHandler.sendMessage(obtainMessage( CredentialProviderService::onBeginCreateCredential, @@ -316,16 +326,20 @@ public abstract class CredentialProviderService extends Service { } } )); - return transport; } @Override - public ICancellationSignal onClearCredentialState(ClearCredentialStateRequest request, + public void onClearCredentialState(ClearCredentialStateRequest request, IClearCredentialStateCallback callback) { Objects.requireNonNull(request); Objects.requireNonNull(callback); ICancellationSignal transport = CancellationSignal.createTransport(); + try { + callback.onCancellable(transport); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } mHandler.sendMessage(obtainMessage( CredentialProviderService::onClearCredentialState, @@ -350,7 +364,6 @@ public abstract class CredentialProviderService extends Service { } } )); - return transport; } }; diff --git a/core/java/android/service/credentials/IBeginCreateCredentialCallback.aidl b/core/java/android/service/credentials/IBeginCreateCredentialCallback.aidl index ab855ef0b13f..4b73cbc77ee3 100644 --- a/core/java/android/service/credentials/IBeginCreateCredentialCallback.aidl +++ b/core/java/android/service/credentials/IBeginCreateCredentialCallback.aidl @@ -1,6 +1,7 @@ package android.service.credentials; import android.service.credentials.BeginCreateCredentialResponse; +import android.os.ICancellationSignal; /** * Interface from the system to a credential provider service. @@ -10,4 +11,5 @@ import android.service.credentials.BeginCreateCredentialResponse; oneway interface IBeginCreateCredentialCallback { void onSuccess(in BeginCreateCredentialResponse request); void onFailure(String errorType, in CharSequence message); + void onCancellable(in ICancellationSignal cancellation); }
\ No newline at end of file diff --git a/core/java/android/service/credentials/IBeginGetCredentialCallback.aidl b/core/java/android/service/credentials/IBeginGetCredentialCallback.aidl index 73e98707d15e..0710fb3a97ea 100644 --- a/core/java/android/service/credentials/IBeginGetCredentialCallback.aidl +++ b/core/java/android/service/credentials/IBeginGetCredentialCallback.aidl @@ -1,6 +1,8 @@ package android.service.credentials; import android.service.credentials.BeginGetCredentialResponse; +import android.os.ICancellationSignal; + /** * Interface from the system to a credential provider service. @@ -10,4 +12,5 @@ import android.service.credentials.BeginGetCredentialResponse; oneway interface IBeginGetCredentialCallback { void onSuccess(in BeginGetCredentialResponse response); void onFailure(String errorType, in CharSequence message); + void onCancellable(in ICancellationSignal cancellation); }
\ No newline at end of file diff --git a/core/java/android/service/credentials/IClearCredentialStateCallback.aidl b/core/java/android/service/credentials/IClearCredentialStateCallback.aidl index ec805d0a1799..57513186fe3d 100644 --- a/core/java/android/service/credentials/IClearCredentialStateCallback.aidl +++ b/core/java/android/service/credentials/IClearCredentialStateCallback.aidl @@ -16,12 +16,16 @@ package android.service.credentials; +import android.os.ICancellationSignal; + + /** * Callback for onClearCredentialState request. * * @hide */ -interface IClearCredentialStateCallback { - oneway void onSuccess(); - oneway void onFailure(String errorType, CharSequence message); +oneway interface IClearCredentialStateCallback { + void onSuccess(); + void onFailure(String errorType, CharSequence message); + void onCancellable(in ICancellationSignal cancellation); }
\ No newline at end of file diff --git a/core/java/android/service/credentials/ICredentialProviderService.aidl b/core/java/android/service/credentials/ICredentialProviderService.aidl index 626dd7858626..ebb4a4ef6cca 100644 --- a/core/java/android/service/credentials/ICredentialProviderService.aidl +++ b/core/java/android/service/credentials/ICredentialProviderService.aidl @@ -30,8 +30,8 @@ import android.os.ICancellationSignal; * * @hide */ -interface ICredentialProviderService { - ICancellationSignal onBeginGetCredential(in BeginGetCredentialRequest request, in IBeginGetCredentialCallback callback); - ICancellationSignal onBeginCreateCredential(in BeginCreateCredentialRequest request, in IBeginCreateCredentialCallback callback); - ICancellationSignal onClearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback); +oneway interface ICredentialProviderService { + void onBeginGetCredential(in BeginGetCredentialRequest request, in IBeginGetCredentialCallback callback); + void onBeginCreateCredential(in BeginCreateCredentialRequest request, in IBeginCreateCredentialCallback callback); + void onClearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback); } diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java index dd5373ff8c38..82571db469be 100644 --- a/core/java/android/service/dreams/DreamManagerInternal.java +++ b/core/java/android/service/dreams/DreamManagerInternal.java @@ -80,10 +80,10 @@ public abstract class DreamManagerInternal { */ public interface DreamManagerStateListener { /** - * Called when keep dreaming when undocked has changed. + * Called when keep dreaming when plug has changed. * * @param keepDreaming True if the current dream should continue when undocking. */ - void onKeepDreamingWhenUndockedChanged(boolean keepDreaming); + void onKeepDreamingWhenUnpluggingChanged(boolean keepDreaming); } } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 402da28b3c5c..828c062d955d 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -45,7 +45,6 @@ import android.provider.Settings.Global; import android.text.TextUtils; import android.text.format.DateFormat; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.PluralsMessageFormatter; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -59,7 +58,6 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -310,86 +308,6 @@ public class ZenModeConfig implements Parcelable { return buffer.toString(); } - public Diff diff(ZenModeConfig to) { - final Diff d = new Diff(); - if (to == null) { - return d.addLine("config", "delete"); - } - if (user != to.user) { - d.addLine("user", user, to.user); - } - if (allowAlarms != to.allowAlarms) { - d.addLine("allowAlarms", allowAlarms, to.allowAlarms); - } - if (allowMedia != to.allowMedia) { - d.addLine("allowMedia", allowMedia, to.allowMedia); - } - if (allowSystem != to.allowSystem) { - d.addLine("allowSystem", allowSystem, to.allowSystem); - } - if (allowCalls != to.allowCalls) { - d.addLine("allowCalls", allowCalls, to.allowCalls); - } - if (allowReminders != to.allowReminders) { - d.addLine("allowReminders", allowReminders, to.allowReminders); - } - if (allowEvents != to.allowEvents) { - d.addLine("allowEvents", allowEvents, to.allowEvents); - } - if (allowRepeatCallers != to.allowRepeatCallers) { - d.addLine("allowRepeatCallers", allowRepeatCallers, to.allowRepeatCallers); - } - if (allowMessages != to.allowMessages) { - d.addLine("allowMessages", allowMessages, to.allowMessages); - } - if (allowCallsFrom != to.allowCallsFrom) { - d.addLine("allowCallsFrom", allowCallsFrom, to.allowCallsFrom); - } - if (allowMessagesFrom != to.allowMessagesFrom) { - d.addLine("allowMessagesFrom", allowMessagesFrom, to.allowMessagesFrom); - } - if (suppressedVisualEffects != to.suppressedVisualEffects) { - d.addLine("suppressedVisualEffects", suppressedVisualEffects, - to.suppressedVisualEffects); - } - final ArraySet<String> allRules = new ArraySet<>(); - addKeys(allRules, automaticRules); - addKeys(allRules, to.automaticRules); - final int N = allRules.size(); - for (int i = 0; i < N; i++) { - final String rule = allRules.valueAt(i); - final ZenRule fromRule = automaticRules != null ? automaticRules.get(rule) : null; - final ZenRule toRule = to.automaticRules != null ? to.automaticRules.get(rule) : null; - ZenRule.appendDiff(d, "automaticRule[" + rule + "]", fromRule, toRule); - } - ZenRule.appendDiff(d, "manualRule", manualRule, to.manualRule); - - if (areChannelsBypassingDnd != to.areChannelsBypassingDnd) { - d.addLine("areChannelsBypassingDnd", areChannelsBypassingDnd, - to.areChannelsBypassingDnd); - } - return d; - } - - public static Diff diff(ZenModeConfig from, ZenModeConfig to) { - if (from == null) { - final Diff d = new Diff(); - if (to != null) { - d.addLine("config", "insert"); - } - return d; - } - return from.diff(to); - } - - private static <T> void addKeys(ArraySet<T> set, ArrayMap<T, ?> map) { - if (map != null) { - for (int i = 0; i < map.size(); i++) { - set.add(map.keyAt(i)); - } - } - } - public boolean isValid() { if (!isValidManualRule(manualRule)) return false; final int N = automaticRules.size(); @@ -1922,66 +1840,6 @@ public class ZenModeConfig implements Parcelable { proto.end(token); } - private static void appendDiff(Diff d, String item, ZenRule from, ZenRule to) { - if (d == null) return; - if (from == null) { - if (to != null) { - d.addLine(item, "insert"); - } - return; - } - from.appendDiff(d, item, to); - } - - private void appendDiff(Diff d, String item, ZenRule to) { - if (to == null) { - d.addLine(item, "delete"); - return; - } - if (enabled != to.enabled) { - d.addLine(item, "enabled", enabled, to.enabled); - } - if (snoozing != to.snoozing) { - d.addLine(item, "snoozing", snoozing, to.snoozing); - } - if (!Objects.equals(name, to.name)) { - d.addLine(item, "name", name, to.name); - } - if (zenMode != to.zenMode) { - d.addLine(item, "zenMode", zenMode, to.zenMode); - } - if (!Objects.equals(conditionId, to.conditionId)) { - d.addLine(item, "conditionId", conditionId, to.conditionId); - } - if (!Objects.equals(condition, to.condition)) { - d.addLine(item, "condition", condition, to.condition); - } - if (!Objects.equals(component, to.component)) { - d.addLine(item, "component", component, to.component); - } - if (!Objects.equals(configurationActivity, to.configurationActivity)) { - d.addLine(item, "configActivity", configurationActivity, to.configurationActivity); - } - if (!Objects.equals(id, to.id)) { - d.addLine(item, "id", id, to.id); - } - if (creationTime != to.creationTime) { - d.addLine(item, "creationTime", creationTime, to.creationTime); - } - if (!Objects.equals(enabler, to.enabler)) { - d.addLine(item, "enabler", enabler, to.enabler); - } - if (!Objects.equals(zenPolicy, to.zenPolicy)) { - d.addLine(item, "zenPolicy", zenPolicy, to.zenPolicy); - } - if (modified != to.modified) { - d.addLine(item, "modified", modified, to.modified); - } - if (!Objects.equals(pkg, to.pkg)) { - d.addLine(item, "pkg", pkg, to.pkg); - } - } - @Override public boolean equals(@Nullable Object o) { if (!(o instanceof ZenRule)) return false; @@ -2040,40 +1898,6 @@ public class ZenModeConfig implements Parcelable { }; } - public static class Diff { - private final ArrayList<String> lines = new ArrayList<>(); - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("Diff["); - final int N = lines.size(); - for (int i = 0; i < N; i++) { - if (i > 0) { - sb.append(",\n"); - } - sb.append(lines.get(i)); - } - return sb.append(']').toString(); - } - - private Diff addLine(String item, String action) { - lines.add(item + ":" + action); - return this; - } - - public Diff addLine(String item, String subitem, Object from, Object to) { - return addLine(item + "." + subitem, from, to); - } - - public Diff addLine(String item, Object from, Object to) { - return addLine(item, from + "->" + to); - } - - public boolean isEmpty() { - return lines.isEmpty(); - } - } - /** * Determines whether dnd behavior should mute all ringer-controlled sounds * This includes notification, ringer and system sounds diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java new file mode 100644 index 000000000000..c7b89eb284b6 --- /dev/null +++ b/core/java/android/service/notification/ZenModeDiff.java @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.notification; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.util.ArrayMap; +import android.util.ArraySet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; +import java.util.Set; + +/** + * ZenModeDiff is a utility class meant to encapsulate the diff between ZenModeConfigs and their + * subcomponents (automatic and manual ZenRules). + * @hide + */ +public class ZenModeDiff { + /** + * Enum representing whether the existence of a config or rule has changed (added or removed, + * or "none" meaning there is no change, which may either mean both null, or there exists a + * diff in fields rather than add/remove). + */ + @IntDef(value = { + NONE, + ADDED, + REMOVED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ExistenceChange{} + + public static final int NONE = 0; + public static final int ADDED = 1; + public static final int REMOVED = 2; + + /** + * Diff class representing an individual field diff. + * @param <T> The type of the field. + */ + public static class FieldDiff<T> { + private final T mFrom; + private final T mTo; + + /** + * Constructor to create a FieldDiff object with the given values. + * @param from from (old) value + * @param to to (new) value + */ + public FieldDiff(@Nullable T from, @Nullable T to) { + mFrom = from; + mTo = to; + } + + /** + * Get the "from" value + */ + public T from() { + return mFrom; + } + + /** + * Get the "to" value + */ + public T to() { + return mTo; + } + + /** + * Get the string representation of this field diff, in the form of "from->to". + */ + @Override + public String toString() { + return mFrom + "->" + mTo; + } + + /** + * Returns whether this represents an actual diff. + */ + public boolean hasDiff() { + // note that Objects.equals handles null values gracefully. + return !Objects.equals(mFrom, mTo); + } + } + + /** + * Base diff class that contains info about whether something was added, and a set of named + * fields that changed. + * Extend for diffs of specific types of objects. + */ + private abstract static class BaseDiff { + // Whether the diff was added or removed + @ExistenceChange private int mExists = NONE; + + // Map from field name to diffs for any standalone fields in the object. + private ArrayMap<String, FieldDiff> mFields = new ArrayMap<>(); + + // Functions for actually diffing objects and string representations have to be implemented + // by subclasses. + + /** + * Return whether this diff represents any changes. + */ + public abstract boolean hasDiff(); + + /** + * Return a string representation of the diff. + */ + public abstract String toString(); + + /** + * Constructor that takes the two objects meant to be compared. This constructor sets + * whether there is an existence change (added or removed). + * @param from previous Object + * @param to new Object + */ + BaseDiff(Object from, Object to) { + if (from == null) { + if (to != null) { + mExists = ADDED; + } + // If both are null, there isn't an existence change; callers/inheritors must handle + // the both null case. + } else if (to == null) { + // in this case, we know that from != null + mExists = REMOVED; + } + + // Subclasses should implement the actual diffing functionality in their own + // constructors. + } + + /** + * Add a diff for a specific field to the map. + * @param name field name + * @param diff FieldDiff object representing the diff + */ + final void addField(String name, FieldDiff diff) { + mFields.put(name, diff); + } + + /** + * Returns whether this diff represents a config being newly added. + */ + public final boolean wasAdded() { + return mExists == ADDED; + } + + /** + * Returns whether this diff represents a config being removed. + */ + public final boolean wasRemoved() { + return mExists == REMOVED; + } + + /** + * Returns whether this diff represents an object being either added or removed. + */ + public final boolean hasExistenceChange() { + return mExists != NONE; + } + + /** + * Returns whether there are any individual field diffs. + */ + public final boolean hasFieldDiffs() { + return mFields.size() > 0; + } + + /** + * Returns the diff for the specific named field if it exists + */ + public final FieldDiff getDiffForField(String name) { + return mFields.getOrDefault(name, null); + } + + /** + * Get the set of all field names with some diff. + */ + public final Set<String> fieldNamesWithDiff() { + return mFields.keySet(); + } + } + + /** + * Diff class representing a diff between two ZenModeConfigs. + */ + public static class ConfigDiff extends BaseDiff { + // Rules. Automatic rule map is keyed by the rule name. + private final ArrayMap<String, RuleDiff> mAutomaticRulesDiff = new ArrayMap<>(); + private RuleDiff mManualRuleDiff; + + // Helpers for string generation + private static final String ALLOW_CALLS_FROM_FIELD = "allowCallsFrom"; + private static final String ALLOW_MESSAGES_FROM_FIELD = "allowMessagesFrom"; + private static final String ALLOW_CONVERSATIONS_FROM_FIELD = "allowConversationsFrom"; + private static final Set<String> PEOPLE_TYPE_FIELDS = + Set.of(ALLOW_CALLS_FROM_FIELD, ALLOW_MESSAGES_FROM_FIELD); + + /** + * Create a diff that contains diffs between the "from" and "to" ZenModeConfigs. + * + * @param from previous ZenModeConfig + * @param to new ZenModeConfig + */ + public ConfigDiff(ZenModeConfig from, ZenModeConfig to) { + super(from, to); + // If both are null skip + if (from == null && to == null) { + return; + } + if (hasExistenceChange()) { + // either added or removed; return here. otherwise (they're not both null) there's + // field diffs. + return; + } + + // Now we compare all the fields, knowing there's a diff and that neither is null + if (from.user != to.user) { + addField("user", new FieldDiff<>(from.user, to.user)); + } + if (from.allowAlarms != to.allowAlarms) { + addField("allowAlarms", new FieldDiff<>(from.allowAlarms, to.allowAlarms)); + } + if (from.allowMedia != to.allowMedia) { + addField("allowMedia", new FieldDiff<>(from.allowMedia, to.allowMedia)); + } + if (from.allowSystem != to.allowSystem) { + addField("allowSystem", new FieldDiff<>(from.allowSystem, to.allowSystem)); + } + if (from.allowCalls != to.allowCalls) { + addField("allowCalls", new FieldDiff<>(from.allowCalls, to.allowCalls)); + } + if (from.allowReminders != to.allowReminders) { + addField("allowReminders", + new FieldDiff<>(from.allowReminders, to.allowReminders)); + } + if (from.allowEvents != to.allowEvents) { + addField("allowEvents", new FieldDiff<>(from.allowEvents, to.allowEvents)); + } + if (from.allowRepeatCallers != to.allowRepeatCallers) { + addField("allowRepeatCallers", + new FieldDiff<>(from.allowRepeatCallers, to.allowRepeatCallers)); + } + if (from.allowMessages != to.allowMessages) { + addField("allowMessages", + new FieldDiff<>(from.allowMessages, to.allowMessages)); + } + if (from.allowConversations != to.allowConversations) { + addField("allowConversations", + new FieldDiff<>(from.allowConversations, to.allowConversations)); + } + if (from.allowCallsFrom != to.allowCallsFrom) { + addField("allowCallsFrom", + new FieldDiff<>(from.allowCallsFrom, to.allowCallsFrom)); + } + if (from.allowMessagesFrom != to.allowMessagesFrom) { + addField("allowMessagesFrom", + new FieldDiff<>(from.allowMessagesFrom, to.allowMessagesFrom)); + } + if (from.allowConversationsFrom != to.allowConversationsFrom) { + addField("allowConversationsFrom", + new FieldDiff<>(from.allowConversationsFrom, to.allowConversationsFrom)); + } + if (from.suppressedVisualEffects != to.suppressedVisualEffects) { + addField("suppressedVisualEffects", + new FieldDiff<>(from.suppressedVisualEffects, to.suppressedVisualEffects)); + } + if (from.areChannelsBypassingDnd != to.areChannelsBypassingDnd) { + addField("areChannelsBypassingDnd", + new FieldDiff<>(from.areChannelsBypassingDnd, to.areChannelsBypassingDnd)); + } + + // Compare automatic and manual rules + final ArraySet<String> allRules = new ArraySet<>(); + addKeys(allRules, from.automaticRules); + addKeys(allRules, to.automaticRules); + final int num = allRules.size(); + for (int i = 0; i < num; i++) { + final String rule = allRules.valueAt(i); + final ZenModeConfig.ZenRule + fromRule = from.automaticRules != null ? from.automaticRules.get(rule) + : null; + final ZenModeConfig.ZenRule + toRule = to.automaticRules != null ? to.automaticRules.get(rule) : null; + RuleDiff ruleDiff = new RuleDiff(fromRule, toRule); + if (ruleDiff.hasDiff()) { + mAutomaticRulesDiff.put(rule, ruleDiff); + } + } + // If there's no diff this may turn out to be null, but that's also fine + RuleDiff manualRuleDiff = new RuleDiff(from.manualRule, to.manualRule); + if (manualRuleDiff.hasDiff()) { + mManualRuleDiff = manualRuleDiff; + } + } + + private static <T> void addKeys(ArraySet<T> set, ArrayMap<T, ?> map) { + if (map != null) { + for (int i = 0; i < map.size(); i++) { + set.add(map.keyAt(i)); + } + } + } + + /** + * Returns whether this diff object contains any diffs in any field. + */ + @Override + public boolean hasDiff() { + return hasExistenceChange() + || hasFieldDiffs() + || mManualRuleDiff != null + || mAutomaticRulesDiff.size() > 0; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Diff["); + if (!hasDiff()) { + sb.append("no changes"); + } + + // If added or deleted, then that's just the end of it + if (hasExistenceChange()) { + if (wasAdded()) { + sb.append("added"); + } else if (wasRemoved()) { + sb.append("removed"); + } + } + + // Handle top-level field change + boolean first = true; + for (String key : fieldNamesWithDiff()) { + FieldDiff diff = getDiffForField(key); + if (diff == null) { + // this shouldn't happen, but + continue; + } + if (first) { + first = false; + } else { + sb.append(",\n"); + } + + // Some special handling for people- and conversation-type fields for readability + if (PEOPLE_TYPE_FIELDS.contains(key)) { + sb.append(key); + sb.append(":"); + sb.append(ZenModeConfig.sourceToString((int) diff.from())); + sb.append("->"); + sb.append(ZenModeConfig.sourceToString((int) diff.to())); + } else if (key.equals(ALLOW_CONVERSATIONS_FROM_FIELD)) { + sb.append(key); + sb.append(":"); + sb.append(ZenPolicy.conversationTypeToString((int) diff.from())); + sb.append("->"); + sb.append(ZenPolicy.conversationTypeToString((int) diff.to())); + } else { + sb.append(key); + sb.append(":"); + sb.append(diff); + } + } + + // manual rule + if (mManualRuleDiff != null && mManualRuleDiff.hasDiff()) { + if (first) { + first = false; + } else { + sb.append(",\n"); + } + sb.append("manualRule:"); + sb.append(mManualRuleDiff); + } + + // automatic rules + for (String rule : mAutomaticRulesDiff.keySet()) { + RuleDiff diff = mAutomaticRulesDiff.get(rule); + if (diff != null && diff.hasDiff()) { + if (first) { + first = false; + } else { + sb.append(",\n"); + } + sb.append("automaticRule["); + sb.append(rule); + sb.append("]:"); + sb.append(diff); + } + } + + return sb.append(']').toString(); + } + + /** + * Get the diff in manual rule, if it exists. + */ + public RuleDiff getManualRuleDiff() { + return mManualRuleDiff; + } + + /** + * Get the full map of automatic rule diffs, or null if there are no diffs. + */ + public ArrayMap<String, RuleDiff> getAllAutomaticRuleDiffs() { + return (mAutomaticRulesDiff.size() > 0) ? mAutomaticRulesDiff : null; + } + } + + /** + * Diff class representing a change between two ZenRules. + */ + public static class RuleDiff extends BaseDiff { + /** + * Create a RuleDiff representing the difference between two ZenRule objects. + * @param from previous ZenRule + * @param to new ZenRule + * @return The diff between the two given ZenRules + */ + public RuleDiff(ZenModeConfig.ZenRule from, ZenModeConfig.ZenRule to) { + super(from, to); + // Short-circuit the both-null case + if (from == null && to == null) { + return; + } + // Return if the diff was added or removed + if (hasExistenceChange()) { + return; + } + + if (from.enabled != to.enabled) { + addField("enabled", new FieldDiff<>(from.enabled, to.enabled)); + } + if (from.snoozing != to.snoozing) { + addField("snoozing", new FieldDiff<>(from.snoozing, to.snoozing)); + } + if (!Objects.equals(from.name, to.name)) { + addField("name", new FieldDiff<>(from.name, to.name)); + } + if (from.zenMode != to.zenMode) { + addField("zenMode", new FieldDiff<>(from.zenMode, to.zenMode)); + } + if (!Objects.equals(from.conditionId, to.conditionId)) { + addField("conditionId", new FieldDiff<>(from.conditionId, to.conditionId)); + } + if (!Objects.equals(from.condition, to.condition)) { + addField("condition", new FieldDiff<>(from.condition, to.condition)); + } + if (!Objects.equals(from.component, to.component)) { + addField("component", new FieldDiff<>(from.component, to.component)); + } + if (!Objects.equals(from.configurationActivity, to.configurationActivity)) { + addField("configurationActivity", new FieldDiff<>( + from.configurationActivity, to.configurationActivity)); + } + if (!Objects.equals(from.id, to.id)) { + addField("id", new FieldDiff<>(from.id, to.id)); + } + if (from.creationTime != to.creationTime) { + addField("creationTime", + new FieldDiff<>(from.creationTime, to.creationTime)); + } + if (!Objects.equals(from.enabler, to.enabler)) { + addField("enabler", new FieldDiff<>(from.enabler, to.enabler)); + } + if (!Objects.equals(from.zenPolicy, to.zenPolicy)) { + addField("zenPolicy", new FieldDiff<>(from.zenPolicy, to.zenPolicy)); + } + if (from.modified != to.modified) { + addField("modified", new FieldDiff<>(from.modified, to.modified)); + } + if (!Objects.equals(from.pkg, to.pkg)) { + addField("pkg", new FieldDiff<>(from.pkg, to.pkg)); + } + } + + /** + * Returns whether this object represents an actual diff. + */ + @Override + public boolean hasDiff() { + return hasExistenceChange() || hasFieldDiffs(); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ZenRuleDiff{"); + // If there's no diff, probably we haven't actually let this object continue existing + // but might as well handle this case. + if (!hasDiff()) { + sb.append("no changes"); + } + + // If added or deleted, then that's just the end of it + if (hasExistenceChange()) { + if (wasAdded()) { + sb.append("added"); + } else if (wasRemoved()) { + sb.append("removed"); + } + } + + // Go through all of the individual fields + boolean first = true; + for (String key : fieldNamesWithDiff()) { + FieldDiff diff = getDiffForField(key); + if (diff == null) { + // this shouldn't happen, but + continue; + } + if (first) { + first = false; + } else { + sb.append(", "); + } + + sb.append(key); + sb.append(":"); + sb.append(diff); + } + + return sb.append("}").toString(); + } + } +} diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 8688a18880b7..24c96eae03cb 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -1573,16 +1573,6 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { } @Override - public void onError(int status) { - Slog.i(TAG, "onError: " + status); - // TODO(b/271534248): This is a workaround before the sound trigger uses the new error - // method. - Message.obtain(mHandler, MSG_DETECTION_SOUND_TRIGGER_FAILURE, - new SoundTriggerFailure(SoundTriggerFailure.ERROR_CODE_UNKNOWN, - "Sound trigger error")).sendToTarget(); - } - - @Override public void onHotwordDetectionServiceFailure( HotwordDetectionServiceFailure hotwordDetectionServiceFailure) { Slog.v(TAG, "onHotwordDetectionServiceFailure: " + hotwordDetectionServiceFailure); @@ -1605,6 +1595,12 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { } @Override + public void onSoundTriggerFailure(SoundTriggerFailure soundTriggerFailure) { + Message.obtain(mHandler, MSG_DETECTION_SOUND_TRIGGER_FAILURE, + Objects.requireNonNull(soundTriggerFailure)).sendToTarget(); + } + + @Override public void onUnknownFailure(String errorMessage) throws RemoteException { Slog.v(TAG, "onUnknownFailure: " + errorMessage); Message.obtain(mHandler, MSG_DETECTION_UNKNOWN_FAILURE, diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java index eac7aee43859..7ab4fafcf312 100644 --- a/core/java/android/service/voice/SoftwareHotwordDetector.java +++ b/core/java/android/service/voice/SoftwareHotwordDetector.java @@ -234,14 +234,6 @@ class SoftwareHotwordDetector extends AbstractDetector { } @Override - public void onError(int status) throws RemoteException { - if (DEBUG) { - Slog.i(TAG, "Ignored #onError (" + status + ") event"); - } - // TODO: Check if we still need to implement this method with DetectorFailure mechanism. - } - - @Override public void onHotwordDetectionServiceFailure( HotwordDetectionServiceFailure hotwordDetectionServiceFailure) throws RemoteException { @@ -265,6 +257,13 @@ class SoftwareHotwordDetector extends AbstractDetector { } @Override + public void onSoundTriggerFailure(SoundTriggerFailure onSoundTriggerFailure) + throws RemoteException { + // It should never be called here. + Slog.wtf(TAG, "Unexpected STFailure in software detector: " + onSoundTriggerFailure); + } + + @Override public void onUnknownFailure(String errorMessage) throws RemoteException { Slog.v(TAG, "onUnknownFailure: " + errorMessage); Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { diff --git a/core/java/android/service/voice/SoundTriggerFailure.java b/core/java/android/service/voice/SoundTriggerFailure.java index 5560800a373f..2ce5e5da4724 100644 --- a/core/java/android/service/voice/SoundTriggerFailure.java +++ b/core/java/android/service/voice/SoundTriggerFailure.java @@ -73,18 +73,28 @@ public final class SoundTriggerFailure implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface SoundTriggerErrorCode {} - private int mErrorCode = ERROR_CODE_UNKNOWN; - private String mErrorMessage = "Unknown"; + private final int mErrorCode; + private final String mErrorMessage; /** * @hide */ @TestApi - public SoundTriggerFailure(int errorCode, @NonNull String errorMessage) { + public SoundTriggerFailure(@SoundTriggerErrorCode int errorCode, + @NonNull String errorMessage) { if (TextUtils.isEmpty(errorMessage)) { throw new IllegalArgumentException("errorMessage is empty or null."); } - mErrorCode = errorCode; + switch (errorCode) { + case ERROR_CODE_UNKNOWN: + case ERROR_CODE_MODULE_DIED: + case ERROR_CODE_RECOGNITION_RESUME_FAILED: + case ERROR_CODE_UNEXPECTED_PREEMPTION: + mErrorCode = errorCode; + break; + default: + throw new IllegalArgumentException("Invalid ErrorCode: " + errorCode); + } mErrorMessage = errorMessage; } @@ -110,13 +120,14 @@ public final class SoundTriggerFailure implements Parcelable { @FailureSuggestedAction.FailureSuggestedActionDef public int getSuggestedAction() { switch (mErrorCode) { + case ERROR_CODE_UNKNOWN: case ERROR_CODE_MODULE_DIED: case ERROR_CODE_UNEXPECTED_PREEMPTION: return FailureSuggestedAction.RECREATE_DETECTOR; case ERROR_CODE_RECOGNITION_RESUME_FAILED: return FailureSuggestedAction.RESTART_RECOGNITION; default: - return FailureSuggestedAction.NONE; + throw new AssertionError("Unexpected error code"); } } diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java index b4f5ff1046ae..93b7964705ba 100644 --- a/core/java/android/service/voice/VisualQueryDetector.java +++ b/core/java/android/service/voice/VisualQueryDetector.java @@ -391,12 +391,6 @@ public class VisualQueryDetector { } @Override - public void onError(int status) throws RemoteException { - Slog.v(TAG, "Initialization Error: (" + status + ")"); - // Do nothing - } - - @Override public void onHotwordDetectionServiceFailure( HotwordDetectionServiceFailure hotwordDetectionServiceFailure) throws RemoteException { @@ -420,6 +414,11 @@ public class VisualQueryDetector { } @Override + public void onSoundTriggerFailure(SoundTriggerFailure soundTriggerFailure) { + Slog.wtf(TAG, "Unexpected STFailure in VisualQueryDetector" + soundTriggerFailure); + } + + @Override public void onUnknownFailure(String errorMessage) throws RemoteException { Slog.v(TAG, "onUnknownFailure: " + errorMessage); Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index fcc64b088def..68cce4ae274a 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -50,6 +50,7 @@ import android.provider.Settings; import android.util.ArraySet; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceActionCheckCallback; import com.android.internal.app.IVoiceInteractionManagerService; @@ -200,6 +201,9 @@ public class VoiceInteractionService extends Service { private final Set<HotwordDetector> mActiveDetectors = new ArraySet<>(); + // True if any of the createAOHD methods should use the test ST module. + @GuardedBy("mLock") + private boolean mTestModuleForAlwaysOnHotwordDetectorEnabled = false; private void onDetectorRemoteException(@NonNull IBinder token, int detectorType) { Log.d(TAG, "onDetectorRemoteException for " + HotwordDetector.detectorTypeToString( @@ -512,14 +516,14 @@ public class VoiceInteractionService extends Service { Objects.requireNonNull(callback); return createAlwaysOnHotwordDetectorInternal(keyphrase, locale, /* supportHotwordDetectionService= */ false, /* options= */ null, - /* sharedMemory= */ null, /* moduleProperties */ null, executor, callback); + /* sharedMemory= */ null, /* moduleProperties= */ null, executor, callback); } /** * Same as {@link createAlwaysOnHotwordDetector(String, Locale, Executor, * AlwaysOnHotwordDetector.Callback)}, but allow explicit selection of the underlying ST * module to attach to. - * Use {@link listModuleProperties} to get available modules to attach to. + * Use {@link #listModuleProperties()} to get available modules to attach to. * @hide */ @TestApi @@ -645,14 +649,14 @@ public class VoiceInteractionService extends Service { Objects.requireNonNull(callback); return createAlwaysOnHotwordDetectorInternal(keyphrase, locale, /* supportHotwordDetectionService= */ true, options, sharedMemory, - /* moduleProperties */ null, executor, callback); + /* moduleProperties= */ null, executor, callback); } /** * Same as {@link createAlwaysOnHotwordDetector(String, Locale, * PersistableBundle, SharedMemory, Executor, AlwaysOnHotwordDetector.Callback)}, * but allow explicit selection of the underlying ST module to attach to. - * Use {@link listModuleProperties} to get available modules to attach to. + * Use {@link #listModuleProperties()} to get available modules to attach to. * @hide */ @TestApi @@ -717,6 +721,10 @@ public class VoiceInteractionService extends Service { try { dspDetector.registerOnDestroyListener(this::onHotwordDetectorDestroyed); + // Check if we are currently overridden, and should use the test module. + if (mTestModuleForAlwaysOnHotwordDetectorEnabled) { + moduleProperties = getTestModuleProperties(); + } // If moduleProperties is null, the default STModule is used. dspDetector.initialize(options, sharedMemory, moduleProperties); } catch (Exception e) { @@ -990,6 +998,44 @@ public class VoiceInteractionService extends Service { return mKeyphraseEnrollmentInfo; } + + /** + * Configure {@link createAlwaysOnHotwordDetector(String, Locale, + * SoundTrigger.ModuleProperties, Executor, AlwaysOnHotwordDetector.Callback)} + * and similar overloads to utilize the test SoundTrigger module instead of the + * actual DSP module. + * @param isEnabled - {@code true} if subsequently created {@link AlwaysOnHotwordDetector} + * objects should attach to a test module. {@code false} if subsequently created + * {@link AlwaysOnHotwordDetector} should attach to the actual DSP module. + * @hide + */ + @TestApi + public final void setTestModuleForAlwaysOnHotwordDetectorEnabled(boolean isEnabled) { + synchronized (mLock) { + mTestModuleForAlwaysOnHotwordDetectorEnabled = isEnabled; + } + } + + /** + * Get the {@link SoundTrigger.ModuleProperties} representing the fake + * STHAL to attach to via {@link createAlwaysOnHotwordDetector(String, Locale, + * SoundTrigger.ModuleProperties, Executor, AlwaysOnHotwordDetector.Callback)} and + * similar overloads for test purposes. + * @return ModuleProperties to use for test purposes. + */ + private final @NonNull SoundTrigger.ModuleProperties getTestModuleProperties() { + var moduleProps = listModuleProperties() + .stream() + .filter((SoundTrigger.ModuleProperties prop) + -> prop.getSupportedModelArch().equals(SoundTrigger.FAKE_HAL_ARCH)) + .findFirst() + .orElse(null); + if (moduleProps == null) { + throw new IllegalStateException("Fake ST HAL should always be available"); + } + return moduleProps; + } + /** * Checks if a given keyphrase and locale are supported to create an * {@link AlwaysOnHotwordDetector}. diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl index 4c51be0ab8d9..f1ae22eca873 100644 --- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl +++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl @@ -32,6 +32,8 @@ interface IWallpaperEngine { oneway void setDisplayPadding(in Rect padding); @UnsupportedAppUsage oneway void setVisibility(boolean visible); + oneway void onScreenTurningOn(); + oneway void onScreenTurnedOn(); oneway void setInAmbientMode(boolean inAmbientDisplay, long animationDuration); @UnsupportedAppUsage oneway void dispatchPointer(in MotionEvent event); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 0b947fc18237..77bbeb59927a 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -168,6 +168,7 @@ public abstract class WallpaperService extends Service { private static final int MSG_ZOOM = 10100; private static final int MSG_RESIZE_PREVIEW = 10110; private static final int MSG_REPORT_SHOWN = 10150; + private static final int MSG_UPDATE_SCREEN_TURNING_ON = 10170; private static final int MSG_UPDATE_DIMMING = 10200; private static final int MSG_WALLPAPER_FLAGS_CHANGED = 10210; @@ -213,6 +214,16 @@ public abstract class WallpaperService extends Service { boolean mInitializing = true; boolean mVisible; + /** + * Whether the screen is turning on. + * After the display is powered on, brightness is initially off. It is turned on only after + * all windows have been drawn, and sysui notifies that it's ready (See + * {@link com.android.internal.policy.IKeyguardDrawnCallback}). + * As some wallpapers use visibility as a signal to start animations, this makes sure + * {@link Engine#onVisibilityChanged} is invoked only when the display is both on and + * visible (with brightness on). + */ + private boolean mIsScreenTurningOn; boolean mReportedVisible; boolean mDestroyed; // Set to true after receiving WallpaperManager#COMMAND_FREEZE. It's reset back to false @@ -1018,6 +1029,7 @@ public abstract class WallpaperService extends Service { out.print(" mDestroyed="); out.println(mDestroyed); out.print(prefix); out.print("mVisible="); out.print(mVisible); out.print(" mReportedVisible="); out.println(mReportedVisible); + out.print(" mIsScreenTurningOn="); out.println(mIsScreenTurningOn); out.print(prefix); out.print("mDisplay="); out.println(mDisplay); out.print(prefix); out.print("mCreated="); out.print(mCreated); out.print(" mSurfaceCreated="); out.print(mSurfaceCreated); @@ -1549,6 +1561,13 @@ public abstract class WallpaperService extends Service { } } + void onScreenTurningOnChanged(boolean isScreenTurningOn) { + if (!mDestroyed) { + mIsScreenTurningOn = isScreenTurningOn; + reportVisibility(false); + } + } + void doVisibilityChanged(boolean visible) { if (!mDestroyed) { mVisible = visible; @@ -1565,9 +1584,10 @@ public abstract class WallpaperService extends Service { return; } if (!mDestroyed) { - mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : - mDisplay.getCommittedState(); - boolean visible = mVisible && mDisplayState != Display.STATE_OFF; + mDisplayState = + mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getCommittedState(); + boolean displayVisible = Display.isOnState(mDisplayState) && !mIsScreenTurningOn; + boolean visible = mVisible && displayVisible; if (DEBUG) { Log.v( TAG, @@ -2486,6 +2506,20 @@ public abstract class WallpaperService extends Service { } } + public void updateScreenTurningOn(boolean isScreenTurningOn) { + Message msg = mCaller.obtainMessageBO(MSG_UPDATE_SCREEN_TURNING_ON, isScreenTurningOn, + null); + mCaller.sendMessage(msg); + } + + public void onScreenTurningOn() throws RemoteException { + updateScreenTurningOn(true); + } + + public void onScreenTurnedOn() throws RemoteException { + updateScreenTurningOn(false); + } + @Override public void executeMessage(Message message) { switch (message.what) { @@ -2530,6 +2564,13 @@ public abstract class WallpaperService extends Service { + ": " + message.arg1); mEngine.doVisibilityChanged(message.arg1 != 0); break; + case MSG_UPDATE_SCREEN_TURNING_ON: + if (DEBUG) { + Log.v(TAG, + message.arg1 != 0 ? "Screen turning on" : "Screen turned on"); + } + mEngine.onScreenTurningOnChanged(/* isScreenTurningOn= */ message.arg1 != 0); + break; case MSG_WALLPAPER_OFFSETS: { mEngine.doOffsetsChanged(true); } break; diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index c3295088ef11..d87198a0dc85 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -128,6 +128,12 @@ public class FeatureFlagUtils { */ public static final String SETTINGS_ENABLE_SPA_PHASE2 = "settings_enable_spa_phase2"; + /** + * Enable the SPA metrics writing. + * @hide + */ + public static final String SETTINGS_ENABLE_SPA_METRICS = "settings_enable_spa_metrics"; + /** Flag to enable/disable adb log metrics * @hide */ @@ -226,6 +232,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA_PHASE2, "false"); + DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA_METRICS, "false"); DEFAULT_FLAGS.put(SETTINGS_ADB_METRICS_WRITER, "false"); DEFAULT_FLAGS.put(SETTINGS_SHOW_STYLUS_PREFERENCES, "true"); DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_ENROLLMENT, "false"); diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 9a93e1b9e1f9..d06b0ce1a2d8 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -354,6 +354,15 @@ public class TimeUtils { } /** @hide Just for debugging; not internationalized. */ + public static void formatDuration(long time, long now, StringBuilder sb) { + if (time == 0) { + sb.append("--"); + return; + } + formatDuration(time-now, sb, 0); + } + + /** @hide Just for debugging; not internationalized. */ public static void formatDuration(long time, long now, PrintWriter pw) { if (time == 0) { pw.print("--"); diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index c92b1b8c120d..edc59931d4f8 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -785,12 +785,13 @@ public final class Choreographer { DisplayEventReceiver.VsyncEventData vsyncEventData) { final long startNanos; final long frameIntervalNanos = vsyncEventData.frameInterval; + boolean resynced = false; try { + FrameTimeline timeline = mFrameData.update(frameTimeNanos, vsyncEventData); if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, - "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId); + Trace.traceBegin( + Trace.TRACE_TAG_VIEW, "Choreographer#doFrame " + timeline.mVsyncId); } - mFrameData.update(frameTimeNanos, vsyncEventData); synchronized (mLock) { if (!mFrameScheduled) { traceMessage("Frame not scheduled"); @@ -828,7 +829,9 @@ public final class Choreographer { + " ms in the past."); } } - mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos); + timeline = mFrameData.update( + frameTimeNanos, mDisplayEventReceiver, jitterNanos); + resynced = true; } if (frameTimeNanos < mLastFrameTimeNanos) { @@ -860,6 +863,12 @@ public final class Choreographer { mLastVsyncEventData.copyFrom(vsyncEventData); } + if (resynced && Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + String message = String.format("Choreographer#doFrame - resynced to %d in %.1fms", + timeline.mVsyncId, (timeline.mDeadlineNanos - startNanos) * 0.000001f); + Trace.traceBegin(Trace.TRACE_TAG_VIEW, message); + } + AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); mFrameInfo.markInputHandlingStart(); @@ -875,6 +884,9 @@ public final class Choreographer { doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos); } finally { AnimationUtils.unlockAnimationClock(); + if (resynced) { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } Trace.traceEnd(Trace.TRACE_TAG_VIEW); } @@ -1149,7 +1161,8 @@ public final class Choreographer { * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from * native. */ - void update(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { + FrameTimeline update( + long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { if (vsyncEventData.frameTimelines.length != mFrameTimelines.length) { throw new IllegalStateException( "Length of native frame timelines received does not match Java. Did " @@ -1164,6 +1177,7 @@ public final class Choreographer { mFrameTimelines[i].update(frameTimeline.vsyncId, frameTimeline.expectedPresentationTime, frameTimeline.deadline); } + return mFrameTimelines[mPreferredFrameTimelineIndex]; } /** @@ -1171,7 +1185,7 @@ public final class Choreographer { * * @param jitterNanos currentTime - frameTime */ - void update( + FrameTimeline update( long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) { int newPreferredIndex = 0; final long minimumDeadline = @@ -1192,6 +1206,7 @@ public final class Choreographer { } else { update(frameTimeNanos, newPreferredIndex); } + return mFrameTimelines[mPreferredFrameTimelineIndex]; } void update(long frameTimeNanos, int newPreferredFrameTimelineIndex) { diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java index 0b4adaeb9890..a8e68b71f5cc 100644 --- a/core/java/android/view/InputEvent.java +++ b/core/java/android/view/InputEvent.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -100,6 +101,7 @@ public abstract class InputEvent implements Parcelable { * @return The display id associated with the event. * @hide */ + @TestApi public abstract int getDisplayId(); /** @@ -107,6 +109,7 @@ public abstract class InputEvent implements Parcelable { * @param displayId * @hide */ + @TestApi public abstract void setDisplayId(int displayId); /** * Copies the event. diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index d35aff9a72b7..3812d37a5fed 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -215,6 +215,7 @@ public final class InputWindowHandle { .append(", scaleFactor=").append(scaleFactor) .append(", transform=").append(transform) .append(", windowToken=").append(windowToken) + .append(", displayId=").append(displayId) .append(", isClone=").append((inputConfig & InputConfig.CLONE) != 0) .toString(); diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index b6d9400fad5c..858da554c670 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -2100,6 +2100,7 @@ public class KeyEvent extends InputEvent implements Parcelable { } /** @hide */ + @TestApi @Override public final int getDisplayId() { return mDisplayId; diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index ac50d09cc091..bd6224b07b16 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -99,9 +99,16 @@ public class SurfaceControlViewHost { @Override public ISurfaceSyncGroup getSurfaceSyncGroup() { CompletableFuture<ISurfaceSyncGroup> surfaceSyncGroup = new CompletableFuture<>(); - mViewRoot.mHandler.post( - () -> surfaceSyncGroup.complete( - mViewRoot.getOrCreateSurfaceSyncGroup().mISurfaceSyncGroup)); + // If the call came from in process and it's already running on the UI thread, return + // results immediately instead of posting to the main thread. If we post to the main + // thread, it will block itself and the return value will always be null. + if (Thread.currentThread() == mViewRoot.mThread) { + return mViewRoot.getOrCreateSurfaceSyncGroup().mISurfaceSyncGroup; + } else { + mViewRoot.mHandler.post( + () -> surfaceSyncGroup.complete( + mViewRoot.getOrCreateSurfaceSyncGroup().mISurfaceSyncGroup)); + } try { return surfaceSyncGroup.get(1, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { @@ -113,6 +120,8 @@ public class SurfaceControlViewHost { private ISurfaceControlViewHost mRemoteInterface = new ISurfaceControlViewHostImpl(); + private ViewRootImpl.ConfigChangedCallback mConfigChangedCallback; + /** * Package encapsulating a Surface hierarchy which contains interactive view * elements. It's expected to get this object from @@ -296,10 +305,11 @@ public class SurfaceControlViewHost { /** @hide */ public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d, @NonNull WindowlessWindowManager wwm, @NonNull String callsite) { + mSurfaceControl = wwm.mRootSurface; mWm = wwm; mViewRoot = new ViewRootImpl(c, d, mWm, new WindowlessWindowLayout()); mCloseGuard.openWithCallSite("release", callsite); - addConfigCallback(c, d); + setConfigCallback(c, d); WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot); @@ -349,21 +359,23 @@ public class SurfaceControlViewHost { mViewRoot = new ViewRootImpl(context, display, mWm, new WindowlessWindowLayout()); mCloseGuard.openWithCallSite("release", callsite); - addConfigCallback(context, display); + setConfigCallback(context, display); WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot); mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection(); } - private void addConfigCallback(Context c, Display d) { + private void setConfigCallback(Context c, Display d) { final IBinder token = c.getWindowContextToken(); - mViewRoot.addConfigCallback((conf) -> { + mConfigChangedCallback = conf -> { if (token instanceof WindowTokenClient) { final WindowTokenClient w = (WindowTokenClient) token; w.onConfigurationChanged(conf, d.getDisplayId(), true); } - }); + }; + + ViewRootImpl.addConfigCallback(mConfigChangedCallback); } /** @@ -378,8 +390,7 @@ public class SurfaceControlViewHost { mCloseGuard.warnIfOpen(); } // We aren't on the UI thread here so we need to pass false to doDie - mViewRoot.die(false /* immediate */); - WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot); + doRelease(false /* immediate */); } /** @@ -392,8 +403,7 @@ public class SurfaceControlViewHost { public @Nullable SurfacePackage getSurfacePackage() { if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) { return new SurfacePackage(new SurfaceControl(mSurfaceControl, "getSurfacePackage"), - mAccessibilityEmbeddedConnection, - mWm.getFocusGrantToken(), mRemoteInterface); + mAccessibilityEmbeddedConnection, getFocusGrantToken(), mRemoteInterface); } else { return null; } @@ -489,7 +499,16 @@ public class SurfaceControlViewHost { */ public void release() { // ViewRoot will release mSurfaceControl for us. - mViewRoot.die(true /* immediate */); + doRelease(true /* immediate */); + } + + private void doRelease(boolean immediate) { + if (mConfigChangedCallback != null) { + ViewRootImpl.removeConfigCallback(mConfigChangedCallback); + mConfigChangedCallback = null; + } + + mViewRoot.die(immediate); WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot); mReleased = true; mCloseGuard.close(); @@ -499,7 +518,7 @@ public class SurfaceControlViewHost { * @hide */ public IBinder getFocusGrantToken() { - return mWm.getFocusGrantToken(); + return mWm.getFocusGrantToken(getWindowToken().asBinder()); } private void addWindowToken(WindowManager.LayoutParams attrs) { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index cdea97ce9b7f..0e4cf89e7772 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1854,6 +1854,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall applyTransactionOnVriDraw(transaction); } mSurfacePackage = p; + + if (isFocused()) { + requestEmbeddedFocus(true); + } invalidate(); } @@ -1947,8 +1951,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, - @Nullable Rect previouslyFocusedRect) { + @Nullable Rect previouslyFocusedRect) { super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); + requestEmbeddedFocus(gainFocus); + } + + private void requestEmbeddedFocus(boolean gainFocus) { final ViewRootImpl viewRoot = getViewRootImpl(); if (mSurfacePackage == null || viewRoot == null) { return; diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java index 4a7ed644f9e2..4464d1918565 100644 --- a/core/java/android/view/VelocityTracker.java +++ b/core/java/android/view/VelocityTracker.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.IntDef; import android.compat.annotation.UnsupportedAppUsage; -import android.hardware.input.InputManager; +import android.hardware.input.InputManagerGlobal; import android.util.ArrayMap; import android.util.Pools.SynchronizedPool; @@ -286,7 +286,8 @@ public final class VelocityTracker { private VelocityTracker(@VelocityTrackerStrategy int strategy) { // If user has not selected a specific strategy if (strategy == VELOCITY_TRACKER_STRATEGY_DEFAULT) { - final String strategyProperty = InputManager.getInstance().getVelocityTrackerStrategy(); + final String strategyProperty = InputManagerGlobal.getInstance() + .getVelocityTrackerStrategy(); // Check if user specified strategy by overriding system property. if (strategyProperty == null || strategyProperty.isEmpty()) { mStrategy = strategy; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2f5cd5434b89..86e7fb09c5ea 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6946,6 +6946,7 @@ public final class ViewRootImpl implements ViewParent, return; } final boolean needsStylusPointerIcon = event.isStylusPointer() + && event.isHoverEvent() && mInputManager.isStylusPointerIconEnabled(); if (needsStylusPointerIcon || event.isFromSource(InputDevice.SOURCE_MOUSE)) { if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER @@ -11262,13 +11263,19 @@ public final class ViewRootImpl implements ViewParent, } if (syncBuffer) { - mBlastBufferQueue.syncNextTransaction(new Consumer<Transaction>() { - @Override - public void accept(Transaction transaction) { - surfaceSyncGroup.addTransaction(transaction); - surfaceSyncGroup.markSyncReady(); - } + boolean result = mBlastBufferQueue.syncNextTransaction(transaction -> { + surfaceSyncGroup.addTransaction(transaction); + surfaceSyncGroup.markSyncReady(); }); + if (!result) { + // syncNextTransaction can only return false if something is already trying + // to sync the same frame in the same BBQ. That shouldn't be possible, but + // if it did happen, invoke markSyncReady so the active SSG doesn't get + // stuck. + Log.e(mTag, "Unable to syncNextTransaction. Possibly something else is" + + " trying to sync?"); + surfaceSyncGroup.markSyncReady(); + } } return didProduceBuffer -> { @@ -11282,7 +11289,7 @@ public final class ViewRootImpl implements ViewParent, // the next draw attempt. The next transaction and transaction complete callback // were only set for the current draw attempt. if (!didProduceBuffer) { - mBlastBufferQueue.syncNextTransaction(null); + mBlastBufferQueue.clearSyncTransaction(); // Gather the transactions that were sent to mergeWithNextTransaction // since the frame didn't draw on this vsync. It's possible the frame will diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 98681446446b..96bfb2d9e1e6 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -106,8 +106,22 @@ public class WindowlessWindowManager implements IWindowSession { mConfiguration.setTo(configuration); } - IBinder getFocusGrantToken() { - return mFocusGrantToken; + IBinder getFocusGrantToken(IBinder window) { + synchronized (this) { + // This can only happen if someone requested the focusGrantToken before setView was + // called for the SCVH. In that case, use the root focusGrantToken since this will be + // the same token sent to WMS for the root window once setView is called. + if (mStateForWindow.isEmpty()) { + return mFocusGrantToken; + } + State state = mStateForWindow.get(window); + if (state != null) { + return state.mFocusGrantToken; + } + } + + Log.w(TAG, "Failed to get focusGrantToken. Returning null token"); + return null; } /** diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java index 38b564ade07d..d69c781a6ac9 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -976,6 +976,7 @@ public class AccessibilityRecord { append(builder, "AddedCount", mAddedCount); append(builder, "RemovedCount", mRemovedCount); append(builder, "ParcelableData", mParcelableData); + append(builder, "DisplayId", mSourceDisplayId); builder.append(" ]"); return builder; } diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index 1fac142df481..390503b80bad 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -62,7 +62,7 @@ interface IAccessibilityManager { in IAccessibilityInteractionConnection connection); void registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient client, - in AccessibilityServiceInfo info, int flags); + in AccessibilityServiceInfo info, int userId, int flags); void unregisterUiTestAutomationService(IAccessibilityServiceClient client); diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index 7d1dc7660871..84ef22637cb0 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -28,6 +28,7 @@ import android.content.res.XmlResourceParser; import android.os.SystemClock; import android.util.AttributeSet; import android.util.Xml; +import android.view.InflateException; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -137,16 +138,9 @@ public class AnimationUtils { try { parser = context.getResources().getAnimation(id); return createAnimationFromXml(context, parser); - } catch (XmlPullParserException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; + } catch (XmlPullParserException | IOException ex) { + throw new NotFoundException( + "Can't load animation resource ID #0x" + Integer.toHexString(id), ex); } finally { if (parser != null) parser.close(); } @@ -159,8 +153,9 @@ public class AnimationUtils { } @UnsupportedAppUsage - private static Animation createAnimationFromXml(Context c, XmlPullParser parser, - AnimationSet parent, AttributeSet attrs) throws XmlPullParserException, IOException { + private static Animation createAnimationFromXml( + Context c, XmlPullParser parser, AnimationSet parent, AttributeSet attrs) + throws XmlPullParserException, IOException, InflateException { Animation anim = null; @@ -168,8 +163,8 @@ public class AnimationUtils { int type; int depth = parser.getDepth(); - while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) - && type != XmlPullParser.END_DOCUMENT) { + while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) + && type != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) { continue; @@ -193,7 +188,7 @@ public class AnimationUtils { } else if (name.equals("extend")) { anim = new ExtendAnimation(c, attrs); } else { - throw new RuntimeException("Unknown animation name: " + parser.getName()); + throw new InflateException("Unknown animation name: " + parser.getName()); } if (parent != null) { @@ -220,29 +215,24 @@ public class AnimationUtils { try { parser = context.getResources().getAnimation(id); return createLayoutAnimationFromXml(context, parser); - } catch (XmlPullParserException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; + } catch (XmlPullParserException | IOException | InflateException ex) { + throw new NotFoundException( + "Can't load animation resource ID #0x" + Integer.toHexString(id), ex); } finally { if (parser != null) parser.close(); } } - private static LayoutAnimationController createLayoutAnimationFromXml(Context c, - XmlPullParser parser) throws XmlPullParserException, IOException { + private static LayoutAnimationController createLayoutAnimationFromXml( + Context c, XmlPullParser parser) + throws XmlPullParserException, IOException, InflateException { return createLayoutAnimationFromXml(c, parser, Xml.asAttributeSet(parser)); } - private static LayoutAnimationController createLayoutAnimationFromXml(Context c, - XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { + private static LayoutAnimationController createLayoutAnimationFromXml( + Context c, XmlPullParser parser, AttributeSet attrs) + throws XmlPullParserException, IOException, InflateException { LayoutAnimationController controller = null; @@ -263,7 +253,7 @@ public class AnimationUtils { } else if ("gridLayoutAnimation".equals(name)) { controller = new GridLayoutAnimationController(c, attrs); } else { - throw new RuntimeException("Unknown layout animation name: " + name); + throw new InflateException("Unknown layout animation name: " + name); } } @@ -342,16 +332,9 @@ public class AnimationUtils { try { parser = context.getResources().getAnimation(id); return createInterpolatorFromXml(context.getResources(), context.getTheme(), parser); - } catch (XmlPullParserException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; + } catch (XmlPullParserException | IOException | InflateException ex) { + throw new NotFoundException( + "Can't load animation resource ID #0x" + Integer.toHexString(id), ex); } finally { if (parser != null) parser.close(); } @@ -367,30 +350,26 @@ public class AnimationUtils { * @throws NotFoundException * @hide */ - public static Interpolator loadInterpolator(Resources res, Theme theme, int id) throws NotFoundException { + public static Interpolator loadInterpolator(Resources res, Theme theme, int id) + throws NotFoundException { XmlResourceParser parser = null; try { parser = res.getAnimation(id); return createInterpolatorFromXml(res, theme, parser); - } catch (XmlPullParserException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; + } catch (XmlPullParserException | IOException | InflateException ex) { + throw new NotFoundException( + "Can't load animation resource ID #0x" + Integer.toHexString(id), ex); } finally { - if (parser != null) + if (parser != null) { parser.close(); + } } } - private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser) - throws XmlPullParserException, IOException { + private static Interpolator createInterpolatorFromXml( + Resources res, Theme theme, XmlPullParser parser) + throws XmlPullParserException, IOException, InflateException { BaseInterpolator interpolator = null; @@ -430,7 +409,7 @@ public class AnimationUtils { } else if (name.equals("pathInterpolator")) { interpolator = new PathInterpolator(res, theme, attrs); } else { - throw new RuntimeException("Unknown interpolator name: " + parser.getName()); + throw new InflateException("Unknown interpolator name: " + parser.getName()); } } return interpolator; diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java index 4aa612c526fe..951eeccf4d8a 100644 --- a/core/java/android/view/autofill/AutofillFeatureFlags.java +++ b/core/java/android/view/autofill/AutofillFeatureFlags.java @@ -194,6 +194,14 @@ public class AutofillFeatureFlags { "should_enable_autofill_on_all_view_types"; /** + * Whether to enable multi-line filter when checking if view is autofillable + * + * @hide + */ + public static final String DEVICE_CONFIG_MULTILINE_FILTER_ENABLED = + "multiline_filter_enabled"; + + /** * Whether include all autofill type not none views in assist structure * * @hide @@ -439,6 +447,17 @@ public class AutofillFeatureFlags { } + /** + * Whether should enable multi-line filter + * + * @hide + */ + public static boolean shouldEnableMultilineFilter() { + return DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_AUTOFILL, + DEVICE_CONFIG_MULTILINE_FILTER_ENABLED, 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 801b13a2c69c..f7b7d3387938 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -707,6 +707,9 @@ public final class AutofillManager { // An allowed activity set read from device config private Set<String> mAllowedActivitySet = new ArraySet<>(); + // Whether to enable multi-line check when checking whether view is autofillable + private boolean mShouldEnableMultilineFilter; + // Indicate whether should include all view with autofill type not none in assist structure private boolean mShouldIncludeAllViewsWithAutofillTypeNotNoneInAssistStructure; @@ -889,6 +892,9 @@ public final class AutofillManager { mNonAutofillableImeActionIdSet = AutofillFeatureFlags.getNonAutofillableImeActionIdSetFromFlag(); + mShouldEnableMultilineFilter = + AutofillFeatureFlags.shouldEnableMultilineFilter(); + final String denyListString = AutofillFeatureFlags.getDenylistStringFromFlag(); final String allowlistString = AutofillFeatureFlags.getAllowlistStringFromFlag(); @@ -948,9 +954,8 @@ public final class AutofillManager { /** * Whether view passes the imeAction check * - * @hide */ - public boolean isPassingImeActionCheck(EditText editText) { + private boolean isPassingImeActionCheck(EditText editText) { final int actionId = editText.getImeOptions(); if (mNonAutofillableImeActionIdSet.contains(String.valueOf(actionId))) { Log.d(TAG, "view not autofillable - not passing ime action check"); @@ -959,6 +964,21 @@ public final class AutofillManager { return true; } + /** + * Checks whether the view passed in is not multiline text + * + * @param editText the view that passed to this check + * @return true if the view input is not multiline, false otherwise + */ + private boolean isPassingMultilineCheck(EditText editText) { + // check if min line is set to be greater than 1 + if (editText.getMinLines() > 1) { + Log.d(TAG, "view not autofillable - has multiline input type"); + return false; + } + return true; + } + 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 @@ -1103,6 +1123,9 @@ public final class AutofillManager { } if (view instanceof EditText) { + if (mShouldEnableMultilineFilter && !isPassingMultilineCheck((EditText) view)) { + return false; + } return isPassingImeActionCheck((EditText) view); } diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java index 70db6e513c88..50249da08c3c 100644 --- a/core/java/android/view/translation/Translator.java +++ b/core/java/android/view/translation/Translator.java @@ -18,7 +18,6 @@ package android.view.translation; import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL; import static android.view.translation.TranslationManager.SYNC_CALLS_TIMEOUT_MS; -import static android.view.translation.UiTranslationController.DEBUG; import android.annotation.CallbackExecutor; import android.annotation.NonNull; @@ -402,7 +401,7 @@ public class Translator { @Override public void onTranslationResponse(TranslationResponse response) throws RemoteException { - if (DEBUG) { + if (Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG)) { Log.i(TAG, "onTranslationResponse called."); } final Runnable runnable = diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java index 514df59f1989..140e3f1b6fdc 100644 --- a/core/java/android/view/translation/UiTranslationController.java +++ b/core/java/android/view/translation/UiTranslationController.java @@ -122,8 +122,9 @@ public class UiTranslationController implements Dumpable { Log.i(TAG, "Cannot update " + stateToString(state) + " for destroyed " + mActivity); return; } + boolean isLoggable = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG); Log.i(TAG, "updateUiTranslationState state: " + stateToString(state) - + (DEBUG ? (", views: " + views + ", spec: " + uiTranslationSpec) : "")); + + (isLoggable ? (", views: " + views + ", spec: " + uiTranslationSpec) : "")); synchronized (mLock) { mCurrentState = state; if (views != null) { @@ -237,7 +238,7 @@ public class UiTranslationController implements Dumpable { } pw.print(outerPrefix); pw.print("padded views: "); pw.println(mViewsToPadContent); } - if (DEBUG) { + if (Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG)) { dumpViewByTraversal(outerPrefix, pw); } } @@ -345,6 +346,7 @@ public class UiTranslationController implements Dumpable { */ private void onVirtualViewTranslationCompleted( SparseArray<LongSparseArray<ViewTranslationResponse>> translatedResult) { + boolean isLoggable = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG); if (mActivity.isDestroyed()) { Log.v(TAG, "onTranslationCompleted:" + mActivity + "is destroyed."); return; @@ -369,7 +371,7 @@ public class UiTranslationController implements Dumpable { } final LongSparseArray<ViewTranslationResponse> virtualChildResponse = translatedResult.valueAt(i); - if (DEBUG) { + if (isLoggable) { Log.v(TAG, "onVirtualViewTranslationCompleted: received response for " + "AutofillId " + autofillId); } @@ -379,7 +381,7 @@ public class UiTranslationController implements Dumpable { } mActivity.runOnUiThread(() -> { if (view.getViewTranslationCallback() == null) { - if (DEBUG) { + if (isLoggable) { Log.d(TAG, view + " doesn't support showing translation because of " + "null ViewTranslationCallback."); } @@ -397,12 +399,13 @@ public class UiTranslationController implements Dumpable { * The method is used to handle the translation result for non-vertual views. */ private void onTranslationCompleted(SparseArray<ViewTranslationResponse> translatedResult) { + boolean isLoggable = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG); if (mActivity.isDestroyed()) { Log.v(TAG, "onTranslationCompleted:" + mActivity + "is destroyed."); return; } final int resultCount = translatedResult.size(); - if (DEBUG) { + if (isLoggable) { Log.v(TAG, "onTranslationCompleted: receive " + resultCount + " responses."); } synchronized (mLock) { @@ -413,7 +416,7 @@ public class UiTranslationController implements Dumpable { } for (int i = 0; i < resultCount; i++) { final ViewTranslationResponse response = translatedResult.valueAt(i); - if (DEBUG) { + if (isLoggable) { Log.v(TAG, "onTranslationCompleted: " + sanitizedViewTranslationResponse(response)); } @@ -443,7 +446,7 @@ public class UiTranslationController implements Dumpable { (TextViewTranslationCallback) callback; if (textViewCallback.isShowingTranslation() || textViewCallback.isAnimationRunning()) { - if (DEBUG) { + if (isLoggable) { Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId + ". Ignoring."); } @@ -458,7 +461,7 @@ public class UiTranslationController implements Dumpable { callback = new TextViewTranslationCallback(); view.setViewTranslationCallback(callback); } else { - if (DEBUG) { + if (isLoggable) { Log.d(TAG, view + " doesn't support showing translation because of " + "null ViewTranslationCallback."); } @@ -506,7 +509,7 @@ public class UiTranslationController implements Dumpable { final TranslationRequest request = new TranslationRequest.Builder() .setViewTranslationRequests(requests) .build(); - if (DEBUG) { + if (Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG)) { StringBuilder msg = new StringBuilder("sendTranslationRequest:{requests=["); for (ViewTranslationRequest viewRequest: requests) { msg.append("{request=") @@ -636,6 +639,7 @@ public class UiTranslationController implements Dumpable { private void runForEachView(BiConsumer<View, ViewTranslationCallback> action) { synchronized (mLock) { + boolean isLoggable = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG); final ArrayMap<AutofillId, WeakReference<View>> views = new ArrayMap<>(mViews); if (views.size() == 0) { Log.w(TAG, "No views can be excuted for runForEachView."); @@ -644,12 +648,12 @@ public class UiTranslationController implements Dumpable { final int viewCounts = views.size(); for (int i = 0; i < viewCounts; i++) { final View view = views.valueAt(i).get(); - if (DEBUG) { + if (isLoggable) { Log.d(TAG, "runForEachView for autofillId = " + (view != null ? view.getAutofillId() : " null")); } if (view == null || view.getViewTranslationCallback() == null) { - if (DEBUG) { + if (isLoggable) { Log.d(TAG, "View was gone or ViewTranslationCallback for autofillId " + "= " + views.keyAt(i)); } diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 3df09c24ca30..1f0e95ea305a 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -49,15 +49,18 @@ import java.util.Formatter; import java.util.Locale; /** - * This widget display an analogic clock with two hands for hours and - * minutes. + * This widget displays an analogic clock with two hands for hours and minutes. * * @attr ref android.R.styleable#AnalogClock_dial * @attr ref android.R.styleable#AnalogClock_hand_hour * @attr ref android.R.styleable#AnalogClock_hand_minute * @attr ref android.R.styleable#AnalogClock_hand_second * @attr ref android.R.styleable#AnalogClock_timeZone - * @deprecated This widget is no longer supported. + * @deprecated This widget is no longer supported; except for + * {@link android.widget.RemoteViews} use cases like + * <a href="https://developer.android.com/develop/ui/views/appwidgets/overview"> + * app widgets</a>. + * */ @RemoteView @Deprecated diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 088065d2f77d..7931d1a06d39 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -8095,12 +8095,14 @@ public class Editor { private boolean mIsInsertModeActive; private InsertModeTransformationMethod mInsertModeTransformationMethod; private final Paint mHighlightPaint; + private final Path mHighlightPath; InsertModeController(@NonNull TextView textView) { mTextView = Objects.requireNonNull(textView); mIsInsertModeActive = false; mInsertModeTransformationMethod = null; mHighlightPaint = new Paint(); + mHighlightPath = new Path(); // The highlight color is supposed to be 12% of the color primary40. We can't // directly access Material 3 theme. But because Material 3 sets the colorPrimary to @@ -8168,10 +8170,8 @@ public class Editor { ((InsertModeTransformationMethod.TransformedText) transformedText); final int highlightStart = insertModeTransformedText.getHighlightStart(); final int highlightEnd = insertModeTransformedText.getHighlightEnd(); - final Layout.SelectionRectangleConsumer consumer = - (left, top, right, bottom, textSelectionLayout) -> - canvas.drawRect(left, top, right, bottom, mHighlightPaint); - layout.getSelection(highlightStart, highlightEnd, consumer); + layout.getSelectionPath(highlightStart, highlightEnd, mHighlightPath); + canvas.drawPath(mHighlightPath, mHighlightPaint); } } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 18874f768929..3165654d806d 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -1780,6 +1780,21 @@ public class RemoteViews implements Parcelable, Filter { Object value = getParameterValue(view); try { MethodHandle method = getMethod(view, this.methodName, param, true /* async */); + // Upload the bitmap to GPU if the parameter is of type Bitmap or Icon. + // Since bitmaps in framework are seldomly modified, this is supposed to accelerate + // the operations. + if (value instanceof Bitmap bitmap) { + bitmap.prepareToDraw(); + } + + if (value instanceof Icon icon + && (icon.getType() == Icon.TYPE_BITMAP + || icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP)) { + Bitmap bitmap = icon.getBitmap(); + if (bitmap != null) { + bitmap.prepareToDraw(); + } + } if (method != null) { Runnable endAction = (Runnable) method.invoke(view, value); diff --git a/core/java/android/window/BackMotionEvent.java b/core/java/android/window/BackMotionEvent.java index 8012a1c26bac..c47572313eeb 100644 --- a/core/java/android/window/BackMotionEvent.java +++ b/core/java/android/window/BackMotionEvent.java @@ -34,6 +34,8 @@ public final class BackMotionEvent implements Parcelable { private final float mTouchX; private final float mTouchY; private final float mProgress; + private final float mVelocityX; + private final float mVelocityY; @BackEvent.SwipeEdge private final int mSwipeEdge; @@ -43,19 +45,32 @@ public final class BackMotionEvent implements Parcelable { /** * Creates a new {@link BackMotionEvent} instance. * + * <p>Note: Velocity is only computed for last event, for performance reasons.</p> + * * @param touchX Absolute X location of the touch point of this event. * @param touchY Absolute Y location of the touch point of this event. * @param progress Value between 0 and 1 on how far along the back gesture is. + * @param velocityX X velocity computed from the touch point of this event. + * Value in pixels/second. {@link Float#NaN} if was not computed. + * @param velocityY Y velocity computed from the touch point of this event. + * Value in pixels/second. {@link Float#NaN} if was not computed. * @param swipeEdge Indicates which edge the swipe starts from. * @param departingAnimationTarget The remote animation target of the departing * application window. */ - public BackMotionEvent(float touchX, float touchY, float progress, + public BackMotionEvent( + float touchX, + float touchY, + float progress, + float velocityX, + float velocityY, @BackEvent.SwipeEdge int swipeEdge, @Nullable RemoteAnimationTarget departingAnimationTarget) { mTouchX = touchX; mTouchY = touchY; mProgress = progress; + mVelocityX = velocityX; + mVelocityY = velocityY; mSwipeEdge = swipeEdge; mDepartingAnimationTarget = departingAnimationTarget; } @@ -64,6 +79,8 @@ public final class BackMotionEvent implements Parcelable { mTouchX = in.readFloat(); mTouchY = in.readFloat(); mProgress = in.readFloat(); + mVelocityX = in.readFloat(); + mVelocityY = in.readFloat(); mSwipeEdge = in.readInt(); mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR); } @@ -91,11 +108,27 @@ public final class BackMotionEvent implements Parcelable { dest.writeFloat(mTouchX); dest.writeFloat(mTouchY); dest.writeFloat(mProgress); + dest.writeFloat(mVelocityX); + dest.writeFloat(mVelocityY); dest.writeInt(mSwipeEdge); dest.writeTypedObject(mDepartingAnimationTarget, flags); } /** + * Returns the absolute X location of the touch point. + */ + public float getTouchX() { + return mTouchX; + } + + /** + * Returns the absolute Y location of the touch point. + */ + public float getTouchY() { + return mTouchY; + } + + /** * Returns the progress of a {@link BackEvent}. * * @see BackEvent#getProgress() @@ -106,17 +139,21 @@ public final class BackMotionEvent implements Parcelable { } /** - * Returns the absolute X location of the touch point. + * Returns the X velocity computed from the touch point. + * + * @return value in pixels/second or {@link Float#NaN} if was not computed. */ - public float getTouchX() { - return mTouchX; + public float getVelocityX() { + return mVelocityX; } /** - * Returns the absolute Y location of the touch point. + * Returns the Y velocity computed from the touch point. + * + * @return value in pixels/second or {@link Float#NaN} if was not computed. */ - public float getTouchY() { - return mTouchY; + public float getVelocityY() { + return mVelocityY; } /** @@ -143,6 +180,8 @@ public final class BackMotionEvent implements Parcelable { + "mTouchX=" + mTouchX + ", mTouchY=" + mTouchY + ", mProgress=" + mProgress + + ", mVelocityX=" + mVelocityX + + ", mVelocityY=" + mVelocityY + ", mSwipeEdge" + mSwipeEdge + ", mDepartingAnimationTarget" + mDepartingAnimationTarget + "}"; diff --git a/core/java/com/android/internal/expresslog/Utils.java b/core/java/android/window/IDumpCallback.aidl index d82192f51662..4c825d43add1 100644 --- a/core/java/com/android/internal/expresslog/Utils.java +++ b/core/java/android/window/IDumpCallback.aidl @@ -13,9 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package android.window; -package com.android.internal.expresslog; - -final class Utils { - static native long hashString(String stringToHash); -} +/** + * Callback for processes which need to feed data to another process when it dumps. + * @hide + */ + interface IDumpCallback { + oneway void onDump(in ParcelFileDescriptor outFd); + }
\ No newline at end of file diff --git a/core/java/android/window/SurfaceSyncGroup.java b/core/java/android/window/SurfaceSyncGroup.java index 7f99fb7e7815..b3d512488239 100644 --- a/core/java/android/window/SurfaceSyncGroup.java +++ b/core/java/android/window/SurfaceSyncGroup.java @@ -120,6 +120,7 @@ public final class SurfaceSyncGroup { private static HandlerThread sHandlerThread; private Handler mHandler; + @GuardedBy("mLock") private boolean mTimeoutAdded; private static boolean isLocalBinder(IBinder binder) { @@ -234,6 +235,9 @@ public final class SurfaceSyncGroup { * SurfaceSyncGroup have completed their sync. */ public void markSyncReady() { + if (DEBUG) { + Log.d(TAG, "markSyncReady " + mName); + } if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "markSyncReady " + mName); } @@ -456,7 +460,15 @@ public final class SurfaceSyncGroup { */ public void addTransaction(@NonNull Transaction transaction) { synchronized (mLock) { - mTransaction.merge(transaction); + // If the caller tries to add a transaction to a completed SSG, just apply the + // transaction immediately since there's nothing to wait on. + if (mFinished) { + Log.w(TAG, "Adding transaction to a completed SurfaceSyncGroup(" + mName + "). " + + " Applying immediately"); + transaction.apply(); + } else { + mTransaction.merge(transaction); + } } } @@ -509,7 +521,7 @@ public final class SurfaceSyncGroup { private boolean addLocalSync(ISurfaceSyncGroup childSyncToken, boolean parentSyncGroupMerge) { if (DEBUG) { - Log.d(TAG, "Adding local sync " + mName); + Log.d(TAG, "Adding local sync to " + mName); } SurfaceSyncGroup childSurfaceSyncGroup = getSurfaceSyncGroup(childSyncToken); @@ -540,7 +552,7 @@ public final class SurfaceSyncGroup { private void setTransactionCallbackFromParent(ISurfaceSyncGroup parentSyncGroup, ITransactionReadyCallback transactionReadyCallback) { if (DEBUG) { - Log.d(TAG, "setTransactionCallbackFromParent " + mName); + Log.d(TAG, "setTransactionCallbackFromParent for child " + mName); } if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { @@ -677,7 +689,7 @@ public final class SurfaceSyncGroup { */ public ITransactionReadyCallback createTransactionReadyCallback(boolean parentSyncGroupMerge) { if (DEBUG) { - Log.d(TAG, "createTransactionReadyCallback " + mName); + Log.d(TAG, "createTransactionReadyCallback as part of " + mName); } ITransactionReadyCallback transactionReadyCallback = new ITransactionReadyCallback.Stub() { @@ -780,7 +792,7 @@ public final class SurfaceSyncGroup { Runnable runnable = () -> { Log.e(TAG, "Failed to receive transaction ready in " + TRANSACTION_READY_TIMEOUT - + "ms. Marking SurfaceSyncGroup as ready " + mName); + + "ms. Marking SurfaceSyncGroup(" + mName + ") as ready"); // Clear out any pending syncs in case the other syncs can't complete or timeout due to // a crash. synchronized (mLock) { diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 787b594af6bb..65394bd87d64 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -63,6 +63,7 @@ interface IBatteryStats { void noteResetCamera(); @EnforcePermission("UPDATE_DEVICE_STATS") void noteResetFlashlight(); + void noteWakeupSensorEvent(long elapsedNanos, int uid, int handle); // Remaining methods are only used in Java. @EnforcePermission("BATTERY_STATS") diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl index ad0d1a401991..380118846dc7 100644 --- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl +++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl @@ -20,6 +20,7 @@ import android.hardware.soundtrigger.SoundTrigger; import android.service.voice.HotwordDetectedResult; import android.service.voice.HotwordDetectionServiceFailure; import android.service.voice.HotwordRejectedResult; +import android.service.voice.SoundTriggerFailure; import android.service.voice.VisualQueryDetectionServiceFailure; /** @@ -57,13 +58,6 @@ oneway interface IHotwordRecognitionStatusCallback { void onRejected(in HotwordRejectedResult result); /** - * Called when the detection fails due to an error. - * - * @param status The error code that was seen. - */ - void onError(int status); - - /** * Called when the detection fails due to an error occurs in the * {@link HotwordDetectionService}. * @@ -84,6 +78,15 @@ oneway interface IHotwordRecognitionStatusCallback { in VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure); /** + * Called when the detection fails due to an error occurs in the + * {@link com.android.server.soundtrigger.SoundTriggerService}. + * + * @param soundTriggerFailure It provides the error code, error message and + * suggested action. + */ + void onSoundTriggerFailure(in SoundTriggerFailure soundTriggerFailure); + + /** * Called when the detection fails due to an unknown error occurs. * * @param errorMessage It provides the error message. diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl index ab7f602e2dfc..ed751cb481c5 100644 --- a/core/java/com/android/internal/app/ISoundTriggerService.aidl +++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl @@ -16,8 +16,9 @@ package com.android.internal.app; -import android.media.permission.Identity; import android.hardware.soundtrigger.SoundTrigger; +import android.media.permission.Identity; +import android.media.soundtrigger_middleware.ISoundTriggerInjection; import com.android.internal.app.ISoundTriggerSession; /** @@ -74,4 +75,8 @@ interface ISoundTriggerService { */ List<SoundTrigger.ModuleProperties> listModuleProperties(in Identity originatorIdentity); + /** + * Attach an HAL injection interface. + */ + void attachInjection(ISoundTriggerInjection injection); } diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 6b40d9873fbb..24d5afc42d8f 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -96,6 +96,21 @@ interface IVoiceInteractionManagerService { * @RequiresPermission Manifest.permission.MANAGE_VOICE_KEYPHRASES */ int deleteKeyphraseSoundModel(int keyphraseId, in String bcp47Locale); + + /** + * Override the persistent enrolled model database with an in-memory + * fake for testing purposes. + * + * @param enabled - {@code true} to enable the test database. {@code false} to enable + * the real, persistent database. + * @param token - IBinder used to register a death listener to clean-up the override + * if tests do not clean up gracefully. + */ + @EnforcePermission("MANAGE_VOICE_KEYPHRASES") + @JavaPassthrough(annotation= "@android.annotation.RequiresPermission(" + + "android.Manifest.permission.MANAGE_VOICE_KEYPHRASES)") + void setModelDatabaseForTestEnabled(boolean enabled, IBinder token); + /** * Indicates if there's a keyphrase sound model available for the given keyphrase ID and the * user ID of the caller. @@ -106,6 +121,7 @@ interface IVoiceInteractionManagerService { * @param bcp47Locale The BCP47 language tag for the keyphrase's locale. */ boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale); + /** * Generates KeyphraseMetadata for an enrolled sound model based on keyphrase string, locale, * and the user ID of the caller. diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS index a1d571fc4350..52f18fb80c27 100644 --- a/core/java/com/android/internal/app/OWNERS +++ b/core/java/com/android/internal/app/OWNERS @@ -1,15 +1,16 @@ per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file UnlaunchableAppActivity.java = file:/core/java/android/app/admin/WorkProfile_OWNERS per-file IntentForwarderActivity.java = file:/core/java/android/app/admin/WorkProfile_OWNERS -per-file *Resolver* = file:/packages/SystemUI/OWNERS -per-file *Chooser* = file:/packages/SystemUI/OWNERS -per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS -per-file AbstractMultiProfilePagerAdapter.java = file:/packages/SystemUI/OWNERS -per-file *EmptyStateProvider.java = file:/packages/SystemUI/OWNERS per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS per-file *SoundTrigger* = file:/media/java/android/media/soundtrigger/OWNERS +# Chooser and Resolver. +per-file *Chooser* = file:chooser/OWNERS +per-file *Resolver* = file:chooser/OWNERS +per-file SimpleIconFactory.java = file:chooser/OWNERS +per-file AbstractMultiProfilePagerAdapter.java = file:chooser/OWNERS +per-file *EmptyStateProvider.java = file:chooser/OWNERS # Voice Interaction per-file *Assist* = file:/core/java/android/service/voice/OWNERS diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java index e47c335f9c7e..73914a2a99f6 100644 --- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java +++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java @@ -16,7 +16,6 @@ package com.android.internal.app; -import static android.app.admin.DevicePolicyResources.Strings.Core.UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE; import static android.app.admin.DevicePolicyResources.Strings.Core.UNLAUNCHABLE_APP_WORK_PAUSED_TITLE; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -87,17 +86,13 @@ public class UnlaunchableAppActivity extends Activity mTelecomManager.getDefaultDialerPackage(UserHandle.of(mUserId)))); final AlertDialog.Builder builder; - final String dialogMessage; if (showEmergencyCallButton) { builder = new AlertDialog.Builder(this, R.style.AlertDialogWithEmergencyButton); - dialogMessage = getDialogMessage(R.string.work_mode_dialer_off_message); builder.setNeutralButton(R.string.work_mode_emergency_call_button, this); } else { builder = new AlertDialog.Builder(this); - dialogMessage = getDialogMessage(R.string.work_mode_off_message); } builder.setTitle(getDialogTitle()) - .setMessage(dialogMessage) .setOnDismissListener(this) .setPositiveButton(R.string.work_mode_turn_on, this) .setNegativeButton(R.string.cancel, null); @@ -120,12 +115,6 @@ public class UnlaunchableAppActivity extends Activity UNLAUNCHABLE_APP_WORK_PAUSED_TITLE, () -> getString(R.string.work_mode_off_title)); } - private String getDialogMessage(int dialogMessageString) { - return getSystemService(DevicePolicyManager.class).getResources().getString( - UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE, - () -> getString(dialogMessageString)); - } - @Override public void onDismiss(DialogInterface dialog) { finish(); diff --git a/core/java/com/android/internal/app/chooser/OWNERS b/core/java/com/android/internal/app/chooser/OWNERS index a6f1632e7b8c..0844cfa6d053 100644 --- a/core/java/com/android/internal/app/chooser/OWNERS +++ b/core/java/com/android/internal/app/chooser/OWNERS @@ -1 +1,3 @@ -file:/packages/SystemUI/OWNERS
\ No newline at end of file +# Bug component: 324112 + +include platform/packages/modules/IntentResolver:/OWNERS diff --git a/core/java/com/android/internal/expresslog/Counter.java b/core/java/com/android/internal/expresslog/Counter.java deleted file mode 100644 index 4a46d91efbf0..000000000000 --- a/core/java/com/android/internal/expresslog/Counter.java +++ /dev/null @@ -1,71 +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.internal.expresslog; - -import android.annotation.NonNull; - -import com.android.internal.util.FrameworkStatsLog; - -/** Counter encapsulates StatsD write API calls */ -public final class Counter { - - // Not instantiable. - private Counter() {} - - /** - * Increments Telemetry Express Counter metric by 1 - * @param metricId to log, no-op if metricId is not defined in the TeX catalog - * @hide - */ - public static void logIncrement(@NonNull String metricId) { - logIncrement(metricId, 1); - } - - /** - * Increments Telemetry Express Counter metric by 1 - * @param metricId to log, no-op if metricId is not defined in the TeX catalog - * @param uid used as a dimension for the count metric - * @hide - */ - public static void logIncrementWithUid(@NonNull String metricId, int uid) { - logIncrementWithUid(metricId, uid, 1); - } - - /** - * Increments Telemetry Express Counter metric by arbitrary value - * @param metricId to log, no-op if metricId is not defined in the TeX catalog - * @param amount to increment counter - * @hide - */ - public static void logIncrement(@NonNull String metricId, long amount) { - final long metricIdHash = Utils.hashString(metricId); - FrameworkStatsLog.write(FrameworkStatsLog.EXPRESS_EVENT_REPORTED, metricIdHash, amount); - } - - /** - * Increments Telemetry Express Counter metric by arbitrary value - * @param metricId to log, no-op if metricId is not defined in the TeX catalog - * @param uid used as a dimension for the count metric - * @param amount to increment counter - * @hide - */ - public static void logIncrementWithUid(@NonNull String metricId, int uid, long amount) { - final long metricIdHash = Utils.hashString(metricId); - FrameworkStatsLog.write( - FrameworkStatsLog.EXPRESS_UID_EVENT_REPORTED, metricIdHash, amount, uid); - } -} diff --git a/core/java/com/android/internal/expresslog/Histogram.java b/core/java/com/android/internal/expresslog/Histogram.java deleted file mode 100644 index 2fe784a5a855..000000000000 --- a/core/java/com/android/internal/expresslog/Histogram.java +++ /dev/null @@ -1,234 +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.internal.expresslog; - -import android.annotation.FloatRange; -import android.annotation.IntRange; -import android.annotation.NonNull; - -import com.android.internal.util.FrameworkStatsLog; - -import java.util.Arrays; - -/** Histogram encapsulates StatsD write API calls */ -public final class Histogram { - - private final long mMetricIdHash; - private final BinOptions mBinOptions; - - /** - * Creates Histogram metric logging wrapper - * - * @param metricId to log, logging will be no-op if metricId is not defined in the TeX catalog - * @param binOptions to calculate bin index for samples - * @hide - */ - public Histogram(@NonNull String metricId, @NonNull BinOptions binOptions) { - mMetricIdHash = Utils.hashString(metricId); - mBinOptions = binOptions; - } - - /** - * Logs increment sample count for automatically calculated bin - * - * @param sample value - * @hide - */ - public void logSample(float sample) { - final int binIndex = mBinOptions.getBinForSample(sample); - FrameworkStatsLog.write(FrameworkStatsLog.EXPRESS_HISTOGRAM_SAMPLE_REPORTED, mMetricIdHash, - /*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 { - /** - * Returns bins count to be used by a histogram - * - * @return bins count used to initialize Options, including overflow & underflow bins - * @hide - */ - int getBinsCount(); - - /** - * Returns bin index for the input sample value - * index == 0 stands for underflow - * index == getBinsCount() - 1 stands for overflow - * - * @return zero based index - * @hide - */ - int getBinForSample(float sample); - } - - /** Used by Histogram to map data sample to corresponding bin for uniform bins */ - public static final class UniformOptions implements BinOptions { - - private final int mBinCount; - private final float mMinValue; - private final float mExclusiveMaxValue; - private final float mBinSize; - - /** - * Creates options for uniform (linear) sized bins - * - * @param binCount amount of histogram bins. 2 bin indexes will be calculated - * automatically to represent underflow & overflow bins - * @param minValue is included in the first bin, values less than minValue - * go to underflow bin - * @param exclusiveMaxValue is included in the overflow bucket. For accurate - * measure up to kMax, then exclusiveMaxValue - * should be set to kMax + 1 - * @hide - */ - public UniformOptions(@IntRange(from = 1) int binCount, float minValue, - float exclusiveMaxValue) { - if (binCount < 1) { - throw new IllegalArgumentException("Bin count should be positive number"); - } - - if (exclusiveMaxValue <= minValue) { - throw new IllegalArgumentException("Bins range invalid (maxValue < minValue)"); - } - - mMinValue = minValue; - mExclusiveMaxValue = exclusiveMaxValue; - mBinSize = (mExclusiveMaxValue - minValue) / binCount; - - // Implicitly add 2 for the extra underflow & overflow bins - mBinCount = binCount + 2; - } - - @Override - public int getBinsCount() { - return mBinCount; - } - - @Override - public int getBinForSample(float sample) { - if (sample < mMinValue) { - // goes to underflow - return 0; - } else if (sample >= mExclusiveMaxValue) { - // goes to overflow - return mBinCount - 1; - } - return (int) ((sample - mMinValue) / mBinSize + 1); - } - } - - /** Used by Histogram to map data sample to corresponding bin for scaled bins */ - public static final class ScaledRangeOptions implements BinOptions { - // store minimum value per bin - final long[] mBins; - - /** - * Creates options for scaled range bins - * - * @param binCount amount of histogram bins. 2 bin indexes will be calculated - * automatically to represent underflow & overflow bins - * @param minValue is included in the first bin, values less than minValue - * go to underflow bin - * @param firstBinWidth used to represent first bin width and as a reference to calculate - * width for consecutive bins - * @param scaleFactor used to calculate width for consecutive bins - * @hide - */ - public ScaledRangeOptions(@IntRange(from = 1) int binCount, int minValue, - @FloatRange(from = 1.f) float firstBinWidth, - @FloatRange(from = 1.f) float scaleFactor) { - if (binCount < 1) { - throw new IllegalArgumentException("Bin count should be positive number"); - } - - if (firstBinWidth < 1.f) { - throw new IllegalArgumentException( - "First bin width invalid (should be 1.f at minimum)"); - } - - if (scaleFactor < 1.f) { - throw new IllegalArgumentException( - "Scaled factor invalid (should be 1.f at minimum)"); - } - - // precalculating bins ranges (no need to create a bin for underflow reference value) - mBins = initBins(binCount + 1, minValue, firstBinWidth, scaleFactor); - } - - @Override - public int getBinsCount() { - return mBins.length + 1; - } - - @Override - public int getBinForSample(float sample) { - if (sample < mBins[0]) { - // goes to underflow - return 0; - } else if (sample >= mBins[mBins.length - 1]) { - // goes to overflow - return mBins.length; - } - - return lower_bound(mBins, (long) sample) + 1; - } - - // To find lower bound using binary search implementation of Arrays utility class - private static int lower_bound(long[] array, long sample) { - int index = Arrays.binarySearch(array, sample); - // If key is not present in the array - if (index < 0) { - // Index specify the position of the key when inserted in the sorted array - // so the element currently present at this position will be the lower bound - return Math.abs(index) - 2; - } - return index; - } - - private static long[] initBins(int count, int minValue, float firstBinWidth, - float scaleFactor) { - long[] bins = new long[count]; - bins[0] = minValue; - double lastWidth = firstBinWidth; - for (int i = 1; i < count; i++) { - // current bin minValue = previous bin width * scaleFactor - double currentBinMinValue = bins[i - 1] + lastWidth; - if (currentBinMinValue > Integer.MAX_VALUE) { - throw new IllegalArgumentException( - "Attempted to create a bucket larger than maxint"); - } - - bins[i] = (long) currentBinMinValue; - lastWidth *= scaleFactor; - } - return bins; - } - } -} diff --git a/core/java/com/android/internal/expresslog/OWNERS b/core/java/com/android/internal/expresslog/OWNERS deleted file mode 100644 index ee865b1e4ec8..000000000000 --- a/core/java/com/android/internal/expresslog/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /services/core/java/com/android/server/stats/OWNERS diff --git a/core/java/com/android/internal/expresslog/TEST_MAPPING b/core/java/com/android/internal/expresslog/TEST_MAPPING deleted file mode 100644 index c9b0cf80a1e6..000000000000 --- a/core/java/com/android/internal/expresslog/TEST_MAPPING +++ /dev/null @@ -1,12 +0,0 @@ -{ - "presubmit": [ - { - "name": "ExpressLogTests", - "options": [ - { - "exclude-annotation": "org.junit.Ignore" - } - ] - } - ] -}
\ No newline at end of file diff --git a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java index e2c096c11fee..aa6b1c00d186 100644 --- a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java +++ b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java @@ -20,7 +20,7 @@ import android.annotation.Nullable; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.expresslog.Counter; +import com.android.modules.expresslog.Counter; import java.io.IOException; import java.util.Arrays; diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index cee8c1a47769..3633d9101fb9 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -1018,7 +1018,7 @@ public final class Zygote { * Applies debugger system properties to the zygote arguments. * * For eng builds all apps are debuggable. On userdebug and user builds - * if persist.debuggable.dalvik.vm.jdwp.enabled is 1 all apps are + * if persist.debug.dalvik.vm.jdwp.enabled is 1 all apps are * debuggable. Otherwise, the debugger state is specified via the * "--enable-jdwp" flag in the spawn request. * diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java index 1172f7ba447a..aa2318d219f8 100644 --- a/core/java/com/android/internal/policy/TransitionAnimation.java +++ b/core/java/com/android/internal/policy/TransitionAnimation.java @@ -50,6 +50,7 @@ import android.media.Image; import android.media.ImageReader; import android.os.SystemProperties; import android.util.Slog; +import android.view.InflateException; import android.view.SurfaceControl; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.TransitionOldType; @@ -1264,7 +1265,7 @@ public class TransitionAnimation { public static Animation loadAnimationSafely(Context context, int resId, String tag) { try { return AnimationUtils.loadAnimation(context, resId); - } catch (Resources.NotFoundException e) { + } catch (Resources.NotFoundException | InflateException e) { Slog.w(tag, "Unable to load animation resource", e); return null; } diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java index f6d80a572c75..8fe2b9cdf1e5 100644 --- a/core/java/com/android/internal/util/DumpUtils.java +++ b/core/java/com/android/internal/util/DumpUtils.java @@ -25,6 +25,7 @@ import android.os.Binder; import android.os.Handler; import android.text.TextUtils; import android.util.Slog; +import android.util.SparseArray; import java.io.PrintWriter; import java.io.StringWriter; @@ -312,5 +313,85 @@ public final class DumpUtils { || cn.flattenToString().toLowerCase().contains(filterString.toLowerCase()); }; } -} + /** + * Lambda used to dump a key (and its index) while iterating though a collection. + */ + public interface KeyDumper { + + /** Dumps the index and key.*/ + void dump(int index, int key); + } + + /** + * Lambda used to dump a value while iterating though a collection. + * + * @param <T> type of the value. + */ + public interface ValueDumper<T> { + + /** Dumps the value.*/ + void dump(T value); + } + + /** + * Dumps a sparse array. + */ + public static void dumpSparseArray(PrintWriter pw, String prefix, SparseArray<?> array, + String name) { + dumpSparseArray(pw, prefix, array, name, /* keyDumper= */ null, /* valueDumper= */ null); + } + + /** + * Dumps the values of a sparse array. + */ + public static <T> void dumpSparseArrayValues(PrintWriter pw, String prefix, + SparseArray<T> array, String name) { + dumpSparseArray(pw, prefix, array, name, (i, k) -> { + pw.printf("%s%s", prefix, prefix); + }, /* valueDumper= */ null); + } + + /** + * Dumps a sparse array, customizing each line. + */ + public static <T> void dumpSparseArray(PrintWriter pw, String prefix, SparseArray<T> array, + String name, @Nullable KeyDumper keyDumper, @Nullable ValueDumper<T> valueDumper) { + int size = array.size(); + if (size == 0) { + pw.print(prefix); + pw.print("No "); + pw.print(name); + pw.println("s"); + return; + } + pw.print(prefix); + pw.print(size); + pw.print(' '); + pw.print(name); + pw.println("(s):"); + + String prefix2 = prefix + prefix; + for (int i = 0; i < size; i++) { + int key = array.keyAt(i); + T value = array.valueAt(i); + if (keyDumper != null) { + keyDumper.dump(i, key); + } else { + pw.print(prefix2); + pw.print(i); + pw.print(": "); + pw.print(key); + pw.print("->"); + } + if (value == null) { + pw.print("(null)"); + } else if (valueDumper != null) { + valueDumper.dump(value); + } else { + pw.print(value); + } + pw.println(); + } + } +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index fc26766d7090..6bec6bc236bd 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -225,7 +225,6 @@ cc_library_shared { "android_security_Scrypt.cpp", "com_android_internal_content_om_OverlayConfig.cpp", "com_android_internal_content_om_OverlayManagerImpl.cpp", - "com_android_internal_expresslog_Utils.cpp", "com_android_internal_net_NetworkUtilsInternal.cpp", "com_android_internal_os_ClassLoaderFactory.cpp", "com_android_internal_os_FuseAppLoop.cpp", @@ -262,6 +261,7 @@ cc_library_shared { "libstatssocket_lazy", "libskia", "libtextclassifier_hash_static", + "libexpresslog_jni", ], shared_libs: [ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index b550f28e0934..21bdf099f18d 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -200,7 +200,7 @@ extern int register_com_android_internal_content_F2fsUtils(JNIEnv* env); extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env); extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env); extern int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env); -extern int register_com_android_internal_expresslog_Utils(JNIEnv* env); +extern int register_com_android_modules_expresslog_Utils(JNIEnv* env); extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env); extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env); extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env); @@ -1586,7 +1586,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_incremental_IncrementalManager), REG_JNI(register_com_android_internal_content_om_OverlayConfig), REG_JNI(register_com_android_internal_content_om_OverlayManagerImpl), - REG_JNI(register_com_android_internal_expresslog_Utils), + REG_JNI(register_com_android_modules_expresslog_Utils), REG_JNI(register_com_android_internal_net_NetworkUtilsInternal), REG_JNI(register_com_android_internal_os_ClassLoaderFactory), REG_JNI(register_com_android_internal_os_LongArrayMultiStateCounter), diff --git a/core/jni/OWNERS b/core/jni/OWNERS index bce533281186..4e4abec88040 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -104,6 +104,3 @@ per-file com_android_internal_os_*MultiStateCounter* = file:/BATTERY_STATS_OWNER # PM per-file com_android_internal_content_* = file:/PACKAGE_MANAGER_OWNERS - -# Stats/expresslog -per-file *expresslog* = file:/services/core/java/com/android/server/stats/OWNERS diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index 03815108f6dd..55aa7117221e 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -125,26 +125,24 @@ private: jobject mObject; }; -static void nativeSyncNextTransaction(JNIEnv* env, jclass clazz, jlong ptr, jobject callback, +static bool nativeSyncNextTransaction(JNIEnv* env, jclass clazz, jlong ptr, jobject callback, jboolean acquireSingleBuffer) { + LOG_ALWAYS_FATAL_IF(!callback, "callback passed in to syncNextTransaction must not be NULL"); + sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr); JavaVM* vm = nullptr; LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM"); - if (!callback) { - queue->syncNextTransaction(nullptr, acquireSingleBuffer); - } else { - auto globalCallbackRef = - std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(callback)); - queue->syncNextTransaction( - [globalCallbackRef](SurfaceComposerClient::Transaction* t) { - JNIEnv* env = getenv(globalCallbackRef->vm()); - env->CallVoidMethod(globalCallbackRef->object(), gTransactionConsumer.accept, - env->NewObject(gTransactionClassInfo.clazz, - gTransactionClassInfo.ctor, - reinterpret_cast<jlong>(t))); - }, - acquireSingleBuffer); - } + + auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(callback)); + return queue->syncNextTransaction( + [globalCallbackRef](SurfaceComposerClient::Transaction* t) { + JNIEnv* env = getenv(globalCallbackRef->vm()); + env->CallVoidMethod(globalCallbackRef->object(), gTransactionConsumer.accept, + env->NewObject(gTransactionClassInfo.clazz, + gTransactionClassInfo.ctor, + reinterpret_cast<jlong>(t))); + }, + acquireSingleBuffer); } static void nativeStopContinuousSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr) { @@ -152,6 +150,11 @@ static void nativeStopContinuousSyncTransaction(JNIEnv* env, jclass clazz, jlong queue->stopContinuousSyncTransaction(); } +static void nativeClearSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr) { + sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr); + queue->clearSyncTransaction(); +} + static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width, jlong height, jint format) { sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr); @@ -207,8 +210,9 @@ static const JNINativeMethod gMethods[] = { {"nativeCreate", "(Ljava/lang/String;Z)J", (void*)nativeCreate}, {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface}, {"nativeDestroy", "(J)V", (void*)nativeDestroy}, - {"nativeSyncNextTransaction", "(JLjava/util/function/Consumer;Z)V", (void*)nativeSyncNextTransaction}, + {"nativeSyncNextTransaction", "(JLjava/util/function/Consumer;Z)Z", (void*)nativeSyncNextTransaction}, {"nativeStopContinuousSyncTransaction", "(J)V", (void*)nativeStopContinuousSyncTransaction}, + {"nativeClearSyncTransaction", "(J)V", (void*)nativeClearSyncTransaction}, {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate}, {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction}, {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum}, diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 8ba4eed8b34d..e1be0cd80bb6 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2481,36 +2481,31 @@ static jint android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject th if (jSurroundFormats == nullptr) { ALOGE("jSurroundFormats is NULL"); - return (jint)AUDIO_JAVA_BAD_VALUE; + return static_cast<jint>(AUDIO_JAVA_BAD_VALUE); } if (!env->IsInstanceOf(jSurroundFormats, gMapClass)) { ALOGE("getSurroundFormats not a map"); - return (jint)AUDIO_JAVA_BAD_VALUE; + return static_cast<jint>(AUDIO_JAVA_BAD_VALUE); } jint jStatus; unsigned int numSurroundFormats = 0; - audio_format_t *surroundFormats = nullptr; - bool *surroundFormatsEnabled = nullptr; - status_t status = AudioSystem::getSurroundFormats(&numSurroundFormats, surroundFormats, - surroundFormatsEnabled); + status_t status = AudioSystem::getSurroundFormats(&numSurroundFormats, nullptr, nullptr); if (status != NO_ERROR) { ALOGE_IF(status != NO_ERROR, "AudioSystem::getSurroundFormats error %d", status); - jStatus = nativeToJavaStatus(status); - goto exit; + return nativeToJavaStatus(status); } if (numSurroundFormats == 0) { - jStatus = (jint)AUDIO_JAVA_SUCCESS; - goto exit; + return static_cast<jint>(AUDIO_JAVA_SUCCESS); } - surroundFormats = (audio_format_t *)calloc(numSurroundFormats, sizeof(audio_format_t)); - surroundFormatsEnabled = (bool *)calloc(numSurroundFormats, sizeof(bool)); - status = AudioSystem::getSurroundFormats(&numSurroundFormats, surroundFormats, - surroundFormatsEnabled); + auto surroundFormats = std::make_unique<audio_format_t[]>(numSurroundFormats); + auto surroundFormatsEnabled = std::make_unique<bool[]>(numSurroundFormats); + status = AudioSystem::getSurroundFormats(&numSurroundFormats, &surroundFormats[0], + &surroundFormatsEnabled[0]); jStatus = nativeToJavaStatus(status); if (status != NO_ERROR) { ALOGE_IF(status != NO_ERROR, "AudioSystem::getSurroundFormats error %d", status); - goto exit; + return jStatus; } for (size_t i = 0; i < numSurroundFormats; i++) { int audioFormat = audioFormatFromNative(surroundFormats[i]); @@ -2526,9 +2521,6 @@ static jint android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject th env->DeleteLocalRef(enabled); } -exit: - free(surroundFormats); - free(surroundFormatsEnabled); return jStatus; } @@ -2538,31 +2530,28 @@ static jint android_media_AudioSystem_getReportedSurroundFormats(JNIEnv *env, jo if (jSurroundFormats == nullptr) { ALOGE("jSurroundFormats is NULL"); - return (jint)AUDIO_JAVA_BAD_VALUE; + return static_cast<jint>(AUDIO_JAVA_BAD_VALUE); } if (!env->IsInstanceOf(jSurroundFormats, gArrayListClass)) { ALOGE("jSurroundFormats not an arraylist"); - return (jint)AUDIO_JAVA_BAD_VALUE; + return static_cast<jint>(AUDIO_JAVA_BAD_VALUE); } jint jStatus; unsigned int numSurroundFormats = 0; - audio_format_t *surroundFormats = nullptr; - status_t status = AudioSystem::getReportedSurroundFormats(&numSurroundFormats, surroundFormats); + status_t status = AudioSystem::getReportedSurroundFormats(&numSurroundFormats, nullptr); if (status != NO_ERROR) { ALOGE_IF(status != NO_ERROR, "AudioSystem::getReportedSurroundFormats error %d", status); - jStatus = nativeToJavaStatus(status); - goto exit; + return nativeToJavaStatus(status); } if (numSurroundFormats == 0) { - jStatus = (jint)AUDIO_JAVA_SUCCESS; - goto exit; + return static_cast<jint>(AUDIO_JAVA_SUCCESS); } - surroundFormats = (audio_format_t *)calloc(numSurroundFormats, sizeof(audio_format_t)); - status = AudioSystem::getReportedSurroundFormats(&numSurroundFormats, surroundFormats); + auto surroundFormats = std::make_unique<audio_format_t[]>(numSurroundFormats); + status = AudioSystem::getReportedSurroundFormats(&numSurroundFormats, &surroundFormats[0]); jStatus = nativeToJavaStatus(status); if (status != NO_ERROR) { ALOGE_IF(status != NO_ERROR, "AudioSystem::getReportedSurroundFormats error %d", status); - goto exit; + return jStatus; } for (size_t i = 0; i < numSurroundFormats; i++) { int audioFormat = audioFormatFromNative(surroundFormats[i]); @@ -2576,8 +2565,6 @@ static jint android_media_AudioSystem_getReportedSurroundFormats(JNIEnv *env, jo env->DeleteLocalRef(surroundFormat); } -exit: - free(surroundFormats); return jStatus; } diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 9501c8d49e53..4f2bf4a4f6cb 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -1238,6 +1238,11 @@ jint android_os_Process_killProcessGroup(JNIEnv* env, jobject clazz, jint uid, j return killProcessGroup(uid, pid, SIGKILL); } +jint android_os_Process_sendSignalToProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid, + jint signal) { + return sendSignalToProcessGroup(uid, pid, signal); +} + void android_os_Process_removeAllProcessGroups(JNIEnv* env, jobject clazz) { return removeAllProcessGroups(); @@ -1305,6 +1310,7 @@ static const JNINativeMethod methods[] = { //{"setApplicationObject", "(Landroid/os/IBinder;)V", //(void*)android_os_Process_setApplicationObject}, {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup}, + {"sendSignalToProcessGroup", "(III)I", (void*)android_os_Process_sendSignalToProcessGroup}, {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups}, {"nativePidFdOpen", "(II)I", (void*)android_os_Process_nativePidFdOpen}, {"freezeCgroupUid", "(IZ)V", (void*)android_os_Process_freezeCgroupUID}, diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 98814bf602fc..6fcff990974a 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -368,73 +368,77 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, jobject inputEventObj; switch (inputEvent->getType()) { - case AINPUT_EVENT_TYPE_KEY: - if (kDebugDispatchCycle) { - ALOGD("channel '%s' ~ Received key event.", getInputChannelName().c_str()); - } - inputEventObj = android_view_KeyEvent_fromNative(env, - static_cast<KeyEvent*>(inputEvent)); - break; - - case AINPUT_EVENT_TYPE_MOTION: { - if (kDebugDispatchCycle) { - ALOGD("channel '%s' ~ Received motion event.", getInputChannelName().c_str()); - } - const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*inputEvent); - if ((motionEvent.getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) { - *outConsumedBatch = true; + case InputEventType::KEY: + if (kDebugDispatchCycle) { + ALOGD("channel '%s' ~ Received key event.", getInputChannelName().c_str()); + } + inputEventObj = + android_view_KeyEvent_fromNative(env, + static_cast<KeyEvent*>(inputEvent)); + break; + + case InputEventType::MOTION: { + if (kDebugDispatchCycle) { + ALOGD("channel '%s' ~ Received motion event.", + getInputChannelName().c_str()); + } + const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*inputEvent); + if ((motionEvent.getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) { + *outConsumedBatch = true; + } + inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent); + break; } - inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent); - break; - } - case AINPUT_EVENT_TYPE_FOCUS: { - FocusEvent* focusEvent = static_cast<FocusEvent*>(inputEvent); - if (kDebugDispatchCycle) { - ALOGD("channel '%s' ~ Received focus event: hasFocus=%s.", - getInputChannelName().c_str(), toString(focusEvent->getHasFocus())); + case InputEventType::FOCUS: { + FocusEvent* focusEvent = static_cast<FocusEvent*>(inputEvent); + if (kDebugDispatchCycle) { + ALOGD("channel '%s' ~ Received focus event: hasFocus=%s.", + getInputChannelName().c_str(), toString(focusEvent->getHasFocus())); + } + env->CallVoidMethod(receiverObj.get(), + gInputEventReceiverClassInfo.onFocusEvent, + jboolean(focusEvent->getHasFocus())); + finishInputEvent(seq, true /* handled */); + continue; } - env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onFocusEvent, - jboolean(focusEvent->getHasFocus())); - finishInputEvent(seq, true /* handled */); - continue; - } - case AINPUT_EVENT_TYPE_CAPTURE: { - const CaptureEvent* captureEvent = static_cast<CaptureEvent*>(inputEvent); - if (kDebugDispatchCycle) { - ALOGD("channel '%s' ~ Received capture event: pointerCaptureEnabled=%s", - getInputChannelName().c_str(), - toString(captureEvent->getPointerCaptureEnabled())); + case InputEventType::CAPTURE: { + const CaptureEvent* captureEvent = static_cast<CaptureEvent*>(inputEvent); + if (kDebugDispatchCycle) { + ALOGD("channel '%s' ~ Received capture event: pointerCaptureEnabled=%s", + getInputChannelName().c_str(), + toString(captureEvent->getPointerCaptureEnabled())); + } + env->CallVoidMethod(receiverObj.get(), + gInputEventReceiverClassInfo.onPointerCaptureEvent, + jboolean(captureEvent->getPointerCaptureEnabled())); + finishInputEvent(seq, true /* handled */); + continue; } - env->CallVoidMethod(receiverObj.get(), - gInputEventReceiverClassInfo.onPointerCaptureEvent, - jboolean(captureEvent->getPointerCaptureEnabled())); - finishInputEvent(seq, true /* handled */); - continue; - } - case AINPUT_EVENT_TYPE_DRAG: { - const DragEvent* dragEvent = static_cast<DragEvent*>(inputEvent); - if (kDebugDispatchCycle) { - ALOGD("channel '%s' ~ Received drag event: isExiting=%s", - getInputChannelName().c_str(), toString(dragEvent->isExiting())); + case InputEventType::DRAG: { + const DragEvent* dragEvent = static_cast<DragEvent*>(inputEvent); + if (kDebugDispatchCycle) { + ALOGD("channel '%s' ~ Received drag event: isExiting=%s", + getInputChannelName().c_str(), toString(dragEvent->isExiting())); + } + env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onDragEvent, + jboolean(dragEvent->isExiting()), dragEvent->getX(), + dragEvent->getY()); + finishInputEvent(seq, true /* handled */); + continue; } - env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onDragEvent, - jboolean(dragEvent->isExiting()), dragEvent->getX(), - dragEvent->getY()); - finishInputEvent(seq, true /* handled */); - continue; - } - case AINPUT_EVENT_TYPE_TOUCH_MODE: { - const TouchModeEvent* touchModeEvent = static_cast<TouchModeEvent*>(inputEvent); - if (kDebugDispatchCycle) { - ALOGD("channel '%s' ~ Received touch mode event: isInTouchMode=%s", - getInputChannelName().c_str(), toString(touchModeEvent->isInTouchMode())); + case InputEventType::TOUCH_MODE: { + const TouchModeEvent* touchModeEvent = static_cast<TouchModeEvent*>(inputEvent); + if (kDebugDispatchCycle) { + ALOGD("channel '%s' ~ Received touch mode event: isInTouchMode=%s", + getInputChannelName().c_str(), + toString(touchModeEvent->isInTouchMode())); + } + env->CallVoidMethod(receiverObj.get(), + gInputEventReceiverClassInfo.onTouchModeChanged, + jboolean(touchModeEvent->isInTouchMode())); + finishInputEvent(seq, true /* handled */); + continue; } - env->CallVoidMethod(receiverObj.get(), - gInputEventReceiverClassInfo.onTouchModeChanged, - jboolean(touchModeEvent->isInTouchMode())); - finishInputEvent(seq, true /* handled */); - continue; - } default: assert(false); // InputConsumer should prevent this from ever happening diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp index 2f9df1fbe9d0..2c4966eaf408 100644 --- a/core/jni/android_view_InputQueue.cpp +++ b/core/jni/android_view_InputQueue.cpp @@ -114,7 +114,7 @@ status_t InputQueue::getEvent(InputEvent** outEvent) { } bool InputQueue::preDispatchEvent(InputEvent* e) { - if (e->getType() == AINPUT_EVENT_TYPE_KEY) { + if (e->getType() == InputEventType::KEY) { KeyEvent* keyEvent = static_cast<KeyEvent*>(e); if (keyEvent->getFlags() & AKEY_EVENT_FLAG_PREDISPATCH) { finishEvent(e, false); diff --git a/core/jni/com_android_internal_expresslog_Utils.cpp b/core/jni/com_android_internal_expresslog_Utils.cpp deleted file mode 100644 index d33a7bda27f7..000000000000 --- a/core/jni/com_android_internal_expresslog_Utils.cpp +++ /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. - */ - -#include <nativehelper/JNIHelp.h> -#include <utils/hash/farmhash.h> - -#include "core_jni_helpers.h" - -// ---------------------------------------------------------------------------- -// JNI Glue -// ---------------------------------------------------------------------------- - -static jclass g_stringClass = nullptr; - -/** - * Class: com_android_internal_expresslog_Utils - * Method: hashString - * Signature: (Ljava/lang/String;)J - */ -static jlong hashString(JNIEnv* env, jclass /*class*/, jstring metricNameObj) { - ScopedUtfChars name(env, metricNameObj); - if (name.c_str() == nullptr) { - return 0; - } - - return static_cast<jlong>(farmhash::Fingerprint64(name.c_str(), name.size())); -} - -static const JNINativeMethod g_methods[] = { - {"hashString", "(Ljava/lang/String;)J", (void*)hashString}, -}; - -static const char* const kUtilsPathName = "com/android/internal/expresslog/Utils"; - -namespace android { - -int register_com_android_internal_expresslog_Utils(JNIEnv* env) { - jclass stringClass = FindClassOrDie(env, "java/lang/String"); - g_stringClass = MakeGlobalRefOrDie(env, stringClass); - - return RegisterMethodsOrDie(env, kUtilsPathName, g_methods, NELEM(g_methods)); -} - -} // namespace android diff --git a/core/proto/android/app/notification_channel.proto b/core/proto/android/app/notification_channel.proto index c835b90ec969..d79de5cc4b2e 100644 --- a/core/proto/android/app/notification_channel.proto +++ b/core/proto/android/app/notification_channel.proto @@ -56,7 +56,9 @@ message NotificationChannelProto { optional android.media.AudioAttributesProto audio_attributes = 16; // If this is a blockable system notification channel. optional bool is_blockable_system = 17; - optional bool fg_service_shown = 18; + // On U+, this field will be true if either a foreground service or a user initiated job is + // shown whereas on T-, this field will only be true if a foreground service is shown. + optional bool user_visible_task_shown = 18; // Default is true. // Allows the notifications to appear outside of the shade in floating windows optional bool allow_app_overlay = 19; diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index ed612a05e6b5..025a57d0e334 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -1035,6 +1035,7 @@ message AppsExitInfoProto { optional int32 uid = 1; repeated .android.app.ApplicationExitInfoProto app_exit_info = 2; + repeated .android.app.ApplicationExitInfoProto app_recoverable_crash = 3; } repeated User users = 2; } diff --git a/core/proto/android/server/windowmanagertransitiontrace.proto b/core/proto/android/server/windowmanagertransitiontrace.proto index 9e53a9162429..25985ebc551a 100644 --- a/core/proto/android/server/windowmanagertransitiontrace.proto +++ b/core/proto/android/server/windowmanagertransitiontrace.proto @@ -23,7 +23,7 @@ import "frameworks/base/core/proto/android/server/windowmanagerservice.proto"; option java_multiple_files = true; /* Represents a file full of transition entries. - Encoded, it should start with 0x9 0x57 0x49 0x4e 0x54 0x52 0x41 0x43 0x45 (.TRNTRACE), such + Encoded, it should start with 0x09 0x54 0x52 0x4E 0x54 0x52 0x41 0x43 0x45 (TRNTRACE), such that it can be easily identified. */ message TransitionTraceProto { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 78d39236b392..05b38a562e29 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1746,37 +1746,6 @@ android:protectionLevel="dangerous" android:permissionFlags="hardRestricted" /> - <!-- @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 - @hide - --> - <permission android:name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE" - android:permissionGroup="android.permission-group.UNDEFINED" - android:label="@string/permlab_bodySensorsWristTemperature" - android:description="@string/permdesc_bodySensorsWristTemperature" - android:backgroundPermission="android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND" - android:protectionLevel="dangerous" /> - - <!-- @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. - <p class="note"><strong>Note: </strong> This permission is for Wear OS only. - <p>Protection level: dangerous - - <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" - android:label="@string/permlab_bodySensors_wristTemperature_background" - android:description="@string/permdesc_bodySensors_wristTemperature_background" - android:protectionLevel="dangerous" - android:permissionFlags="hardRestricted" /> - <!-- Allows an app to use fingerprint hardware. <p>Protection level: normal @deprecated Applications should request {@link diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3ff63519572f..5544701d9325 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -534,8 +534,10 @@ <!-- If this is true, long press on power button will be available from the non-interactive state --> <bool name="config_supportLongPressPowerWhenNonInteractive">false</bool> - <!-- If this is true, then keep dreaming when undocking. --> - <bool name="config_keepDreamingWhenUndocking">false</bool> + <!-- If this is true, then keep dreaming when unplugging. + This config was formerly known as config_keepDreamingWhenUndocking. + It has been updated to affect other plug types. --> + <bool name="config_keepDreamingWhenUnplugging">false</bool> <!-- The timeout (in ms) to wait before attempting to reconnect to the dream overlay service if it becomes disconnected --> @@ -1373,6 +1375,9 @@ <!-- Number of notifications to keep in the notification service historical archive --> <integer name="config_notificationServiceArchiveSize">100</integer> + <!-- List of packages that will be able to use full screen intent in notifications by default --> + <string-array name="config_useFullScreenIntentPackages" translatable="false" /> + <!-- Allow the menu hard key to be disabled in LockScreen on some devices --> <bool name="config_disableMenuKeyInLockScreen">false</bool> @@ -4301,8 +4306,12 @@ This package must be trusted, as it has the permissions to control other applications on the device. Example: "com.android.wellbeing" + + Note: This config is deprecated, please use config_systemWellbeing instead. --> - <string name="config_defaultWellbeingPackage" translatable="false"></string> + <string name="config_defaultWellbeingPackage" translatable="false"> + @string/config_systemWellbeing + </string> <!-- The component name for the default system attention service. This service must be trusted, as it can be activated without explicit consent of the user. @@ -6067,6 +6076,12 @@ <!-- Wear OS: the name of the main activity of the device's sysui. --> <string name="config_wearSysUiMainActivity" translatable="false"/> + <!-- Wear OS: the name of the package containing the Media Controls Activity. --> + <string name="config_wearMediaControlsPackage" translatable="false"/> + + <!-- Wear OS: the name of the package containing the Media Sessions APK. --> + <string name="config_wearMediaSessionsPackage" translatable="false"/> + <bool name="config_secondaryBuiltInDisplayIsRound">@bool/config_windowIsRound</bool> <!-- The display round config for each display in a multi-display device. --> diff --git a/core/res/res/values/public-final.xml b/core/res/res/values/public-final.xml index 85325fec7277..daa0f553f47a 100644 --- a/core/res/res/values/public-final.xml +++ b/core/res/res/values/public-final.xml @@ -3402,4 +3402,343 @@ <!-- @hide @SystemApi --> <public type="bool" name="config_enableQrCodeScannerOnLockScreen" id="0x01110008" /> + <!-- =============================================================== + Resources added in version U of the platform + + NOTE: After this version of the platform is forked, changes cannot be made to the root + branch's groups for that release. Only merge changes to the forked platform branch. + =============================================================== --> + <eat-comment/> + + <staging-public-group-final type="attr" first-id="0x01ce0000"> + <public name="handwritingBoundsOffsetLeft" /> + <public name="handwritingBoundsOffsetTop" /> + <public name="handwritingBoundsOffsetRight" /> + <public name="handwritingBoundsOffsetBottom" /> + <public name="accessibilityDataSensitive" /> + <public name="enableTextStylingShortcuts" /> + <public name="requiredDisplayCategory"/> + <public name="removed_maxConcurrentSessionsCount" /> + <public name="visualQueryDetectionService" /> + <public name="physicalKeyboardHintLanguageTag" /> + <public name="physicalKeyboardHintLayoutType" /> + <public name="allowSharedIsolatedProcess" /> + <public name="keyboardLocale" /> + <public name="keyboardLayoutType" /> + <public name="allowUpdateOwnership" /> + <public name="isCredential"/> + <public name="searchResultHighlightColor" /> + <public name="focusedSearchResultHighlightColor" /> + <public name="stylusHandwritingSettingsActivity" /> + <public name="windowNoMoveAnimation" /> + <public name="settingsSubtitle" /> + <public name="capability" /> + </staging-public-group-final> + + <public type="attr" name="handwritingBoundsOffsetLeft" id="0x01010673" /> + <public type="attr" name="handwritingBoundsOffsetTop" id="0x01010674" /> + <public type="attr" name="handwritingBoundsOffsetRight" id="0x01010675" /> + <public type="attr" name="handwritingBoundsOffsetBottom" id="0x01010676" /> + <public type="attr" name="accessibilityDataSensitive" id="0x01010677" /> + <public type="attr" name="enableTextStylingShortcuts" id="0x01010678" /> + <public type="attr" name="requiredDisplayCategory" id="0x01010679" /> + <public type="attr" name="visualQueryDetectionService" id="0x0101067a" /> + <public type="attr" name="physicalKeyboardHintLanguageTag" id="0x0101067b" /> + <public type="attr" name="physicalKeyboardHintLayoutType" id="0x0101067c" /> + <public type="attr" name="allowSharedIsolatedProcess" id="0x0101067d" /> + <public type="attr" name="keyboardLocale" id="0x0101067e" /> + <public type="attr" name="keyboardLayoutType" id="0x0101067f" /> + <public type="attr" name="allowUpdateOwnership" id="0x01010680" /> + <public type="attr" name="isCredential" id="0x01010681" /> + <public type="attr" name="searchResultHighlightColor" id="0x01010682" /> + <public type="attr" name="focusedSearchResultHighlightColor" id="0x01010683" /> + <public type="attr" name="stylusHandwritingSettingsActivity" id="0x01010684" /> + <public type="attr" name="windowNoMoveAnimation" id="0x01010685" /> + <public type="attr" name="settingsSubtitle" id="0x01010686" /> + <public type="attr" name="capability" id="0x01010687" /> + + <staging-public-group-final type="id" first-id="0x01cd0000"> + <public name="bold" /> + <public name="italic" /> + <public name="underline" /> + <public name="accessibilityActionScrollInDirection" /> + </staging-public-group-final> + + <public type="id" name="bold" id="0x0102005b" /> + <public type="id" name="italic" id="0x0102005c" /> + <public type="id" name="underline" id="0x0102005d" /> + <public type="id" name="accessibilityActionScrollInDirection" id="0x0102005e" /> + + <staging-public-group-final type="string" first-id="0x01cb0000"> + <!-- @hide @SystemApi --> + <public name="config_systemWearHealthService" /> + <!-- @hide @SystemApi --> + <public name="config_defaultNotes" /> + <!-- @hide @SystemApi --> + <public name="config_systemFinancedDeviceController" /> + <!-- @hide @SystemApi --> + <public name="config_systemCallStreaming" /> + </staging-public-group-final> + + <!-- @hide @SystemApi --> + <public type="string" name="config_systemWearHealthService" id="0x01040044" /> + <!-- @hide @SystemApi --> + <public type="string" name="config_defaultNotes" id="0x01040045" /> + <!-- @hide @SystemApi --> + <public type="string" name="config_systemFinancedDeviceController" id="0x01040046" /> + <!-- @hide @SystemApi --> + <public type="string" name="config_systemCallStreaming" id="0x01040047" /> + + <staging-public-group-final type="dimen" first-id="0x01ca0000"> + <!-- @hide @SystemApi --> + <public name="config_viewConfigurationHandwritingGestureLineMargin" /> + </staging-public-group-final> + + <!-- @hide @SystemApi --> + <public type="dimen" name="config_viewConfigurationHandwritingGestureLineMargin" id="0x0105000a" /> + + <staging-public-group-final type="color" first-id="0x01c90000"> + <public name="system_primary_container_light" /> + <public name="system_on_primary_container_light" /> + <public name="system_primary_light" /> + <public name="system_on_primary_light" /> + <public name="system_secondary_container_light" /> + <public name="system_on_secondary_container_light" /> + <public name="system_secondary_light" /> + <public name="system_on_secondary_light" /> + <public name="system_tertiary_container_light" /> + <public name="system_on_tertiary_container_light" /> + <public name="system_tertiary_light" /> + <public name="system_on_tertiary_light" /> + <public name="system_background_light" /> + <public name="system_on_background_light" /> + <public name="system_surface_light" /> + <public name="system_on_surface_light" /> + <public name="system_surface_container_low_light" /> + <public name="system_surface_container_lowest_light" /> + <public name="system_surface_container_light" /> + <public name="system_surface_container_high_light" /> + <public name="system_surface_container_highest_light" /> + <public name="system_surface_bright_light" /> + <public name="system_surface_dim_light" /> + <public name="system_surface_variant_light" /> + <public name="system_on_surface_variant_light" /> + <public name="system_outline_light" /> + <public name="system_error_light" /> + <public name="system_on_error_light" /> + <public name="system_error_container_light" /> + <public name="system_on_error_container_light" /> + <public name="removed_system_primary_fixed_light" /> + <public name="removed_system_primary_fixed_dim_light" /> + <public name="removed_system_on_primary_fixed_light" /> + <public name="removed_system_on_primary_fixed_variant_light" /> + <public name="removed_system_secondary_fixed_light" /> + <public name="removed_system_secondary_fixed_dim_light" /> + <public name="removed_system_on_secondary_fixed_light" /> + <public name="removed_system_on_secondary_fixed_variant_light" /> + <public name="removed_system_tertiary_fixed_light" /> + <public name="removed_system_tertiary_fixed_dim_light" /> + <public name="removed_system_on_tertiary_fixed_light" /> + <public name="removed_system_on_tertiary_fixed_variant_light" /> + <public name="system_control_activated_light" /> + <public name="system_control_normal_light" /> + <public name="system_control_highlight_light" /> + <public name="system_text_primary_inverse_light" /> + <public name="system_text_secondary_and_tertiary_inverse_light" /> + <public name="system_text_primary_inverse_disable_only_light" /> + <public name="system_text_secondary_and_tertiary_inverse_disabled_light" /> + <public name="system_text_hint_inverse_light" /> + <public name="system_palette_key_color_primary_light" /> + <public name="system_palette_key_color_secondary_light" /> + <public name="system_palette_key_color_tertiary_light" /> + <public name="system_palette_key_color_neutral_light" /> + <public name="system_palette_key_color_neutral_variant_light" /> + <public name="system_primary_container_dark"/> + <public name="system_on_primary_container_dark"/> + <public name="system_primary_dark"/> + <public name="system_on_primary_dark"/> + <public name="system_secondary_container_dark"/> + <public name="system_on_secondary_container_dark"/> + <public name="system_secondary_dark"/> + <public name="system_on_secondary_dark"/> + <public name="system_tertiary_container_dark"/> + <public name="system_on_tertiary_container_dark"/> + <public name="system_tertiary_dark"/> + <public name="system_on_tertiary_dark"/> + <public name="system_background_dark"/> + <public name="system_on_background_dark"/> + <public name="system_surface_dark"/> + <public name="system_on_surface_dark"/> + <public name="system_surface_container_low_dark"/> + <public name="system_surface_container_lowest_dark"/> + <public name="system_surface_container_dark"/> + <public name="system_surface_container_high_dark"/> + <public name="system_surface_container_highest_dark"/> + <public name="system_surface_bright_dark"/> + <public name="system_surface_dim_dark"/> + <public name="system_surface_variant_dark"/> + <public name="system_on_surface_variant_dark"/> + <public name="system_outline_dark"/> + <public name="system_error_dark"/> + <public name="system_on_error_dark"/> + <public name="system_error_container_dark"/> + <public name="system_on_error_container_dark"/> + <public name="removed_system_primary_fixed_dark"/> + <public name="removed_system_primary_fixed_dim_dark"/> + <public name="removed_system_on_primary_fixed_dark"/> + <public name="removed_system_on_primary_fixed_variant_dark"/> + <public name="removed_system_secondary_fixed_dark"/> + <public name="removed_system_secondary_fixed_dim_dark"/> + <public name="removed_system_on_secondary_fixed_dark"/> + <public name="removed_system_on_secondary_fixed_variant_dark"/> + <public name="removed_system_tertiary_fixed_dark"/> + <public name="removed_system_tertiary_fixed_dim_dark"/> + <public name="removed_system_on_tertiary_fixed_dark"/> + <public name="removed_system_on_tertiary_fixed_variant_dark"/> + <public name="system_control_activated_dark"/> + <public name="system_control_normal_dark"/> + <public name="system_control_highlight_dark"/> + <public name="system_text_primary_inverse_dark"/> + <public name="system_text_secondary_and_tertiary_inverse_dark"/> + <public name="system_text_primary_inverse_disable_only_dark"/> + <public name="system_text_secondary_and_tertiary_inverse_disabled_dark"/> + <public name="system_text_hint_inverse_dark"/> + <public name="system_palette_key_color_primary_dark"/> + <public name="system_palette_key_color_secondary_dark"/> + <public name="system_palette_key_color_tertiary_dark"/> + <public name="system_palette_key_color_neutral_dark"/> + <public name="system_palette_key_color_neutral_variant_dark"/> + <public name="system_primary_fixed" /> + <public name="system_primary_fixed_dim" /> + <public name="system_on_primary_fixed" /> + <public name="system_on_primary_fixed_variant" /> + <public name="system_secondary_fixed" /> + <public name="system_secondary_fixed_dim" /> + <public name="system_on_secondary_fixed" /> + <public name="system_on_secondary_fixed_variant" /> + <public name="system_tertiary_fixed" /> + <public name="system_tertiary_fixed_dim" /> + <public name="system_on_tertiary_fixed" /> + <public name="system_on_tertiary_fixed_variant" /> + <public name="system_outline_variant_light" /> + <public name="system_outline_variant_dark" /> + </staging-public-group-final> + + <public type="color" name="system_primary_container_light" id="0x0106005e" /> + <public type="color" name="system_on_primary_container_light" id="0x0106005f" /> + <public type="color" name="system_primary_light" id="0x01060060" /> + <public type="color" name="system_on_primary_light" id="0x01060061" /> + <public type="color" name="system_secondary_container_light" id="0x01060062" /> + <public type="color" name="system_on_secondary_container_light" id="0x01060063" /> + <public type="color" name="system_secondary_light" id="0x01060064" /> + <public type="color" name="system_on_secondary_light" id="0x01060065" /> + <public type="color" name="system_tertiary_container_light" id="0x01060066" /> + <public type="color" name="system_on_tertiary_container_light" id="0x01060067" /> + <public type="color" name="system_tertiary_light" id="0x01060068" /> + <public type="color" name="system_on_tertiary_light" id="0x01060069" /> + <public type="color" name="system_background_light" id="0x0106006a" /> + <public type="color" name="system_on_background_light" id="0x0106006b" /> + <public type="color" name="system_surface_light" id="0x0106006c" /> + <public type="color" name="system_on_surface_light" id="0x0106006d" /> + <public type="color" name="system_surface_container_low_light" id="0x0106006e" /> + <public type="color" name="system_surface_container_lowest_light" id="0x0106006f" /> + <public type="color" name="system_surface_container_light" id="0x01060070" /> + <public type="color" name="system_surface_container_high_light" id="0x01060071" /> + <public type="color" name="system_surface_container_highest_light" id="0x01060072" /> + <public type="color" name="system_surface_bright_light" id="0x01060073" /> + <public type="color" name="system_surface_dim_light" id="0x01060074" /> + <public type="color" name="system_surface_variant_light" id="0x01060075" /> + <public type="color" name="system_on_surface_variant_light" id="0x01060076" /> + <public type="color" name="system_outline_light" id="0x01060077" /> + <public type="color" name="system_error_light" id="0x01060078" /> + <public type="color" name="system_on_error_light" id="0x01060079" /> + <public type="color" name="system_error_container_light" id="0x0106007a" /> + <public type="color" name="system_on_error_container_light" id="0x0106007b" /> + <public type="color" name="system_control_activated_light" id="0x0106007c" /> + <public type="color" name="system_control_normal_light" id="0x0106007d" /> + <public type="color" name="system_control_highlight_light" id="0x0106007e" /> + <public type="color" name="system_text_primary_inverse_light" id="0x0106007f" /> + <public type="color" name="system_text_secondary_and_tertiary_inverse_light" id="0x01060080" /> + <public type="color" name="system_text_primary_inverse_disable_only_light" id="0x01060081" /> + <public type="color" name="system_text_secondary_and_tertiary_inverse_disabled_light" id="0x01060082" /> + <public type="color" name="system_text_hint_inverse_light" id="0x01060083" /> + <public type="color" name="system_palette_key_color_primary_light" id="0x01060084" /> + <public type="color" name="system_palette_key_color_secondary_light" id="0x01060085" /> + <public type="color" name="system_palette_key_color_tertiary_light" id="0x01060086" /> + <public type="color" name="system_palette_key_color_neutral_light" id="0x01060087" /> + <public type="color" name="system_palette_key_color_neutral_variant_light" id="0x01060088" /> + <public type="color" name="system_primary_container_dark" id="0x01060089" /> + <public type="color" name="system_on_primary_container_dark" id="0x0106008a" /> + <public type="color" name="system_primary_dark" id="0x0106008b" /> + <public type="color" name="system_on_primary_dark" id="0x0106008c" /> + <public type="color" name="system_secondary_container_dark" id="0x0106008d" /> + <public type="color" name="system_on_secondary_container_dark" id="0x0106008e" /> + <public type="color" name="system_secondary_dark" id="0x0106008f" /> + <public type="color" name="system_on_secondary_dark" id="0x01060090" /> + <public type="color" name="system_tertiary_container_dark" id="0x01060091" /> + <public type="color" name="system_on_tertiary_container_dark" id="0x01060092" /> + <public type="color" name="system_tertiary_dark" id="0x01060093" /> + <public type="color" name="system_on_tertiary_dark" id="0x01060094" /> + <public type="color" name="system_background_dark" id="0x01060095" /> + <public type="color" name="system_on_background_dark" id="0x01060096" /> + <public type="color" name="system_surface_dark" id="0x01060097" /> + <public type="color" name="system_on_surface_dark" id="0x01060098" /> + <public type="color" name="system_surface_container_low_dark" id="0x01060099" /> + <public type="color" name="system_surface_container_lowest_dark" id="0x0106009a" /> + <public type="color" name="system_surface_container_dark" id="0x0106009b" /> + <public type="color" name="system_surface_container_high_dark" id="0x0106009c" /> + <public type="color" name="system_surface_container_highest_dark" id="0x0106009d" /> + <public type="color" name="system_surface_bright_dark" id="0x0106009e" /> + <public type="color" name="system_surface_dim_dark" id="0x0106009f" /> + <public type="color" name="system_surface_variant_dark" id="0x010600a0" /> + <public type="color" name="system_on_surface_variant_dark" id="0x010600a1" /> + <public type="color" name="system_outline_dark" id="0x010600a2" /> + <public type="color" name="system_error_dark" id="0x010600a3" /> + <public type="color" name="system_on_error_dark" id="0x010600a4" /> + <public type="color" name="system_error_container_dark" id="0x010600a5" /> + <public type="color" name="system_on_error_container_dark" id="0x010600a6" /> + <public type="color" name="system_control_activated_dark" id="0x010600a7" /> + <public type="color" name="system_control_normal_dark" id="0x010600a8" /> + <public type="color" name="system_control_highlight_dark" id="0x010600a9" /> + <public type="color" name="system_text_primary_inverse_dark" id="0x010600aa" /> + <public type="color" name="system_text_secondary_and_tertiary_inverse_dark" id="0x010600ab" /> + <public type="color" name="system_text_primary_inverse_disable_only_dark" id="0x010600ac" /> + <public type="color" name="system_text_secondary_and_tertiary_inverse_disabled_dark" id="0x010600ad" /> + <public type="color" name="system_text_hint_inverse_dark" id="0x010600ae" /> + <public type="color" name="system_palette_key_color_primary_dark" id="0x010600af" /> + <public type="color" name="system_palette_key_color_secondary_dark" id="0x010600b0" /> + <public type="color" name="system_palette_key_color_tertiary_dark" id="0x010600b1" /> + <public type="color" name="system_palette_key_color_neutral_dark" id="0x010600b2" /> + <public type="color" name="system_palette_key_color_neutral_variant_dark" id="0x010600b3" /> + <public type="color" name="system_primary_fixed" id="0x010600b4" /> + <public type="color" name="system_primary_fixed_dim" id="0x010600b5" /> + <public type="color" name="system_on_primary_fixed" id="0x010600b6" /> + <public type="color" name="system_on_primary_fixed_variant" id="0x010600b7" /> + <public type="color" name="system_secondary_fixed" id="0x010600b8" /> + <public type="color" name="system_secondary_fixed_dim" id="0x010600b9" /> + <public type="color" name="system_on_secondary_fixed" id="0x010600ba" /> + <public type="color" name="system_on_secondary_fixed_variant" id="0x010600bb" /> + <public type="color" name="system_tertiary_fixed" id="0x010600bc" /> + <public type="color" name="system_tertiary_fixed_dim" id="0x010600bd" /> + <public type="color" name="system_on_tertiary_fixed" id="0x010600be" /> + <public type="color" name="system_on_tertiary_fixed_variant" id="0x010600bf" /> + <public type="color" name="system_outline_variant_light" id="0x010600c0" /> + <public type="color" name="system_outline_variant_dark" id="0x010600c1" /> + + <staging-public-group-final type="bool" first-id="0x01be0000"> + <!-- @hide @SystemApi --> + <public name="config_safetyProtectionEnabled" /> + <!-- @hide @SystemApi --> + <public name="config_enableDefaultNotes" /> + <!-- @hide @SystemApi --> + <public name="config_enableDefaultNotesForWorkProfile" /> + </staging-public-group-final> + + <!-- @hide @SystemApi --> + <public type="bool" name="config_safetyProtectionEnabled" id="0x01110009" /> + <!-- @hide @SystemApi --> + <public type="bool" name="config_enableDefaultNotes" id="0x0111000a" /> + <!-- @hide @SystemApi --> + <public type="bool" name="config_enableDefaultNotesForWorkProfile" id="0x0111000b" /> + </resources> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index 9cbf3b679851..49a19407e59f 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -102,231 +102,65 @@ <resources> <!-- =============================================================== - Resources added in version U of the platform + Resources added in version NEXT of the platform NOTE: After this version of the platform is forked, changes cannot be made to the root branch's groups for that release. Only merge changes to the forked platform branch. =============================================================== --> <eat-comment/> - <staging-public-group type="attr" first-id="0x01ce0000"> - <public name="handwritingBoundsOffsetLeft" /> - <public name="handwritingBoundsOffsetTop" /> - <public name="handwritingBoundsOffsetRight" /> - <public name="handwritingBoundsOffsetBottom" /> - <public name="accessibilityDataSensitive" /> - <public name="enableTextStylingShortcuts" /> - <public name="requiredDisplayCategory"/> - <public name="removed_maxConcurrentSessionsCount" /> - <public name="visualQueryDetectionService" /> - <public name="physicalKeyboardHintLanguageTag" /> - <public name="physicalKeyboardHintLayoutType" /> - <public name="allowSharedIsolatedProcess" /> - <public name="keyboardLocale" /> - <public name="keyboardLayoutType" /> - <public name="allowUpdateOwnership" /> - <public name="isCredential"/> - <public name="searchResultHighlightColor" /> - <public name="focusedSearchResultHighlightColor" /> - <public name="stylusHandwritingSettingsActivity" /> - <public name="windowNoMoveAnimation" /> - <public name="settingsSubtitle" /> - <public name="capability" /> + <staging-public-group type="attr" first-id="0x01bd0000"> </staging-public-group> - <staging-public-group type="id" first-id="0x01cd0000"> - <public name="bold" /> - <public name="italic" /> - <public name="underline" /> - <public name="accessibilityActionScrollInDirection" /> + <staging-public-group type="id" first-id="0x01bc0000"> </staging-public-group> - <staging-public-group type="style" first-id="0x01cc0000"> + <staging-public-group type="style" first-id="0x01bb0000"> </staging-public-group> - <staging-public-group type="string" first-id="0x01cb0000"> - <!-- @hide @SystemApi --> - <public name="config_systemWearHealthService" /> - <!-- @hide @SystemApi --> - <public name="config_defaultNotes" /> - <!-- @hide @SystemApi --> - <public name="config_systemFinancedDeviceController" /> - <!-- @hide @SystemApi --> - <public name="config_systemCallStreaming" /> + <staging-public-group type="string" first-id="0x01ba0000"> </staging-public-group> - <staging-public-group type="dimen" first-id="0x01ca0000"> - <!-- @hide @SystemApi --> - <public name="config_viewConfigurationHandwritingGestureLineMargin" /> + <staging-public-group type="dimen" first-id="0x01b90000"> </staging-public-group> - <staging-public-group type="color" first-id="0x01c90000"> - <public name="system_primary_container_light" /> - <public name="system_on_primary_container_light" /> - <public name="system_primary_light" /> - <public name="system_on_primary_light" /> - <public name="system_secondary_container_light" /> - <public name="system_on_secondary_container_light" /> - <public name="system_secondary_light" /> - <public name="system_on_secondary_light" /> - <public name="system_tertiary_container_light" /> - <public name="system_on_tertiary_container_light" /> - <public name="system_tertiary_light" /> - <public name="system_on_tertiary_light" /> - <public name="system_background_light" /> - <public name="system_on_background_light" /> - <public name="system_surface_light" /> - <public name="system_on_surface_light" /> - <public name="system_surface_container_low_light" /> - <public name="system_surface_container_lowest_light" /> - <public name="system_surface_container_light" /> - <public name="system_surface_container_high_light" /> - <public name="system_surface_container_highest_light" /> - <public name="system_surface_bright_light" /> - <public name="system_surface_dim_light" /> - <public name="system_surface_variant_light" /> - <public name="system_on_surface_variant_light" /> - <public name="system_outline_light" /> - <public name="system_error_light" /> - <public name="system_on_error_light" /> - <public name="system_error_container_light" /> - <public name="system_on_error_container_light" /> - <public name="removed_system_primary_fixed_light" /> - <public name="removed_system_primary_fixed_dim_light" /> - <public name="removed_system_on_primary_fixed_light" /> - <public name="removed_system_on_primary_fixed_variant_light" /> - <public name="removed_system_secondary_fixed_light" /> - <public name="removed_system_secondary_fixed_dim_light" /> - <public name="removed_system_on_secondary_fixed_light" /> - <public name="removed_system_on_secondary_fixed_variant_light" /> - <public name="removed_system_tertiary_fixed_light" /> - <public name="removed_system_tertiary_fixed_dim_light" /> - <public name="removed_system_on_tertiary_fixed_light" /> - <public name="removed_system_on_tertiary_fixed_variant_light" /> - <public name="system_control_activated_light" /> - <public name="system_control_normal_light" /> - <public name="system_control_highlight_light" /> - <public name="system_text_primary_inverse_light" /> - <public name="system_text_secondary_and_tertiary_inverse_light" /> - <public name="system_text_primary_inverse_disable_only_light" /> - <public name="system_text_secondary_and_tertiary_inverse_disabled_light" /> - <public name="system_text_hint_inverse_light" /> - <public name="system_palette_key_color_primary_light" /> - <public name="system_palette_key_color_secondary_light" /> - <public name="system_palette_key_color_tertiary_light" /> - <public name="system_palette_key_color_neutral_light" /> - <public name="system_palette_key_color_neutral_variant_light" /> - <public name="system_primary_container_dark"/> - <public name="system_on_primary_container_dark"/> - <public name="system_primary_dark"/> - <public name="system_on_primary_dark"/> - <public name="system_secondary_container_dark"/> - <public name="system_on_secondary_container_dark"/> - <public name="system_secondary_dark"/> - <public name="system_on_secondary_dark"/> - <public name="system_tertiary_container_dark"/> - <public name="system_on_tertiary_container_dark"/> - <public name="system_tertiary_dark"/> - <public name="system_on_tertiary_dark"/> - <public name="system_background_dark"/> - <public name="system_on_background_dark"/> - <public name="system_surface_dark"/> - <public name="system_on_surface_dark"/> - <public name="system_surface_container_low_dark"/> - <public name="system_surface_container_lowest_dark"/> - <public name="system_surface_container_dark"/> - <public name="system_surface_container_high_dark"/> - <public name="system_surface_container_highest_dark"/> - <public name="system_surface_bright_dark"/> - <public name="system_surface_dim_dark"/> - <public name="system_surface_variant_dark"/> - <public name="system_on_surface_variant_dark"/> - <public name="system_outline_dark"/> - <public name="system_error_dark"/> - <public name="system_on_error_dark"/> - <public name="system_error_container_dark"/> - <public name="system_on_error_container_dark"/> - <public name="removed_system_primary_fixed_dark"/> - <public name="removed_system_primary_fixed_dim_dark"/> - <public name="removed_system_on_primary_fixed_dark"/> - <public name="removed_system_on_primary_fixed_variant_dark"/> - <public name="removed_system_secondary_fixed_dark"/> - <public name="removed_system_secondary_fixed_dim_dark"/> - <public name="removed_system_on_secondary_fixed_dark"/> - <public name="removed_system_on_secondary_fixed_variant_dark"/> - <public name="removed_system_tertiary_fixed_dark"/> - <public name="removed_system_tertiary_fixed_dim_dark"/> - <public name="removed_system_on_tertiary_fixed_dark"/> - <public name="removed_system_on_tertiary_fixed_variant_dark"/> - <public name="system_control_activated_dark"/> - <public name="system_control_normal_dark"/> - <public name="system_control_highlight_dark"/> - <public name="system_text_primary_inverse_dark"/> - <public name="system_text_secondary_and_tertiary_inverse_dark"/> - <public name="system_text_primary_inverse_disable_only_dark"/> - <public name="system_text_secondary_and_tertiary_inverse_disabled_dark"/> - <public name="system_text_hint_inverse_dark"/> - <public name="system_palette_key_color_primary_dark"/> - <public name="system_palette_key_color_secondary_dark"/> - <public name="system_palette_key_color_tertiary_dark"/> - <public name="system_palette_key_color_neutral_dark"/> - <public name="system_palette_key_color_neutral_variant_dark"/> - <public name="system_primary_fixed" /> - <public name="system_primary_fixed_dim" /> - <public name="system_on_primary_fixed" /> - <public name="system_on_primary_fixed_variant" /> - <public name="system_secondary_fixed" /> - <public name="system_secondary_fixed_dim" /> - <public name="system_on_secondary_fixed" /> - <public name="system_on_secondary_fixed_variant" /> - <public name="system_tertiary_fixed" /> - <public name="system_tertiary_fixed_dim" /> - <public name="system_on_tertiary_fixed" /> - <public name="system_on_tertiary_fixed_variant" /> - <public name="system_outline_variant_light" /> - <public name="system_outline_variant_dark" /> + <staging-public-group type="color" first-id="0x01b80000"> </staging-public-group> - <staging-public-group type="array" first-id="0x01c80000"> + <staging-public-group type="array" first-id="0x01b70000"> </staging-public-group> - <staging-public-group type="drawable" first-id="0x01c70000"> + <staging-public-group type="drawable" first-id="0x01b60000"> </staging-public-group> - <staging-public-group type="layout" first-id="0x01c60000"> + <staging-public-group type="layout" first-id="0x01b50000"> </staging-public-group> - <staging-public-group type="anim" first-id="0x01c50000"> + <staging-public-group type="anim" first-id="0x01b40000"> </staging-public-group> - <staging-public-group type="animator" first-id="0x01c40000"> + <staging-public-group type="animator" first-id="0x01b30000"> </staging-public-group> - <staging-public-group type="interpolator" first-id="0x01c30000"> + <staging-public-group type="interpolator" first-id="0x01b20000"> </staging-public-group> - <staging-public-group type="mipmap" first-id="0x01c20000"> + <staging-public-group type="mipmap" first-id="0x01b10000"> </staging-public-group> - <staging-public-group type="integer" first-id="0x01c10000"> + <staging-public-group type="integer" first-id="0x01b00000"> </staging-public-group> - <staging-public-group type="transition" first-id="0x01c00000"> + <staging-public-group type="transition" first-id="0x01af0000"> </staging-public-group> - <staging-public-group type="raw" first-id="0x01bf0000"> + <staging-public-group type="raw" first-id="0x01ae0000"> </staging-public-group> - <staging-public-group type="bool" first-id="0x01be0000"> - <!-- @hide @SystemApi --> - <public name="config_safetyProtectionEnabled" /> - <!-- @hide @SystemApi --> - <public name="config_enableDefaultNotes" /> - <!-- @hide @SystemApi --> - <public name="config_enableDefaultNotesForWorkProfile" /> + <staging-public-group type="bool" first-id="0x01ad0000"> </staging-public-group> - <staging-public-group type="fraction" first-id="0x01bd0000"> + <staging-public-group type="fraction" first-id="0x01ac0000"> </staging-public-group> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 3ee8af2842bf..947dc2de9841 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1347,16 +1347,6 @@ <!-- Description of the background body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors in the background. [CHAR LIMIT=NONE] --> <string name="permdesc_bodySensors_background" product="default">Allows the app to access body sensor data, such as heart rate, temperature, and blood oxygen percentage, while the app is in the background.</string> - <!-- Title of the body sensors wrist temperature permission, listed so the user can decide whether to allow the application to access body sensor wrist temperature data. [CHAR LIMIT=NONE] --> - <string name="permlab_bodySensorsWristTemperature">Access body sensor wrist temperature data while the app is in use.</string> - <!-- Description of the body sensors wrist temperature permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] --> - <string name="permdesc_bodySensorsWristTemperature" product="default">Allows the app to access body sensor wrist temperature data, while the app is in use.</string> - - <!-- Title of the body sensors wrist temperature permission, listed so the user can decide whether to allow the application to access body sensor wrist temperature data. [CHAR LIMIT=NONE] --> - <string name="permlab_bodySensors_wristTemperature_background">Access body sensor wrist temperature data while the app is in the background.</string> - <!-- Description of the body sensors wrist temperature permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] --> - <string name="permdesc_bodySensors_wristTemperature_background" product="default">Allows the app to access body sensor wrist temperature data, while the app is in the background.</string> - <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_readCalendar">Read calendar events and details</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> @@ -5369,15 +5359,11 @@ <string name="app_suspended_unsuspend_message">Unpause app</string> <!-- Title of a dialog. This text is confirming that the user wants to turn on access to their work apps, which the user had previously paused. "Work" is an adjective. [CHAR LIMIT=30] --> - <string name="work_mode_off_title">Turn on work apps?</string> - <!-- Text in a dialog. This text is confirming that the user wants to turn on access to their work apps and notifications, which the user had previously paused. "Work" is an adjective. [CHAR LIMIT=NONE] --> - <string name="work_mode_off_message">Get access to your work apps and notifications</string> - <!-- Title for button to turn on work profile. [CHAR LIMIT=NONE] --> - <string name="work_mode_turn_on">Turn on</string> + <string name="work_mode_off_title">Unpause work apps?</string> + <!-- Title for button to unpause on work profile. [CHAR LIMIT=NONE] --> + <string name="work_mode_turn_on">Unpause</string> <!-- Title for button to launch the personal safety app to make an emergency call --> <string name="work_mode_emergency_call_button">Emergency</string> - <!-- Text shown in a dialog when the user tries to launch a disabled work profile app when work apps are paused--> - <string name="work_mode_dialer_off_message">Get access to your work apps and calls</string> <!-- Title of the dialog that is shown when the user tries to launch a blocked application [CHAR LIMIT=50] --> <string name="app_blocked_title">App is not available</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7b582da836aa..b93a78695207 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1944,7 +1944,7 @@ <java-symbol type="bool" name="config_allowTheaterModeWakeFromLidSwitch" /> <java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" /> <java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" /> - <java-symbol type="bool" name="config_keepDreamingWhenUndocking" /> + <java-symbol type="bool" name="config_keepDreamingWhenUnplugging" /> <java-symbol type="integer" name="config_keyguardDrawnTimeout" /> <java-symbol type="bool" name="config_goToSleepOnButtonPressTheaterMode" /> <java-symbol type="bool" name="config_supportLongPressPowerWhenNonInteractive" /> @@ -2017,6 +2017,7 @@ <java-symbol type="integer" name="config_notificationsBatteryMediumARGB" /> <java-symbol type="integer" name="config_notificationsBatteryNearlyFullLevel" /> <java-symbol type="integer" name="config_notificationServiceArchiveSize" /> + <java-symbol type="array" name="config_useFullScreenIntentPackages" /> <java-symbol type="integer" name="config_previousVibrationsDumpLimit" /> <java-symbol type="integer" name="config_defaultVibrationAmplitude" /> <java-symbol type="dimen" name="config_hapticChannelMaxVibrationAmplitude" /> @@ -3138,10 +3139,8 @@ <!-- Work profile unlaunchable app alert dialog--> <java-symbol type="style" name="AlertDialogWithEmergencyButton"/> - <java-symbol type="string" name="work_mode_dialer_off_message" /> <java-symbol type="string" name="work_mode_emergency_call_button" /> <java-symbol type="string" name="work_mode_off_title" /> - <java-symbol type="string" name="work_mode_off_message" /> <java-symbol type="string" name="work_mode_turn_on" /> <java-symbol type="string" name="deprecated_target_sdk_message" /> @@ -4865,6 +4864,8 @@ <java-symbol type="string" name="config_wearSysUiPackage"/> <java-symbol type="string" name="config_wearSysUiMainActivity"/> + <java-symbol type="string" name="config_wearMediaControlsPackage"/> + <java-symbol type="string" name="config_wearMediaSessionsPackage"/> <java-symbol type="string" name="config_defaultQrCodeComponent"/> <java-symbol type="dimen" name="secondary_rounded_corner_radius" /> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index e59b2597722f..706845360bf4 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1665,47 +1665,47 @@ easier. <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorErrorContainer">@color/system_error_container_light</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorOnBackground">@color/system_on_background_light</item> <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorOnError">@color/system_on_error_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorTertiary">@color/system_tertiary_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOutline">@color/system_outline_light</item> + <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -1758,47 +1758,47 @@ easier. <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorErrorContainer">@color/system_error_container_light</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorOnBackground">@color/system_on_background_light</item> <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorOnError">@color/system_on_error_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorTertiary">@color/system_tertiary_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOutline">@color/system_outline_light</item> + <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> </style> <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert"> @@ -4043,16 +4043,16 @@ easier. <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> + <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> @@ -4123,16 +4123,16 @@ easier. <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> + <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> @@ -4195,16 +4195,16 @@ easier. <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> + <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> @@ -4366,16 +4366,16 @@ easier. <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> + <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> @@ -4475,47 +4475,47 @@ easier. <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorErrorContainer">@color/system_error_container_light</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorOnBackground">@color/system_on_background_light</item> <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorOnError">@color/system_on_error_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorTertiary">@color/system_tertiary_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOutline">@color/system_outline_light</item> + <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert"> @@ -4570,47 +4570,47 @@ easier. <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorErrorContainer">@color/system_error_container_light</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorOnBackground">@color/system_on_background_light</item> <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorOnError">@color/system_on_error_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorTertiary">@color/system_tertiary_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOutline">@color/system_outline_light</item> + <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" /> @@ -4700,16 +4700,16 @@ easier. <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> + <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> + <item name="materialColorPrimaryInverse">@color/system_primary_light</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> + <item name="materialColorSurfaceInverse">@color/system_surface_light</item> <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> diff --git a/core/res/res/xml/irq_device_map.xml b/core/res/res/xml/irq_device_map.xml index 4fae8fb77687..8b3667e9f2a9 100644 --- a/core/res/res/xml/irq_device_map.xml +++ b/core/res/res/xml/irq_device_map.xml @@ -18,14 +18,16 @@ --> <irq-device-map> <!-- This file maps devices (chips) that can send interrupts to the main processor (and bring it - out of sleep) to logical subsystems in userspace code. Since each Android device has its own - uniquely designed chipset, this mapping is expected to be empty by default and should be - overridden by device-specific configs. + out of sleep) to logical subsystems in userspace code. Since each Android device can have + a differently designed chipset, this mapping is expected to be empty by default and should + be overridden by device-specific configs. This mapping helps the system to meaningfully attribute CPU wakeups to logical work that - happened on the device. The devices are referred to by their names as defined in the kernel. - Currently, defined subsystems are: - - Alarm: Use this to denote wakeup alarms requested by apps via the AlarmManager API. - - Wifi: Use this to denote network traffic that uses the wifi transport. + happened on the device and the app activity that caused it. The devices are referred to by + their names as defined in the kernel. Currently, defined subsystems are: + - Alarm: Use this to denote wakeup alarms requested by apps via the AlarmManager API. + - Wifi: Use this to denote network traffic that uses the wifi transport. + - Sound_trigger: Use this to denote sound phrase detection, like the ones supported by + SoundTriggerManager. The overlay should use tags <device> and <subsystem> to describe this mapping in the following way: diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS index b3f399363aef..8d9461d8035d 100644 --- a/core/tests/coretests/src/android/app/OWNERS +++ b/core/tests/coretests/src/android/app/OWNERS @@ -4,3 +4,6 @@ per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS per-file *Notification* = file:/packages/SystemUI/OWNERS per-file *Zen* = file:/packages/SystemUI/OWNERS per-file *StatusBar* = file:/packages/SystemUI/OWNERS + +# A11Y and related +per-file *UiAutomation* = file:/services/accessibility/OWNERS diff --git a/core/tests/coretests/src/android/app/UiAutomationTest.java b/core/tests/coretests/src/android/app/UiAutomationTest.java new file mode 100644 index 000000000000..3ac5057bcf24 --- /dev/null +++ b/core/tests/coretests/src/android/app/UiAutomationTest.java @@ -0,0 +1,144 @@ +/* + * 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.app; + +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; + +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.Looper; +import android.os.UserManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public final class UiAutomationTest { + + private static final int SECONDARY_DISPLAY_ID = 42; + private static final int DISPLAY_ID_ASSIGNED_TO_USER = 108; + + private final Looper mLooper = Looper.getMainLooper(); + + @Mock + private Context mContext; + @Mock + private UserManager mUserManager; + @Mock + private IUiAutomationConnection mConnection; + + @Before + public void setFixtures() { + when(mContext.getMainLooper()).thenReturn(mLooper); + mockSystemService(UserManager.class, mUserManager); + + // Set default expectations + mockVisibleBackgroundUsersSupported(/* supported= */ false); + mockUserVisibility(/* visible= */ true); + // make sure it's not used, unless explicitly mocked + mockDisplayAssignedToUser(INVALID_DISPLAY); + mockContextDisplay(DEFAULT_DISPLAY); + } + + @Test + public void testContextConstructor_nullContext() { + assertThrows(IllegalArgumentException.class, + () -> new UiAutomation((Context) null, mConnection)); + } + + @Test + public void testContextConstructor_nullConnection() { + assertThrows(IllegalArgumentException.class, + () -> new UiAutomation(mContext, (IUiAutomationConnection) null)); + } + + @Test + public void testGetDisplay_contextWithSecondaryDisplayId() { + mockContextDisplay(SECONDARY_DISPLAY_ID); + + UiAutomation uiAutomation = new UiAutomation(mContext, mConnection); + + // It's always DEFAULT_DISPLAY regardless, unless the device supports visible bg users + assertWithMessage("getDisplayId()").that(uiAutomation.getDisplayId()) + .isEqualTo(DEFAULT_DISPLAY); + } + + @Test + public void testGetDisplay_contextWithInvalidDisplayId() { + mockContextDisplay(INVALID_DISPLAY); + + UiAutomation uiAutomation = new UiAutomation(mContext, mConnection); + + assertWithMessage("getDisplayId()").that(uiAutomation.getDisplayId()) + .isEqualTo(DEFAULT_DISPLAY); + } + + @Test + public void testGetDisplay_visibleBgUsers() { + mockVisibleBackgroundUsersSupported(/* supported= */ true); + mockContextDisplay(SECONDARY_DISPLAY_ID); + // Should be using display from context, not from user + mockDisplayAssignedToUser(DISPLAY_ID_ASSIGNED_TO_USER); + + UiAutomation uiAutomation = new UiAutomation(mContext, mConnection); + + assertWithMessage("getDisplayId()").that(uiAutomation.getDisplayId()) + .isEqualTo(SECONDARY_DISPLAY_ID); + } + + @Test + public void testGetDisplay_visibleBgUsers_contextWithInvalidDisplayId() { + mockVisibleBackgroundUsersSupported(/* supported= */ true); + mockContextDisplay(INVALID_DISPLAY); + mockDisplayAssignedToUser(DISPLAY_ID_ASSIGNED_TO_USER); + + UiAutomation uiAutomation = new UiAutomation(mContext, mConnection); + + assertWithMessage("getDisplayId()").that(uiAutomation.getDisplayId()) + .isEqualTo(DISPLAY_ID_ASSIGNED_TO_USER); + } + + private <T> void mockSystemService(Class<T> svcClass, T svc) { + String svcName = svcClass.getName(); + when(mContext.getSystemServiceName(svcClass)).thenReturn(svcName); + when(mContext.getSystemService(svcName)).thenReturn(svc); + } + + private void mockVisibleBackgroundUsersSupported(boolean supported) { + when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(supported); + } + + private void mockContextDisplay(int displayId) { + when(mContext.getDisplayId()).thenReturn(displayId); + } + + private void mockDisplayAssignedToUser(int displayId) { + when(mUserManager.getMainDisplayIdAssignedToUser()).thenReturn(displayId); + } + + private void mockUserVisibility(boolean visible) { + when(mUserManager.isUserVisible()).thenReturn(visible); + } +} diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java index 980211fe4cc8..c6bb07b17fd4 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import android.app.Activity; import android.compat.testing.PlatformCompatChangeRule; import android.os.Bundle; +import android.platform.test.annotations.IwTest; import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.util.PollingCheck; @@ -84,6 +85,7 @@ public class FontScaleConverterActivityTest { } } + @IwTest(focusArea = "accessibility") @Test public void testFontsScaleNonLinearly() { final ActivityScenario<TestActivity> scenario = rule.getScenario(); @@ -114,6 +116,7 @@ public class FontScaleConverterActivityTest { ))); } + @IwTest(focusArea = "accessibility") @Test public void testOnConfigurationChanged_doesNotCrash() { final ActivityScenario<TestActivity> scenario = rule.getScenario(); @@ -127,6 +130,7 @@ public class FontScaleConverterActivityTest { }); } + @IwTest(focusArea = "accessibility") @Test public void testUpdateConfiguration_doesNotCrash() { final ActivityScenario<TestActivity> scenario = rule.getScenario(); diff --git a/core/tests/coretests/src/android/content/res/TEST_MAPPING b/core/tests/coretests/src/android/content/res/TEST_MAPPING index 4ea6e40a7225..ab14950891c3 100644 --- a/core/tests/coretests/src/android/content/res/TEST_MAPPING +++ b/core/tests/coretests/src/android/content/res/TEST_MAPPING @@ -39,5 +39,18 @@ } ] } + ], + "ironwood-postsubmit": [ + { + "name": "FrameworksCoreTests", + "options":[ + { + "include-annotation": "android.platform.test.annotations.IwTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } ] } diff --git a/core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java b/core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java new file mode 100644 index 000000000000..66f3bca72aeb --- /dev/null +++ b/core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java @@ -0,0 +1,102 @@ +/* + * 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.hardware.biometrics; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.CancellationSignal; +import android.os.Handler; +import android.os.RemoteException; +import android.os.test.TestLooper; +import android.platform.test.annotations.Presubmit; + +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.MockitoJUnitRunner; +import org.mockito.junit.MockitoRule; + +import java.util.concurrent.Executor; + + +@Presubmit +@RunWith(MockitoJUnitRunner.class) +public class BiometricPromptTest { + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private Context mContext; + @Mock + private IAuthService mService; + private BiometricPrompt mBiometricPrompt; + + private CancellationSignal mCancellationSignal; + + private final TestLooper mLooper = new TestLooper(); + private final Handler mHandler = new Handler(mLooper.getLooper()); + private final Executor mExecutor = mHandler::post; + + @Before + public void setUp() throws RemoteException { + mBiometricPrompt = new BiometricPrompt.Builder(mContext) + .setUseDefaultSubtitle() + .setUseDefaultTitle() + .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG + | BiometricManager.Authenticators.DEVICE_CREDENTIAL) + .setService(mService) + .build(); + + mCancellationSignal = new CancellationSignal(); + when(mService.authenticate(any(), anyLong(), anyInt(), any(), anyString(), any())) + .thenReturn(0L); + when(mContext.getPackageName()).thenReturn("BiometricPromptTest"); + } + + @Test + public void testCancellationAfterAuthenticationFailed() throws RemoteException { + ArgumentCaptor<IBiometricServiceReceiver> biometricServiceReceiverCaptor = + ArgumentCaptor.forClass(IBiometricServiceReceiver.class); + BiometricPrompt.AuthenticationCallback callback = + new BiometricPrompt.AuthenticationCallback() { + @Override + public void onAuthenticationError(int errorCode, CharSequence errString) { + super.onAuthenticationError(errorCode, errString); + }}; + mBiometricPrompt.authenticate(mCancellationSignal, mExecutor, callback); + mLooper.dispatchAll(); + + verify(mService).authenticate(any(), anyLong(), anyInt(), + biometricServiceReceiverCaptor.capture(), anyString(), any()); + + biometricServiceReceiverCaptor.getValue().onAuthenticationFailed(); + mLooper.dispatchAll(); + mCancellationSignal.cancel(); + + verify(mService).cancelAuthentication(any(), anyString(), anyLong()); + } +} diff --git a/core/tests/coretests/src/android/hardware/biometrics/OWNERS b/core/tests/coretests/src/android/hardware/biometrics/OWNERS new file mode 100644 index 000000000000..6a2192a2c7fb --- /dev/null +++ b/core/tests/coretests/src/android/hardware/biometrics/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt b/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt index 4f27e9997cf6..fdcc7c993ddd 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt @@ -15,11 +15,14 @@ */ package android.hardware.input +import android.content.Context +import android.content.ContextWrapper import android.hardware.BatteryState import android.os.Handler import android.os.HandlerExecutor import android.os.test.TestLooper import android.platform.test.annotations.Presubmit +import androidx.test.core.app.ApplicationProvider import com.android.server.testutils.any import java.util.concurrent.Executor import kotlin.test.assertEquals @@ -32,8 +35,10 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.anyInt import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoJUnitRunner @@ -53,6 +58,7 @@ class InputDeviceBatteryListenerTest { private var registeredListener: IInputDeviceBatteryListener? = null private val monitoredDevices = mutableListOf<Int>() private lateinit var executor: Executor + private lateinit var context: Context private lateinit var inputManager: InputManager @Mock @@ -60,11 +66,15 @@ class InputDeviceBatteryListenerTest { @Before fun setUp() { + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) testLooper = TestLooper() executor = HandlerExecutor(Handler(testLooper.looper)) registeredListener = null monitoredDevices.clear() - inputManager = InputManager.resetInstance(iInputManagerMock) + InputManagerGlobal.resetInstance(iInputManagerMock) + inputManager = InputManager(context) + `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) + .thenReturn(inputManager) // Handle battery listener registration. doAnswer { @@ -102,7 +112,7 @@ class InputDeviceBatteryListenerTest { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } private fun notifyBatteryStateChanged( diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java index bf65af32e0ac..1e505abbc169 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java @@ -28,9 +28,12 @@ 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.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.Context; +import android.content.ContextWrapper; import android.hardware.lights.Light; import android.hardware.lights.LightState; import android.hardware.lights.LightsManager; @@ -40,6 +43,8 @@ import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; import android.view.InputDevice; +import androidx.test.InstrumentationRegistry; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -76,12 +81,15 @@ public class InputDeviceLightsManagerTest { @Before public void setUp() throws Exception { + final Context context = spy(new ContextWrapper(InstrumentationRegistry.getContext())); when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID}); when(mIInputManagerMock.getInputDevice(eq(DEVICE_ID))).thenReturn( createInputDevice(DEVICE_ID)); - mInputManager = InputManager.resetInstance(mIInputManagerMock); + InputManagerGlobal.resetInstance(mIInputManagerMock); + mInputManager = new InputManager(context); + when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(mInputManager); ArrayMap<Integer, LightState> lightStatesById = new ArrayMap<>(); doAnswer(invocation -> { @@ -106,7 +114,7 @@ public class InputDeviceLightsManagerTest { @After public void tearDown() { - InputManager.clearInstance(); + InputManagerGlobal.clearInstance(); } private InputDevice createInputDevice(int id) { diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java index 6cf2314fea45..b33cfdda4a09 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java @@ -81,9 +81,9 @@ public class InputDeviceSensorManagerTest { @Before public void setUp() throws Exception { final Context context = spy(new ContextWrapper(InstrumentationRegistry.getContext())); - InputManager inputManager = InputManager.resetInstance(mIInputManagerMock); - - when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager); + InputManagerGlobal.resetInstance(mIInputManagerMock); + mInputManager = new InputManager(context); + when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(mInputManager); when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID}); @@ -98,13 +98,11 @@ public class InputDeviceSensorManagerTest { .thenReturn(true); when(mIInputManagerMock.registerSensorListener(any())).thenReturn(true); - - mInputManager = context.getSystemService(InputManager.class); } @After public void tearDown() { - InputManager.clearInstance(); + InputManagerGlobal.clearInstance(); } private class InputTestSensorEventListener implements SensorEventListener { diff --git a/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt b/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt index ee7a6083a0e2..2ebe362b60f2 100644 --- a/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt +++ b/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt @@ -15,11 +15,14 @@ */ package android.hardware.input +import android.content.Context +import android.content.ContextWrapper import android.content.res.Resources import android.platform.test.annotations.Presubmit import android.view.Display import android.view.DisplayInfo import android.view.InputDevice +import androidx.test.core.app.ApplicationProvider import org.junit.After import org.junit.Assert.assertNotNull import org.junit.Assert.assertEquals @@ -28,6 +31,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.eq import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit @@ -52,17 +56,20 @@ class InputManagerTest { @get:Rule val rule = MockitoJUnit.rule()!! - private lateinit var inputManager: InputManager - private lateinit var devicesChangedListener: IInputDevicesChangedListener private val deviceGenerationMap = mutableMapOf<Int /*deviceId*/, Int /*generation*/>() + private lateinit var context: Context + private lateinit var inputManager: InputManager @Mock private lateinit var iInputManager: IInputManager @Before fun setUp() { - inputManager = InputManager.resetInstance(iInputManager) + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + InputManagerGlobal.resetInstance(iInputManager) + inputManager = InputManager(context) + `when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager) `when`(iInputManager.inputDeviceIds).then { deviceGenerationMap.keys.toIntArray() } @@ -70,7 +77,7 @@ class InputManagerTest { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } private fun notifyDeviceChanged( diff --git a/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt b/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt index 91d19a19379d..ce816ab98b12 100644 --- a/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt +++ b/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt @@ -16,10 +16,13 @@ package android.hardware.input +import android.content.Context +import android.content.ContextWrapper import android.os.Handler import android.os.HandlerExecutor import android.os.test.TestLooper import android.platform.test.annotations.Presubmit +import androidx.test.core.app.ApplicationProvider import com.android.server.testutils.any import org.junit.After import org.junit.Before @@ -27,7 +30,9 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoJUnitRunner import java.util.concurrent.Executor @@ -51,6 +56,7 @@ class KeyboardBacklightListenerTest { private lateinit var testLooper: TestLooper private var registeredListener: IKeyboardBacklightListener? = null private lateinit var executor: Executor + private lateinit var context: Context private lateinit var inputManager: InputManager @Mock @@ -58,10 +64,14 @@ class KeyboardBacklightListenerTest { @Before fun setUp() { + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + InputManagerGlobal.resetInstance(iInputManagerMock) testLooper = TestLooper() executor = HandlerExecutor(Handler(testLooper.looper)) registeredListener = null - inputManager = InputManager.resetInstance(iInputManagerMock) + inputManager = InputManager(context) + `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) + .thenReturn(inputManager) // Handle keyboard backlight listener registration. doAnswer { @@ -89,7 +99,7 @@ class KeyboardBacklightListenerTest { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } private fun notifyKeyboardBacklightChanged( diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java index 3b6e8eaafc22..cde100cc20aa 100644 --- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java +++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java @@ -70,7 +70,13 @@ public class WindowOnBackInvokedDispatcherTest { private ApplicationInfo mApplicationInfo; private final BackMotionEvent mBackEvent = new BackMotionEvent( - 0, 0, 0, BackEvent.EDGE_LEFT, null); + /* touchX = */ 0, + /* touchY = */ 0, + /* progress = */ 0, + /* velocityX = */ 0, + /* velocityY = */ 0, + /* swipeEdge = */ BackEvent.EDGE_LEFT, + /* departingAnimationTarget = */ null); @Before public void setUp() throws Exception { diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java index 4716312c59a8..36c2a62ae6ed 100644 --- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java @@ -23,16 +23,25 @@ import static com.android.internal.util.DumpUtils.isPlatformCriticalPackage; import static com.android.internal.util.DumpUtils.isPlatformNonCriticalPackage; import static com.android.internal.util.DumpUtils.isPlatformPackage; +import static com.google.common.truth.Truth.assertWithMessage; + import android.content.ComponentName; +import android.util.SparseArray; import junit.framework.TestCase; +import java.io.PrintWriter; +import java.io.StringWriter; + /** * Run with: atest FrameworksCoreTests:DumpUtilsTest */ public class DumpUtilsTest extends TestCase { + private final StringWriter mStringWriter = new StringWriter(); + private final PrintWriter mPrintWriter = new PrintWriter(mStringWriter); + private static ComponentName cn(String componentName) { if (componentName == null) { return null; @@ -168,4 +177,144 @@ public class DumpUtilsTest extends TestCase { Integer.toHexString(System.identityHashCode(component))).test( wcn("com.google/.abc"))); } + + public void testDumpSparseArray_empty() { + SparseArray<String> array = new SparseArray<>(); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ "...", array, "whatever"); + + String output = flushPrintWriter(); + + assertWithMessage("empty array dump").that(output).isEqualTo("...No whatevers\n"); + } + + public void testDumpSparseArray_oneElement() { + SparseArray<String> array = new SparseArray<>(); + array.put(1, "uno"); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number"); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".1 number(s):\n" + + "..0: 1->uno\n"); + } + + public void testDumpSparseArray_oneNullElement() { + SparseArray<String> array = new SparseArray<>(); + array.put(1, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "NULL"); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".1 NULL(s):\n" + + "..0: 1->(null)\n"); + } + + public void testDumpSparseArray_multipleElements() { + SparseArray<String> array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number"); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 number(s):\n" + + "..0: 1->uno\n" + + "..1: 2->duo\n" + + "..2: 42->(null)\n"); + } + + public void testDumpSparseArray_keyDumperOnly() { + SparseArray<String> array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number", + (i, k) -> { + mPrintWriter.printf("_%d=%d_", i, k); + }, /* valueDumper= */ null); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 number(s):\n" + + "_0=1_uno\n" + + "_1=2_duo\n" + + "_2=42_(null)\n"); + } + + public void testDumpSparseArray_valueDumperOnly() { + SparseArray<String> array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number", + /* keyDumper= */ null, + s -> { + mPrintWriter.print(s.toUpperCase()); + }); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 number(s):\n" + + "..0: 1->UNO\n" + + "..1: 2->DUO\n" + + "..2: 42->(null)\n"); + } + + public void testDumpSparseArray_keyAndValueDumpers() { + SparseArray<String> array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number", + (i, k) -> { + mPrintWriter.printf("_%d=%d_", i, k); + }, + s -> { + mPrintWriter.print(s.toUpperCase()); + }); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 number(s):\n" + + "_0=1_UNO\n" + + "_1=2_DUO\n" + + "_2=42_(null)\n"); + } + + public void testDumpSparseArrayValues() { + SparseArray<String> array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArrayValues(mPrintWriter, /* prefix= */ ".", array, "number"); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 numbers:\n" + + "..uno\n" + + "..duo\n" + + "..(null)\n"); + } + + private String flushPrintWriter() { + mPrintWriter.flush(); + + return mStringWriter.toString(); + } } diff --git a/core/tests/expresslog/OWNERS b/core/tests/expresslog/OWNERS deleted file mode 100644 index 3dc958b07f9c..000000000000 --- a/core/tests/expresslog/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Bug component: 719316 -# Stats/expresslog -file:/services/core/java/com/android/server/stats/OWNERS diff --git a/core/tests/expresslog/TEST_MAPPING b/core/tests/expresslog/TEST_MAPPING deleted file mode 100644 index c9b0cf80a1e6..000000000000 --- a/core/tests/expresslog/TEST_MAPPING +++ /dev/null @@ -1,12 +0,0 @@ -{ - "presubmit": [ - { - "name": "ExpressLogTests", - "options": [ - { - "exclude-annotation": "org.junit.Ignore" - } - ] - } - ] -}
\ No newline at end of file diff --git a/core/tests/expresslog/src/com/android/internal/expresslog/ScaledRangeOptionsTest.java b/core/tests/expresslog/src/com/android/internal/expresslog/ScaledRangeOptionsTest.java deleted file mode 100644 index ee62d7528818..000000000000 --- a/core/tests/expresslog/src/com/android/internal/expresslog/ScaledRangeOptionsTest.java +++ /dev/null @@ -1,167 +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.internal.expresslog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -@SmallTest -public class ScaledRangeOptionsTest { - private static final String TAG = ScaledRangeOptionsTest.class.getSimpleName(); - - @Test - public void testGetBinsCount() { - Histogram.ScaledRangeOptions options1 = new Histogram.ScaledRangeOptions(1, 100, 100, 2); - assertEquals(3, options1.getBinsCount()); - - Histogram.ScaledRangeOptions options10 = new Histogram.ScaledRangeOptions(10, 100, 100, 2); - assertEquals(12, options10.getBinsCount()); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructZeroBinsCount() { - new Histogram.ScaledRangeOptions(0, 100, 100, 2); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructNegativeBinsCount() { - new Histogram.ScaledRangeOptions(-1, 100, 100, 2); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructNegativeFirstBinWidth() { - new Histogram.ScaledRangeOptions(10, 100, -100, 2); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructTooSmallFirstBinWidth() { - new Histogram.ScaledRangeOptions(10, 100, 0.5f, 2); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructNegativeScaleFactor() { - new Histogram.ScaledRangeOptions(10, 100, 100, -2); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructTooSmallScaleFactor() { - new Histogram.ScaledRangeOptions(10, 100, 100, 0.5f); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructTooBigScaleFactor() { - new Histogram.ScaledRangeOptions(10, 100, 100, 500.f); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructTooBigBinRange() { - new Histogram.ScaledRangeOptions(100, 100, 100, 10.f); - } - - @Test - public void testBinIndexForRangeEqual1() { - Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(10, 1, 1, 1); - assertEquals(12, options.getBinsCount()); - - assertEquals(11, options.getBinForSample(11)); - - for (int i = 0, bins = options.getBinsCount(); i < bins; i++) { - assertEquals(i, options.getBinForSample(i)); - } - } - - @Test - public void testBinIndexForRangeEqual2() { - // this should produce bin otpions similar to linear histogram with bin width 2 - Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(10, 1, 2, 1); - assertEquals(12, options.getBinsCount()); - - for (int i = 0, bins = options.getBinsCount(); i < bins; i++) { - assertEquals(i, options.getBinForSample(i * 2)); - assertEquals(i, options.getBinForSample(i * 2 - 1)); - } - } - - @Test - public void testBinIndexForRangeEqual5() { - Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(2, 0, 5, 1); - assertEquals(4, options.getBinsCount()); - for (int i = 0; i < 2; i++) { - for (int sample = 0; sample < 5; sample++) { - assertEquals(i + 1, options.getBinForSample(i * 5 + sample)); - } - } - } - - @Test - public void testBinIndexForRangeEqual10() { - Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(10, 1, 10, 1); - assertEquals(0, options.getBinForSample(0)); - assertEquals(options.getBinsCount() - 2, options.getBinForSample(100)); - assertEquals(options.getBinsCount() - 1, options.getBinForSample(101)); - - final float binSize = (101 - 1) / 10f; - for (int i = 1, bins = options.getBinsCount() - 1; i < bins; i++) { - assertEquals(i, options.getBinForSample(i * binSize)); - } - } - - @Test - public void testBinIndexForScaleFactor2() { - final int binsCount = 10; - final int minValue = 10; - final int firstBinWidth = 5; - final int scaledFactor = 2; - - Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions( - binsCount, minValue, firstBinWidth, scaledFactor); - assertEquals(binsCount + 2, options.getBinsCount()); - long[] binCounts = new long[10]; - - // precalculate max valid value - start value for the overflow bin - int lastBinStartValue = minValue; //firstBinMin value - int lastBinWidth = firstBinWidth; - for (int binIdx = 2; binIdx <= binsCount + 1; binIdx++) { - lastBinStartValue = lastBinStartValue + lastBinWidth; - lastBinWidth *= scaledFactor; - } - - // underflow bin - for (int i = 1; i < minValue; i++) { - assertEquals(0, options.getBinForSample(i)); - } - - for (int i = 10; i < lastBinStartValue; i++) { - assertTrue(options.getBinForSample(i) > 0); - assertTrue(options.getBinForSample(i) <= binsCount); - binCounts[options.getBinForSample(i) - 1]++; - } - - // overflow bin - assertEquals(binsCount + 1, options.getBinForSample(lastBinStartValue)); - - for (int i = 1; i < binsCount; i++) { - assertEquals(binCounts[i], binCounts[i - 1] * 2L); - } - } -} diff --git a/core/tests/expresslog/src/com/android/internal/expresslog/UniformOptionsTest.java b/core/tests/expresslog/src/com/android/internal/expresslog/UniformOptionsTest.java deleted file mode 100644 index 037dbb32c2f8..000000000000 --- a/core/tests/expresslog/src/com/android/internal/expresslog/UniformOptionsTest.java +++ /dev/null @@ -1,125 +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.internal.expresslog; - -import androidx.test.filters.SmallTest; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -@SmallTest -public class UniformOptionsTest { - private static final String TAG = UniformOptionsTest.class.getSimpleName(); - - @Test - public void testGetBinsCount() { - Histogram.UniformOptions options1 = new Histogram.UniformOptions(1, 100, 1000); - assertEquals(3, options1.getBinsCount()); - - Histogram.UniformOptions options10 = new Histogram.UniformOptions(10, 100, 1000); - assertEquals(12, options10.getBinsCount()); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructZeroBinsCount() { - new Histogram.UniformOptions(0, 100, 1000); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructNegativeBinsCount() { - new Histogram.UniformOptions(-1, 100, 1000); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructMaxValueLessThanMinValue() { - new Histogram.UniformOptions(10, 1000, 100); - } - - @Test - public void testBinIndexForRangeEqual1() { - Histogram.UniformOptions options = new Histogram.UniformOptions(10, 1, 11); - for (int i = 0, bins = options.getBinsCount(); i < bins; i++) { - assertEquals(i, options.getBinForSample(i)); - } - } - - @Test - public void testBinIndexForRangeEqual2() { - Histogram.UniformOptions options = new Histogram.UniformOptions(10, 1, 21); - for (int i = 0, bins = options.getBinsCount(); i < bins; i++) { - assertEquals(i, options.getBinForSample(i * 2)); - assertEquals(i, options.getBinForSample(i * 2 - 1)); - } - } - - @Test - public void testBinIndexForRangeEqual5() { - Histogram.UniformOptions options = new Histogram.UniformOptions(2, 0, 10); - assertEquals(4, options.getBinsCount()); - for (int i = 0; i < 2; i++) { - for (int sample = 0; sample < 5; sample++) { - assertEquals(i + 1, options.getBinForSample(i * 5 + sample)); - } - } - } - - @Test - public void testBinIndexForRangeEqual10() { - Histogram.UniformOptions options = new Histogram.UniformOptions(10, 1, 101); - assertEquals(0, options.getBinForSample(0)); - assertEquals(options.getBinsCount() - 2, options.getBinForSample(100)); - assertEquals(options.getBinsCount() - 1, options.getBinForSample(101)); - - final float binSize = (101 - 1) / 10f; - for (int i = 1, bins = options.getBinsCount() - 1; i < bins; i++) { - assertEquals(i, options.getBinForSample(i * binSize)); - } - } - - @Test - public void testBinIndexForRangeEqual90() { - final int binCount = 10; - final int minValue = 100; - final int maxValue = 100000; - - Histogram.UniformOptions options = new Histogram.UniformOptions(binCount, minValue, - maxValue); - - // logging underflow sample - assertEquals(0, options.getBinForSample(minValue - 1)); - - // logging overflow sample - assertEquals(binCount + 1, options.getBinForSample(maxValue)); - assertEquals(binCount + 1, options.getBinForSample(maxValue + 1)); - - // logging min edge sample - assertEquals(1, options.getBinForSample(minValue)); - - // logging max edge sample - assertEquals(binCount, options.getBinForSample(maxValue - 1)); - - // logging single valid sample per bin - final int binSize = (maxValue - minValue) / binCount; - - for (int i = 0; i < binCount; i++) { - assertEquals(i + 1, options.getBinForSample(minValue + binSize * i)); - } - } -} diff --git a/data/etc/preinstalled-packages-platform-overlays.xml b/data/etc/preinstalled-packages-platform-overlays.xml index 99594336999b..cea535e8f480 100644 --- a/data/etc/preinstalled-packages-platform-overlays.xml +++ b/data/etc/preinstalled-packages-platform-overlays.xml @@ -56,6 +56,10 @@ <install-in-user-type package="com.android.internal.systemui.navbar.transparent"> <install-in user-type="FULL" /> </install-in-user-type> + <install-in-user-type package="com.android.role.notes.enabled"> + <install-in user-type="FULL" /> + <install-in user-type="PROFILE" /> + </install-in-user-type> <install-in-user-type package="com.android.theme.color.amethyst"> <install-in user-type="FULL" /> <install-in user-type="PROFILE" /> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 2afd54b984a4..7434cb02cc7c 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -175,12 +175,6 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "-1941440781": { - "message": "Creating Pending Move-to-back: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Task.java" - }, "-1939861963": { "message": "Create root task displayId=%d winMode=%d", "level": "VERBOSE", @@ -475,6 +469,18 @@ "group": "WM_DEBUG_TASKS", "at": "com\/android\/server\/wm\/RecentTasks.java" }, + "-1643780158": { + "message": "Saving original orientation before camera compat, last orientation is %d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + }, + "-1639406696": { + "message": "NOSENSOR override detected", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + }, "-1638958146": { "message": "Removing activity %s from task=%s adding to task=%s Callers=%s", "level": "INFO", @@ -619,12 +625,6 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityStarter.java" }, - "-1484988952": { - "message": "Creating Pending Multiwindow Fullscreen Request: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityClientController.java" - }, "-1483435730": { "message": "InsetsSource setWin %s for type %s", "level": "DEBUG", @@ -751,6 +751,12 @@ "group": "WM_DEBUG_IME", "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, + "-1397175017": { + "message": "Other orientation overrides are in place: not reverting", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + }, "-1394745488": { "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s", "level": "INFO", @@ -883,6 +889,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, + "-1258739769": { + "message": "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b", + "level": "DEBUG", + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" + }, "-1257821162": { "message": "OUT SURFACE %s: copied", "level": "INFO", @@ -1297,6 +1309,12 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-874087484": { + "message": "SyncGroup %d: Set ready %b", + "level": "VERBOSE", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + }, "-869242375": { "message": "Content Recording: Unable to start recording due to invalid region for display %d", "level": "VERBOSE", @@ -1699,6 +1717,12 @@ "group": "WM_DEBUG_WINDOW_TRANSITIONS", "at": "com\/android\/server\/wm\/Transition.java" }, + "-529187878": { + "message": "Reverting orientation after camera compat force rotation", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + }, "-521613870": { "message": "App died during pause, not stopping: %s", "level": "VERBOSE", @@ -2371,6 +2395,12 @@ "group": "WM_DEBUG_FOCUS_LIGHT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "138097009": { + "message": "NOSENSOR override is absent: reverting", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + }, "140319294": { "message": "IME target changed within ActivityRecord", "level": "DEBUG", @@ -2563,12 +2593,6 @@ "group": "WM_DEBUG_ANIM", "at": "com\/android\/server\/wm\/WindowState.java" }, - "286170861": { - "message": "Creating Pending Transition for TaskFragment: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" - }, "288485303": { "message": "Attempted to set remove mode to a display that does not exist: %d", "level": "WARN", @@ -3151,12 +3175,6 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "800698875": { - "message": "SyncGroup %d: Started when there is other active SyncGroup", - "level": "WARN", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, "801521566": { "message": "Content Recording: Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.", "level": "WARN", @@ -3217,12 +3235,6 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "898260097": { - "message": "Creating Pending Pip-Enter: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, "898863925": { "message": "Attempted to add QS dialog window with unknown token %s. Aborting.", "level": "WARN", @@ -3967,12 +3979,6 @@ "group": "WM_DEBUG_CONTENT_RECORDING", "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "1667162379": { - "message": "Creating Pending Transition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" - }, "1670933628": { "message": " Setting allReady override", "level": "VERBOSE", @@ -4003,12 +4009,6 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "1689989893": { - "message": "SyncGroup %d: Set ready", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, "1699269281": { "message": "Don't organize or trigger events for untrusted displayId=%d", "level": "WARN", @@ -4039,6 +4039,12 @@ "group": "WM_DEBUG_SYNC_ENGINE", "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, + "1735199721": { + "message": "Queueing transition: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/TransitionController.java" + }, "1739298851": { "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d", "level": "WARN", diff --git a/data/keyboards/GoogleTV-Remote.idc b/data/keyboards/GoogleTV-Remote.idc new file mode 100644 index 000000000000..14fb4e29c33c --- /dev/null +++ b/data/keyboards/GoogleTV-Remote.idc @@ -0,0 +1,25 @@ +# Copyright 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. + +# +# Input Device Configuration file for Google Reference Remote Control Unit (RCU). +# +# + +# Basic Parameters +# Depending on the FLASH configurations, RCUs may have PID 0006 instead +# of 0001. +keyboard.layout = Vendor_0957_Product_0001 +keyboard.doNotWakeByDefault = 1 +audio.mic = 1 diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java index 9940ca3933c8..c52f700ef4f6 100644 --- a/graphics/java/android/graphics/BLASTBufferQueue.java +++ b/graphics/java/android/graphics/BLASTBufferQueue.java @@ -16,6 +16,7 @@ package android.graphics; +import android.annotation.NonNull; import android.view.Surface; import android.view.SurfaceControl; @@ -31,9 +32,10 @@ public final class BLASTBufferQueue { private static native long nativeCreate(String name, boolean updateDestinationFrame); private static native void nativeDestroy(long ptr); private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle); - private static native void nativeSyncNextTransaction(long ptr, + private static native boolean nativeSyncNextTransaction(long ptr, Consumer<SurfaceControl.Transaction> callback, boolean acquireSingleBuffer); private static native void nativeStopContinuousSyncTransaction(long ptr); + private static native void nativeClearSyncTransaction(long ptr); private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height, int format); private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr, @@ -92,9 +94,9 @@ public final class BLASTBufferQueue { * acquired. If false, continue to acquire all buffers into the * transaction until stopContinuousSyncTransaction is called. */ - public void syncNextTransaction(boolean acquireSingleBuffer, - Consumer<SurfaceControl.Transaction> callback) { - nativeSyncNextTransaction(mNativeObject, callback, acquireSingleBuffer); + public boolean syncNextTransaction(boolean acquireSingleBuffer, + @NonNull Consumer<SurfaceControl.Transaction> callback) { + return nativeSyncNextTransaction(mNativeObject, callback, acquireSingleBuffer); } /** @@ -104,8 +106,8 @@ public final class BLASTBufferQueue { * @param callback The callback invoked when the buffer has been added to the transaction. The * callback will contain the transaction with the buffer. */ - public void syncNextTransaction(Consumer<SurfaceControl.Transaction> callback) { - syncNextTransaction(true /* acquireSingleBuffer */, callback); + public boolean syncNextTransaction(@NonNull Consumer<SurfaceControl.Transaction> callback) { + return syncNextTransaction(true /* acquireSingleBuffer */, callback); } /** @@ -118,6 +120,14 @@ public final class BLASTBufferQueue { } /** + * Tell BBQ to clear the sync transaction that was previously set. The callback will not be + * invoked when the next frame is acquired. + */ + public void clearSyncTransaction() { + nativeClearSyncTransaction(mNativeObject); + } + + /** * Updates {@link SurfaceControl}, size, and format for a particular BLASTBufferQueue * @param sc The new SurfaceControl that this BLASTBufferQueue will update * @param width The new width for the buffer. diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 8dd23b70ae61..2307d6080f9f 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -401,8 +401,9 @@ public final class Bitmap implements Parcelable { /** * This is called by methods that want to throw an exception if the bitmap * has already been recycled. + * @hide */ - private void checkRecycled(String errorMessage) { + void checkRecycled(String errorMessage) { if (mRecycled) { throw new IllegalStateException(errorMessage); } @@ -1921,6 +1922,7 @@ public final class Bitmap implements Parcelable { */ public void setGainmap(@Nullable Gainmap gainmap) { checkRecycled("Bitmap is recycled"); + mGainmap = null; nativeSetGainmap(mNativePtr, gainmap == null ? 0 : gainmap.mNativePtr); } diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 701e20c499da..1da8e189d768 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -482,7 +482,9 @@ public class BitmapFactory { if (opts == null || opts.inBitmap == null) { return 0; } - + // Clear out the gainmap since we don't attempt to reuse it and don't want to + // accidentally keep it on the re-used bitmap + opts.inBitmap.setGainmap(null); return opts.inBitmap.getNativeInstance(); } diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 2f6dd468511b..5c065775eea2 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -120,6 +120,7 @@ public class BitmapShader extends Shader { if (bitmap == null) { throw new IllegalArgumentException("Bitmap must be non-null"); } + bitmap.checkRecycled("Cannot create BitmapShader for recycled bitmap"); mBitmap = bitmap; mTileX = tileX; mTileY = tileY; @@ -188,6 +189,8 @@ public class BitmapShader extends Shader { /** @hide */ @Override protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) { + mBitmap.checkRecycled("BitmapShader's bitmap has been recycled"); + boolean enableLinearFilter = mFilterMode == FILTER_MODE_LINEAR; if (mFilterMode == FILTER_MODE_DEFAULT) { mFilterFromPaint = filterFromPaint; diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 0b29973507d2..56c3068fe5e9 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -2083,32 +2083,29 @@ public final class ImageDecoder implements AutoCloseable { } sIsP010SupportedForAV1Initialized = true; - - if (hasHardwareDecoder("video/av01")) { - sIsP010SupportedForAV1 = true; - return true; - } - - sIsP010SupportedForAV1 = Build.VERSION.DEVICE_INITIAL_SDK_INT - >= Build.VERSION_CODES.S; - return sIsP010SupportedForAV1; + return sIsP010SupportedForAV1 = isP010SupportedforMime("video/av01"); } } /** - * 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; + * Checks if the device supports decoding 10-bit for the given mime type. + */ + private static boolean isP010SupportedforMime(String mime) { + MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS); + for (MediaCodecInfo mediaCodecInfo : codecList.getCodecInfos()) { + if (mediaCodecInfo.isEncoder()) { + continue; + } + for (String mediaType : mediaCodecInfo.getSupportedTypes()) { + if (mediaType.equalsIgnoreCase(mime)) { + MediaCodecInfo.CodecCapabilities codecCapabilities = + mediaCodecInfo.getCapabilitiesForType(mediaType); + for (int i = 0; i < codecCapabilities.colorFormats.length; ++i) { + if (codecCapabilities.colorFormats[i] + == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010) { + return true; + } + } } } } diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java index d785c3c895b8..f26b50ed4e2a 100644 --- a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java +++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java @@ -21,10 +21,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; -import android.os.RemoteException; import android.os.ServiceManager; -import android.security.GenerateRkpKey; -import android.security.keymaster.KeymasterDefs; class CredstoreIdentityCredentialStore extends IdentityCredentialStore { @@ -125,18 +122,7 @@ class CredstoreIdentityCredentialStore extends IdentityCredentialStore { @NonNull String docType) throws AlreadyPersonalizedException, DocTypeNotSupportedException { try { - IWritableCredential wc; - wc = mStore.createCredential(credentialName, docType); - try { - GenerateRkpKey keyGen = new GenerateRkpKey(mContext); - // We don't know what the security level is for the backing keymint, so go ahead and - // poke the provisioner for both TEE and SB. - keyGen.notifyKeyGenerated(KeymasterDefs.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT); - keyGen.notifyKeyGenerated(KeymasterDefs.KM_SECURITY_LEVEL_STRONGBOX); - } catch (RemoteException e) { - // Not really an error state. Does not apply at all if RKP is unsupported or - // disabled on a given device. - } + IWritableCredential wc = mStore.createCredential(credentialName, docType); return new CredstoreWritableIdentityCredential(mContext, credentialName, docType, wc); } catch (android.os.RemoteException e) { throw new RuntimeException("Unexpected RemoteException ", e); diff --git a/keystore/java/android/security/GenerateRkpKey.java b/keystore/java/android/security/GenerateRkpKey.java deleted file mode 100644 index 698133287f63..000000000000 --- a/keystore/java/android/security/GenerateRkpKey.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.security; - -import android.annotation.CheckResult; -import android.annotation.IntDef; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -/** - * GenerateKey is a helper class to handle interactions between Keystore and the RemoteProvisioner - * app. There are two cases where Keystore should use this class. - * - * (1) : An app generates a new attested key pair, so Keystore calls notifyKeyGenerated to let the - * RemoteProvisioner app check if the state of the attestation key pool is getting low enough - * to warrant provisioning more attestation certificates early. - * - * (2) : An app attempts to generate a new key pair, but the keystore service discovers it is out of - * attestation key pairs and cannot provide one for the given application. Keystore can then - * make a blocking call on notifyEmpty to allow the RemoteProvisioner app to get another - * attestation certificate chain provisioned. - * - * In most cases, the proper usage of (1) should preclude the need for (2). - * - * @hide - */ -public class GenerateRkpKey { - private static final String TAG = "GenerateRkpKey"; - - private static final int NOTIFY_EMPTY = 0; - private static final int NOTIFY_KEY_GENERATED = 1; - private static final int TIMEOUT_MS = 1000; - - private IGenerateRkpKeyService mBinder; - private Context mContext; - private CountDownLatch mCountDownLatch; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, value = { - IGenerateRkpKeyService.Status.OK, - IGenerateRkpKeyService.Status.NO_NETWORK_CONNECTIVITY, - IGenerateRkpKeyService.Status.NETWORK_COMMUNICATION_ERROR, - IGenerateRkpKeyService.Status.DEVICE_NOT_REGISTERED, - IGenerateRkpKeyService.Status.HTTP_CLIENT_ERROR, - IGenerateRkpKeyService.Status.HTTP_SERVER_ERROR, - IGenerateRkpKeyService.Status.HTTP_UNKNOWN_ERROR, - IGenerateRkpKeyService.Status.INTERNAL_ERROR, - }) - public @interface Status { - } - - private ServiceConnection mConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName className, IBinder service) { - mBinder = IGenerateRkpKeyService.Stub.asInterface(service); - mCountDownLatch.countDown(); - } - - @Override public void onBindingDied(ComponentName className) { - mCountDownLatch.countDown(); - } - - @Override - public void onServiceDisconnected(ComponentName className) { - mBinder = null; - } - }; - - /** - * Constructor which takes a Context object. - */ - public GenerateRkpKey(Context context) { - mContext = context; - } - - @Status - private int bindAndSendCommand(int command, int securityLevel) throws RemoteException { - Intent intent = new Intent(IGenerateRkpKeyService.class.getName()); - ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); - int returnCode = IGenerateRkpKeyService.Status.OK; - if (comp == null) { - // On a system that does not use RKP, the RemoteProvisioner app won't be installed. - return returnCode; - } - intent.setComponent(comp); - mCountDownLatch = new CountDownLatch(1); - Executor executor = Executors.newCachedThreadPool(); - if (!mContext.bindService(intent, Context.BIND_AUTO_CREATE, executor, mConnection)) { - throw new RemoteException("Failed to bind to GenerateRkpKeyService"); - } - try { - mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - Log.e(TAG, "Interrupted: ", e); - } - if (mBinder != null) { - switch (command) { - case NOTIFY_EMPTY: - returnCode = mBinder.generateKey(securityLevel); - break; - case NOTIFY_KEY_GENERATED: - mBinder.notifyKeyGenerated(securityLevel); - break; - default: - Log.e(TAG, "Invalid case for command"); - } - } else { - Log.e(TAG, "Binder object is null; failed to bind to GenerateRkpKeyService."); - returnCode = IGenerateRkpKeyService.Status.INTERNAL_ERROR; - } - mContext.unbindService(mConnection); - return returnCode; - } - - /** - * Fulfills the use case of (2) described in the class documentation. Blocks until the - * RemoteProvisioner application can get new attestation keys signed by the server. - * @return the status of the key generation - */ - @CheckResult - @Status - public int notifyEmpty(int securityLevel) throws RemoteException { - return bindAndSendCommand(NOTIFY_EMPTY, securityLevel); - } - - /** - * Fulfills the use case of (1) described in the class documentation. Non blocking call. - */ - public void notifyKeyGenerated(int securityLevel) throws RemoteException { - bindAndSendCommand(NOTIFY_KEY_GENERATED, securityLevel); - } -} diff --git a/keystore/java/android/security/IGenerateRkpKeyService.aidl b/keystore/java/android/security/IGenerateRkpKeyService.aidl deleted file mode 100644 index eeaeb27a7c77..000000000000 --- a/keystore/java/android/security/IGenerateRkpKeyService.aidl +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.security; - -/** - * Interface to allow the framework to notify the RemoteProvisioner app when keys are empty. This - * will be used if Keystore replies with an error code NO_KEYS_AVAILABLE in response to an - * attestation request. The framework can then synchronously call generateKey() to get more - * attestation keys generated and signed. Upon return, the caller can be certain an attestation key - * is available. - * - * @hide - */ -interface IGenerateRkpKeyService { - @JavaDerive(toString=true) - @Backing(type="int") - enum Status { - /** No error(s) occurred */ - OK = 0, - /** Unable to provision keys due to a lack of internet connectivity. */ - NO_NETWORK_CONNECTIVITY = 1, - /** An error occurred while communicating with the RKP server. */ - NETWORK_COMMUNICATION_ERROR = 2, - /** The given device was not registered with the RKP backend. */ - DEVICE_NOT_REGISTERED = 4, - /** The RKP server returned an HTTP client error, indicating a misbehaving client. */ - HTTP_CLIENT_ERROR = 5, - /** The RKP server returned an HTTP server error, indicating something went wrong on the server. */ - HTTP_SERVER_ERROR = 6, - /** The RKP server returned an HTTP status that is unknown. This should never happen. */ - HTTP_UNKNOWN_ERROR = 7, - /** An unexpected internal error occurred. This should never happen. */ - INTERNAL_ERROR = 8, - } - - /** - * Ping the provisioner service to let it know an app generated a key. This may or may not have - * consumed a remotely provisioned attestation key, so the RemoteProvisioner app should check. - */ - oneway void notifyKeyGenerated(in int securityLevel); - - /** - * Ping the provisioner service to indicate there are no remaining attestation keys left. - */ - Status generateKey(in int securityLevel); -} diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index c3b0f9bc16d3..474b7ea56be9 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -20,7 +20,6 @@ import static android.security.keystore2.AndroidKeyStoreCipherSpiBase.DEFAULT_MG import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.ActivityThread; import android.content.Context; import android.hardware.security.keymint.EcCurve; import android.hardware.security.keymint.KeyParameter; @@ -28,9 +27,6 @@ import android.hardware.security.keymint.KeyPurpose; import android.hardware.security.keymint.SecurityLevel; import android.hardware.security.keymint.Tag; import android.os.Build; -import android.os.RemoteException; -import android.security.GenerateRkpKey; -import android.security.IGenerateRkpKeyService; import android.security.KeyPairGeneratorSpec; import android.security.KeyStore2; import android.security.KeyStoreException; @@ -621,45 +617,6 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato @Override public KeyPair generateKeyPair() { - GenerateKeyPairHelperResult result = new GenerateKeyPairHelperResult(0, null); - for (int i = 0; i < 2; i++) { - /** - * NOTE: There is no need to delay between re-tries because the call to - * GenerateRkpKey.notifyEmpty() will delay for a while before returning. - */ - result = generateKeyPairHelper(); - if (result.rkpStatus == KeyStoreException.RKP_SUCCESS && result.keyPair != null) { - return result.keyPair; - } - } - - // RKP failure - if (result.rkpStatus != KeyStoreException.RKP_SUCCESS) { - KeyStoreException ksException = new KeyStoreException(ResponseCode.OUT_OF_KEYS, - "Could not get RKP keys", result.rkpStatus); - throw new ProviderException("Failed to provision new attestation keys.", ksException); - } - - return result.keyPair; - } - - private static class GenerateKeyPairHelperResult { - // Zero indicates success, non-zero indicates failure. Values should be - // {@link android.security.KeyStoreException#RKP_TEMPORARILY_UNAVAILABLE}, - // {@link android.security.KeyStoreException#RKP_SERVER_REFUSED_ISSUANCE}, - // {@link android.security.KeyStoreException#RKP_FETCHING_PENDING_CONNECTIVITY} - // {@link android.security.KeyStoreException#RKP_FETCHING_PENDING_SOFTWARE_REBOOT} - public final int rkpStatus; - @Nullable - public final KeyPair keyPair; - - private GenerateKeyPairHelperResult(int rkpStatus, KeyPair keyPair) { - this.rkpStatus = rkpStatus; - this.keyPair = keyPair; - } - } - - private GenerateKeyPairHelperResult generateKeyPairHelper() { if (mKeyStore == null || mSpec == null) { throw new IllegalStateException("Not initialized"); } @@ -697,26 +654,12 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato AndroidKeyStorePublicKey publicKey = AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse( descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm); - GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread - .currentApplication()); - try { - if (mSpec.getAttestationChallenge() != null) { - keyGen.notifyKeyGenerated(securityLevel); - } - } catch (RemoteException e) { - // This is not really an error state, and necessarily does not apply to non RKP - // systems or hybrid systems where RKP is not currently turned on. - Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.", e); - } success = true; - KeyPair kp = new KeyPair(publicKey, publicKey.getPrivateKey()); - return new GenerateKeyPairHelperResult(0, kp); + return new KeyPair(publicKey, publicKey.getPrivateKey()); } catch (KeyStoreException e) { switch (e.getErrorCode()) { case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE: throw new StrongBoxUnavailableException("Failed to generated key pair.", e); - case ResponseCode.OUT_OF_KEYS: - return checkIfRetryableOrThrow(e, securityLevel); default: ProviderException p = new ProviderException("Failed to generate key pair.", e); if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) { @@ -742,55 +685,6 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato } } - // In case keystore reports OUT_OF_KEYS, call this handler in an attempt to remotely provision - // some keys. - GenerateKeyPairHelperResult checkIfRetryableOrThrow(KeyStoreException e, int securityLevel) { - GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread - .currentApplication()); - KeyStoreException ksException; - try { - final int keyGenStatus = keyGen.notifyEmpty(securityLevel); - // Default stance: temporary error. This is a hint to the caller to try again with - // exponential back-off. - int rkpStatus; - switch (keyGenStatus) { - case IGenerateRkpKeyService.Status.NO_NETWORK_CONNECTIVITY: - rkpStatus = KeyStoreException.RKP_FETCHING_PENDING_CONNECTIVITY; - break; - case IGenerateRkpKeyService.Status.DEVICE_NOT_REGISTERED: - rkpStatus = KeyStoreException.RKP_SERVER_REFUSED_ISSUANCE; - break; - case IGenerateRkpKeyService.Status.OK: - // Explicitly return not-OK here so we retry in generateKeyPair. All other cases - // should throw because a retry doesn't make sense if we didn't actually - // provision fresh keys. - return new GenerateKeyPairHelperResult( - KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE, null); - case IGenerateRkpKeyService.Status.NETWORK_COMMUNICATION_ERROR: - case IGenerateRkpKeyService.Status.HTTP_CLIENT_ERROR: - case IGenerateRkpKeyService.Status.HTTP_SERVER_ERROR: - case IGenerateRkpKeyService.Status.HTTP_UNKNOWN_ERROR: - case IGenerateRkpKeyService.Status.INTERNAL_ERROR: - default: - // These errors really should never happen. The best we can do is assume they - // are transient and hint to the caller to retry with back-off. - rkpStatus = KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE; - break; - } - ksException = new KeyStoreException( - ResponseCode.OUT_OF_KEYS, - "Out of RKP keys due to IGenerateRkpKeyService status: " + keyGenStatus, - rkpStatus); - } catch (RemoteException f) { - ksException = new KeyStoreException( - ResponseCode.OUT_OF_KEYS, - "Remote exception: " + f.getMessage(), - KeyStoreException.RKP_TEMPORARILY_UNAVAILABLE); - } - ksException.initCause(e); - throw new ProviderException("Failed to provision new attestation keys.", ksException); - } - private void addAttestationParameters(@NonNull List<KeyParameter> params) throws ProviderException, IllegalArgumentException, DeviceIdAttestationException { byte[] challenge = mSpec.getAttestationChallenge(); diff --git a/libs/WindowManager/Jetpack/Android.bp b/libs/WindowManager/Jetpack/Android.bp index a5b192cd7ceb..abe8f859f2fe 100644 --- a/libs/WindowManager/Jetpack/Android.bp +++ b/libs/WindowManager/Jetpack/Android.bp @@ -55,20 +55,6 @@ prebuilt_etc { } // Extensions -// NOTE: This module is still under active development and must not -// be used in production. Use 'androidx.window.sidecar' instead. -android_library_import { - name: "window-extensions", - aars: ["window-extensions-release.aar"], - sdk_version: "current", -} - -android_library_import { - name: "window-extensions-core", - aars: ["window-extensions-core-release.aar"], - sdk_version: "current", -} - java_library { name: "androidx.window.extensions", srcs: [ @@ -77,8 +63,8 @@ java_library { "src/androidx/window/common/**/*.java", ], static_libs: [ - "window-extensions", - "window-extensions-core", + "androidx.window.extensions_extensions-nodeps", + "androidx.window.extensions.core_core-nodeps", ], installable: true, sdk_version: "core_platform", diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java index 575b0cea78f7..cc46a4bc4ea3 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java @@ -129,12 +129,9 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, * {@link WindowAreaComponent#STATUS_AVAILABLE} or * {@link WindowAreaComponent#STATUS_UNAVAILABLE} if the feature is supported or not in that * state respectively. When the rear display feature is triggered, the status is updated to be - * {@link WindowAreaComponent#STATUS_UNAVAILABLE}. + * {@link WindowAreaComponent#STATUS_ACTIVE}. * TODO(b/240727590): Prefix with AREA_ * - * TODO(b/239833099): Add a STATUS_ACTIVE option to let apps know if a feature is currently - * enabled. - * * @param consumer {@link Consumer} interested in receiving updates to the status of * rear display mode. */ @@ -407,18 +404,21 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, } } - @GuardedBy("mLock") private int getCurrentRearDisplayModeStatus() { if (mRearDisplayState == INVALID_DEVICE_STATE) { return WindowAreaComponent.STATUS_UNSUPPORTED; } + if (!ArrayUtils.contains(mCurrentSupportedDeviceStates, mRearDisplayState)) { + return WindowAreaComponent.STATUS_UNAVAILABLE; + } + if (mRearDisplaySessionStatus == WindowAreaComponent.SESSION_STATE_ACTIVE - || !ArrayUtils.contains(mCurrentSupportedDeviceStates, mRearDisplayState) || isRearDisplayActive()) { - return WindowAreaComponent.STATUS_UNAVAILABLE; + return WindowAreaComponent.STATUS_ACTIVE; } + return WindowAreaComponent.STATUS_AVAILABLE; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java index 8386131b177d..a7a6b3c92157 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java @@ -122,16 +122,6 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { addWindowLayoutInfoListener(activity, extConsumer); } - @Override - public void addWindowLayoutInfoListener(@NonNull @UiContext Context context, - @NonNull java.util.function.Consumer<WindowLayoutInfo> consumer) { - final Consumer<WindowLayoutInfo> extConsumer = consumer::accept; - synchronized (mLock) { - mJavaToExtConsumers.put(consumer, extConsumer); - } - addWindowLayoutInfoListener(context, extConsumer); - } - /** * Similar to {@link #addWindowLayoutInfoListener(Activity, java.util.function.Consumer)}, but * takes a UI Context as a parameter. diff --git a/libs/WindowManager/Jetpack/window-extensions-core-release.aar b/libs/WindowManager/Jetpack/window-extensions-core-release.aar Binary files differdeleted file mode 100644 index 96ff840b984b..000000000000 --- a/libs/WindowManager/Jetpack/window-extensions-core-release.aar +++ /dev/null diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar Binary files differdeleted file mode 100644 index c3b6916121d0..000000000000 --- a/libs/WindowManager/Jetpack/window-extensions-release.aar +++ /dev/null diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS index 852edef544b8..f0ed6ee5cb67 100644 --- a/libs/WindowManager/Shell/OWNERS +++ b/libs/WindowManager/Shell/OWNERS @@ -1,4 +1,4 @@ xutan@google.com # Give submodule owners in shell resource approval -per-file res*/*/*.xml = hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com +per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml index 8d1da0f7ad1b..298ad3025b00 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml @@ -63,11 +63,11 @@ android:tint="@color/bubbles_icon_tint"/> <TextView - android:id="@+id/bubble_manage_menu_dont_bubble_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" - android:textAppearance="@*android:style/TextAppearance.DeviceDefault" /> + android:textAppearance="@*android:style/TextAppearance.DeviceDefault" + android:text="@string/bubbles_dont_bubble_conversation" /> </LinearLayout> diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index d158cec18ce6..36619b7d35dc 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dubbeltik om\nhierdie 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Skermskoot"</string> <string name="close_text" msgid="4986518933445178928">"Maak toe"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Maak kieslys oop"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 7831c3022917..3d0ec321b6d8 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ይህን መተግበሪያ\nለማንቀሳቀስ ሁለቴ መታ ያድርጉ"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"ቅጽበታዊ ገጽ እይታ"</string> <string name="close_text" msgid="4986518933445178928">"ዝጋ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"ምናሌን ክፈት"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 09781c71eb61..e311f66a2553 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"انقر مرّتَين لنقل\nهذا التطبيق."</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-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index 856a1321ef8e..8991588c7152 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"এই এপ্টো\nস্থানান্তৰ কৰিবলৈ দুবাৰ টিপক"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"স্ক্ৰীনশ্বট"</string> <string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"মেনু খোলক"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index 1efeb4abef8c..0efa3b53398f 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Tətbiqi köçürmək üçün iki dəfə toxunun"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tətbiqi köçürmək üçün\niki dəfə toxunun"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Skrinşot"</string> <string name="close_text" msgid="4986518933445178928">"Bağlayın"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Menyunu açın"</string> </resources> 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 6c507667c085..a010a9801526 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvaput dodirnite da biste\npremestili 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string> <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Otvorite meni"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index 88d9793b78ab..e7d22e05937f 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Каб перамясціць праграму,\nнацісніце двойчы"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Здымак экрана"</string> <string name="close_text" msgid="4986518933445178928">"Закрыць"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Адкрыць меню"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index bf061b2dbb13..ad26350bc545 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Докоснете двукратно, за да\nпреместите това приложение"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Екранна снимка"</string> <string name="close_text" msgid="4986518933445178928">"Затваряне"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Отваряне на менюто"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index 453a2fc8472f..eb23dcdad561 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"এই অ্যাপ সরাতে\nডবল ট্যাপ করুন"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"স্ক্রিনশট"</string> <string name="close_text" msgid="4986518933445178928">"বন্ধ করুন"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"মেনু খুলুন"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index 987f0a75a3da..1fbfab42a746 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -94,7 +94,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">"Dodirnite dvaput da pomjerite aplikaciju"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dodirnite dvaput da\npomjerite 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string> <string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Otvaranje menija"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index 499f2d73409a..3f041f4384df 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Fes doble toc per moure aquesta aplicació"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Fes doble toc per\nmoure aquesta aplicació"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string> <string name="close_text" msgid="4986518933445178928">"Tanca"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Obre el menú"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index 8d80b9ab3c76..c734ef8aef5c 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dvojitým klepnutím přesunete aplikaci"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvojitým klepnutím\npřesunete aplikaci"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Snímek obrazovky"</string> <string name="close_text" msgid="4986518933445178928">"Zavřít"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Otevřít nabídku"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index 86d702100b02..036bdc109680 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tryk to gange\nfor 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string> <string name="close_text" msgid="4986518933445178928">"Luk"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Åbn menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index 9d0882822963..ec1b9d3a1734 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Doppeltippen, um die App zu verschieben"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Zum Verschieben\ndoppeltippen"</string> <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 5f6a2930ff9d..11f9dd1c0810 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Πατήστε δύο φορές για\nμετακίνηση αυτής της εφαρμογής"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Στιγμιότυπο οθόνης"</string> <string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Άνοιγμα μενού"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index 346089414cef..216d0c139e15 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -94,7 +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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index 8cba053c4a6a..e3795cc15048 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -94,7 +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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove 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 346089414cef..216d0c139e15 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -94,7 +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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index 346089414cef..216d0c139e15 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -94,7 +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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml index 696e714d3411..b762b80b45cf 100644 --- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml @@ -94,7 +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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove 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 fff274913296..628cf7f17f6f 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -94,7 +94,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">"No volver a mostrar"</string> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Presiona dos veces para mover esta app"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Presiona dos veces\npara 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">"Cerrar"</string> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string> <string name="close_text" msgid="4986518933445178928">"Cerrar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Abrir el menú"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index 5fcd12de2fab..cfa7865a599d 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -94,7 +94,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">"No volver a mostrar"</string> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Toca dos veces para mover esta aplicación"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toca dos veces para\nmover esta aplicación"</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">"Cerrar"</string> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Captura de pantalla"</string> <string name="close_text" msgid="4986518933445178928">"Cerrar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Abrir menú"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index 07fd6838e5dd..666aa46fbfda 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Rakenduse teisaldamiseks topeltpuudutage"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Rakenduse teisaldamiseks\ntopeltpuudutage"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Ekraanipilt"</string> <string name="close_text" msgid="4986518933445178928">"Sule"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Ava menüü"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index be972d9d8120..d7397f312d41 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Sakatu birritan\naplikazioa 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Pantaila-argazkia"</string> <string name="close_text" msgid="4986518933445178928">"Itxi"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Ireki menua"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index 26f5fcf364be..5e13c3e9bdbf 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"برای جابهجا کردن این برنامه\nدوضربه بزنید"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"نماگرفت"</string> <string name="close_text" msgid="4986518933445178928">"بستن"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"باز کردن منو"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index 5686d9a7a440..c047c656f19a 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Siirrä sovellus kaksoisnapauttamalla"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Kaksoisnapauta, jos\nhaluat siirtää sovellusta"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Kuvakaappaus"</string> <string name="close_text" msgid="4986518933445178928">"Sulje"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Avaa valikko"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index 2788de690817..6b60fdca8a58 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -32,17 +32,13 @@ <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> - <!-- 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_forced_resizable" msgid="7429086980048964687">"L\'application peut ne pas fonctionner avec l\'écran partagé"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"L\'application ne prend pas en charge l\'écran partagé"</string> <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> - <!-- no translation found for accessibility_divider (6407584574218956849) --> - <skip /> - <!-- no translation found for divider_title (1963391955593749442) --> - <skip /> + <string name="accessibility_divider" msgid="6407584574218956849">"Séparateur d\'écran partagé"</string> + <string name="divider_title" msgid="1963391955593749442">"Séparateur d\'écran partagé"</string> <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> @@ -89,8 +85,7 @@ <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> - <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> - <skip /> + <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Faites glisser une autre application pour utiliser l\'écran partagé"</string> <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> @@ -99,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Toucher deux fois pour déplacer cette application"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toucher deux fois pour\ndéplacer cette application"</string> <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 6e1a583983b2..768936e27073 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Appuyez deux fois pour déplacer cette appli"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Appuyez deux fois\npour déplacer cette appli"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Capture d\'écran"</string> <string name="close_text" msgid="4986518933445178928">"Fermer"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Ouvrir le menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index aaaf3bdd0dbb..ad5629a1f6cf 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -94,7 +94,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">"Non mostrar outra vez"</string> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Toca dúas veces para mover esta aplicación"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toca dúas veces para\nmover esta aplicación"</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">"Pechar"</string> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index ee5a335af706..29e044fa838e 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"આ ઍપને ખસેડવા માટે\nબે વાર ટૅપ કરો"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"સ્ક્રીનશૉટ"</string> <string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"મેનૂ ખોલો"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index 258862a7b37d..1934aa598ad2 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ऐप्लिकेशन की जगह बदलने के लिए\nदो बार टैप करें"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"स्क्रीनशॉट"</string> <string name="close_text" msgid="4986518933445178928">"बंद करें"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"मेन्यू खोलें"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index 21fdf5dc462e..04a70730fe88 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvaput dodirnite da biste\npremjestili 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Snimka zaslona"</string> <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Otvaranje izbornika"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index a0928d36117e..045af2f015f8 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Koppintson duplán az alkalmazás áthelyezéséhez"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Koppintson duplán\naz alkalmazás áthelyezéséhez"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Képernyőkép"</string> <string name="close_text" msgid="4986518933445178928">"Bezárás"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menü bezárása"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Menü megnyitása"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index f5c2e4bdb457..30499a4f60ee 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Կրկնակի հպեք՝\nհավելվածը տեղափոխելու համար"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Սքրինշոթ"</string> <string name="close_text" msgid="4986518933445178928">"Փակել"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Բացել ընտրացանկը"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index 3a7d4b3dd524..9c8b6147a780 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Ketuk dua kali untuk memindahkan aplikasi ini"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ketuk dua kali untuk\nmemindahkan aplikasi ini"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string> <string name="close_text" msgid="4986518933445178928">"Tutup"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Buka Menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index f745305c6faf..1507fd60e775 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Ýttu tvisvar til að færa þetta forrit"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ýttu tvisvar til\nað færa þetta forrit"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Skjámynd"</string> <string name="close_text" msgid="4986518933445178928">"Loka"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Opna valmynd"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index f1edcedef18c..cd99724d3ae4 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tocca due volte per\nspostare 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string> <string name="close_text" msgid="4986518933445178928">"Chiudi"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Apri menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index d07c91fe14c3..21bee9ff0df5 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"אפשר להקיש הקשה כפולה כדי\nלהעביר את האפליקציה למקום אחר"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"צילום מסך"</string> <string name="close_text" msgid="4986518933445178928">"סגירה"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"פתיחת התפריט"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index ea42aa50e177..9451dbbfa4f6 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -89,12 +89,12 @@ <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> - <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"再起動して画面をすっきりさせますか?"</string> - <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"アプリを再起動して画面をすっきりさせることはできますが、進捗状況が失われ、保存されていない変更が消える可能性があります"</string> + <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"アプリを再起動して画面表示を最適化しますか?"</string> + <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"アプリを再起動することにより表示を最適化できますが、保存されていない変更は失われる可能性があります"</string> <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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ダブルタップすると\nこのアプリを移動できます"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"スクリーンショット"</string> <string name="close_text" msgid="4986518933445178928">"閉じる"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"メニューを開く"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 16ba1aa5f5b6..ab5c83991940 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ამ აპის გადასატანად\nორმაგად შეეხეთ მას"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"ეკრანის ანაბეჭდი"</string> <string name="close_text" msgid="4986518933445178928">"დახურვა"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"მენიუს გახსნა"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index f42cdc322f7d..eb37b55d35b3 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -32,17 +32,13 @@ <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> - <!-- 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_forced_resizable" msgid="7429086980048964687">"Қолданба экранды бөлу режимінде жұмыс істемеуі мүмкін."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Қолданбада экранды бөлу мүмкін емес."</string> <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> - <!-- no translation found for accessibility_divider (6407584574218956849) --> - <skip /> - <!-- no translation found for divider_title (1963391955593749442) --> - <skip /> + <string name="accessibility_divider" msgid="6407584574218956849">"Экранды бөлу режимінің бөлгіші"</string> + <string name="divider_title" msgid="1963391955593749442">"Экранды бөлу режимінің бөлгіші"</string> <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> @@ -89,8 +85,7 @@ <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> - <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> - <skip /> + <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Экранды бөлу үшін басқа қолданбаға өтіңіз."</string> <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> @@ -99,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Бұл қолданбаны басқа орынға\nжылжыту үшін екі рет түртіңіз."</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> @@ -115,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string> <string name="close_text" msgid="4986518933445178928">"Жабу"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Мәзірді ашу"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index be5047ea46f8..b8e7ba1c6bb1 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ចុចពីរដងដើម្បី\nផ្លាស់ទីកម្មវិធីនេះ"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"រូបថតអេក្រង់"</string> <string name="close_text" msgid="4986518933445178928">"បិទ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"បិទម៉ឺនុយ"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"បើកម៉ឺនុយ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index 8b0fae89534d..af8dd9b3c200 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -24,7 +24,7 @@ <string name="pip_menu_title" msgid="5393619322111827096">"ಮೆನು"</string> <string name="pip_menu_accessibility_title" msgid="8129016817688656249">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ ಮೆನು"</string> <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವಾಗಿದೆ"</string> - <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ಈ ವೈಶಿಷ್ಟ್ಯ ಬಳಸುವುದನ್ನು ನೀವು ಬಯಸದಿದ್ದರೆ, ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಲು ಮತ್ತು ಅದನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> + <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ಈ ಫೀಚರ್ ಬಳಸುವುದನ್ನು ನೀವು ಬಯಸದಿದ್ದರೆ, ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಲು ಮತ್ತು ಅದನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="pip_play" msgid="3496151081459417097">"ಪ್ಲೇ"</string> <string name="pip_pause" msgid="690688849510295232">"ವಿರಾಮಗೊಳಿಸಿ"</string> <string name="pip_skip_to_next" msgid="8403429188794867653">"ಮುಂದಕ್ಕೆ ಸ್ಕಿಪ್ ಮಾಡಿ"</string> @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಸರಿಸಲು\nಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string> <string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"ಮೆನು ತೆರೆಯಿರಿ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index 19789899df6d..d9fd59dea513 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"두 번 탭하여\n이 앱 이동"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"스크린샷"</string> <string name="close_text" msgid="4986518933445178928">"닫기"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"메뉴 열기"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index 745cea3f49f5..543948633cf9 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Бул колдонмону жылдыруу үчүн\nэки жолу таптаңыз"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string> <string name="close_text" msgid="4986518933445178928">"Жабуу"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Менюну ачуу"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index 4dd5ade21f66..fe737176b758 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ແຕະສອງເທື່ອເພື່ອ\nຍ້າຍແອັບນີ້"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"ຮູບໜ້າຈໍ"</string> <string name="close_text" msgid="4986518933445178928">"ປິດ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"ເປີດເມນູ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index 7c1e7e1dfb39..37e61a023b64 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dukart palieskite, kad\nperkeltumė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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Ekrano kopija"</string> <string name="close_text" msgid="4986518933445178928">"Uždaryti"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Atidaryti meniu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index 69db08a2adb6..58737b23d2f5 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Lai pārvietotu šo lietotni, veiciet dubultskārienu"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Veiciet dubultskārienu,\nlai pārvietotu šo lietotni"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Ekrānuzņēmums"</string> <string name="close_text" msgid="4986518933445178928">"Aizvērt"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Atvērt izvēlni"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index d9479d38537a..f7bcde9574b6 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Допрете двапати за да ја\nпоместите апликацијава"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Слика од екранот"</string> <string name="close_text" msgid="4986518933445178928">"Затворете"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Отвори го менито"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index 2afde7b21124..1ae95e29508f 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ഈ ആപ്പ് നീക്കാൻ\nഡബിൾ ടാപ്പ് ചെയ്യുക"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"സ്ക്രീൻഷോട്ട്"</string> <string name="close_text" msgid="4986518933445178928">"അടയ്ക്കുക"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"മെനു തുറക്കുക"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index 69bd08e5e63e..312a5e450ccc 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Энэ аппыг зөөхийн тулд\nхоёр товшино уу"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Дэлгэцийн агшин"</string> <string name="close_text" msgid="4986518933445178928">"Хаах"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Цэс нээх"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index 5382b941f4d4..e2da77f17659 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"हे ॲप हलवण्यासाठी\nदोनदा टॅप करा"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"स्क्रीनशॉट"</string> <string name="close_text" msgid="4986518933445178928">"बंद करा"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"मेनू उघडा"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index c1b2d497c27a..9965226ed185 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ketik dua kali untuk\nalih 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Tangkapan skrin"</string> <string name="close_text" msgid="4986518933445178928">"Tutup"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Buka Menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index f3b7bfc3a9a9..f44d976aa2d6 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ဤအက်ပ်ကို ရွှေ့ရန်\nနှစ်ချက်တို့ပါ"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"ဖန်သားပြင်ဓာတ်ပုံ"</string> <string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"မီနူး ဖွင့်ရန်"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index bf197d5f57fc..9cb98733de98 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Dobbelttrykk for å flytte denne appen"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dobbelttrykk for\nå flytte denne appen"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Skjermdump"</string> <string name="close_text" msgid="4986518933445178928">"Lukk"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Åpne menyen"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index 519a7cb89e8c..3d4d2bca99c8 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"यो एप सार्न डबल\nट्याप गर्नुहोस्"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"स्क्रिनसट"</string> <string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"मेनु खोल्नुहोस्"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index 7847901a390e..796cb057fcdc 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dubbeltik om\ndeze 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string> <string name="close_text" msgid="4986518933445178928">"Sluiten"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Menu openen"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index efc1af335fc3..185ece610464 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ଏହି ଆପକୁ ମୁଭ\nକରିବା ପାଇଁ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"ସ୍କ୍ରିନସଟ"</string> <string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"ମେନୁ ଖୋଲନ୍ତୁ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index fbcaf6e9c1c4..12a9f714b053 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ਇਸ ਐਪ ਦਾ ਟਿਕਾਣਾ ਬਦਲਣ ਲਈ\nਡਬਲ ਟੈਪ ਕਰੋ"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string> <string name="close_text" msgid="4986518933445178928">"ਬੰਦ ਕਰੋ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ਮੀਨੂ ਬੰਦ ਕਰੋ"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"ਮੀਨੂ ਖੋਲ੍ਹੋ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index 9451c6efbad1..ce37cda079cf 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Aby przenieść aplikację,\nkliknij dwukrotnie"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Zrzut ekranu"</string> <string name="close_text" msgid="4986518933445178928">"Zamknij"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Otwórz menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index 6b187193fd7f..317ebf2b5d5a 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes para\nmover 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Captura de tela"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Abrir o menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index ede86fa2a18e..708d3d91f58a 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes\npara 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Captura de ecrã"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Abrir menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index 6b187193fd7f..317ebf2b5d5a 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes para\nmover 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Captura de tela"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Abrir o menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index 4aade7f87171..dbd9ac3ee05c 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Atinge de două ori ca să muți aplicația"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Atinge de două ori\nca să muți aplicația"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Captură de ecran"</string> <string name="close_text" msgid="4986518933445178928">"Închide"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Deschide meniul"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index b9733dd00bd1..a773b3752d13 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Дважды нажмите, чтобы\nпереместить приложение."</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Скриншот"</string> <string name="close_text" msgid="4986518933445178928">"Закрыть"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыть меню"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Открыть меню"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index 3b6769324c17..624d7711a625 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"මෙම යෙදුම ගෙන යාමට\nදෙවරක් තට්ටු කරන්න"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"තිර රුව"</string> <string name="close_text" msgid="4986518933445178928">"වසන්න"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"මෙනුව විවෘත කරන්න"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index adf582fdf6be..5c7d173df79c 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Túto aplikáciu\npresuniete 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Snímka obrazovky"</string> <string name="close_text" msgid="4986518933445178928">"Zavrieť"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Otvoriť ponuku"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index 08c1b3811a6e..03c68ffc435c 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvakrat se dotaknite\nza premik te aplikacije"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Posnetek zaslona"</string> <string name="close_text" msgid="4986518933445178928">"Zapri"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Odpri meni"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index e184ee025d83..3878c47a9518 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Trokit dy herë për të\nlë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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Pamja e ekranit"</string> <string name="close_text" msgid="4986518933445178928">"Mbyll"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Hap menynë"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index e6be8d34861e..20ccbd771f72 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Двапут додирните да бисте\nпреместили ову апликацију"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Снимак екрана"</string> <string name="close_text" msgid="4986518933445178928">"Затворите"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Отворите мени"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index a5c4e232347c..b7035c1c5145 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Tryck snabbt två gånger för att flytta denna app"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tryck snabbt två gånger\nför att flytta denna app"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Skärmbild"</string> <string name="close_text" msgid="4986518933445178928">"Stäng"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Öppna menyn"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index f25f7db8ab88..cac1debe2f09 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Gusa mara mbili ili\nusogeze 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Picha ya skrini"</string> <string name="close_text" msgid="4986518933445178928">"Funga"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Fungua Menyu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index b150164de82a..23a2cdc999c9 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -32,17 +32,13 @@ <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> - <!-- 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_forced_resizable" msgid="7429086980048964687">"திரைப் பிரிப்புப் பயன்முறையில் ஆப்ஸ் செயல்படாமல் போகக்கூடும்"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"திரைப் பிரிப்புப் பயன்முறையை ஆப்ஸ் ஆதரிக்காது"</string> <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> - <!-- no translation found for accessibility_divider (6407584574218956849) --> - <skip /> - <!-- no translation found for divider_title (1963391955593749442) --> - <skip /> + <string name="accessibility_divider" msgid="6407584574218956849">"திரைப் பிரிப்பான்"</string> + <string name="divider_title" msgid="1963391955593749442">"திரைப் பிரிப்பான்"</string> <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> @@ -89,8 +85,7 @@ <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> - <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> - <skip /> + <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"திரைப் பிரிப்புக்கு மற்றொரு ஆப்ஸை இழுக்கலாம்"</string> <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> @@ -99,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"இந்த ஆப்ஸை நகர்த்த\nஇருமுறை தட்டவும்"</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-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index c75930b46170..6b415900ab98 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ఈ యాప్ను తరలించడానికి\nడబుల్-ట్యాప్ చేయండి"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"స్క్రీన్షాట్"</string> <string name="close_text" msgid="4986518933445178928">"మూసివేయండి"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"మెనూను తెరవండి"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index 22368c06fde8..e61904e85b4a 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"แตะสองครั้ง\nเพื่อย้ายแอปนี้"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"ภาพหน้าจอ"</string> <string name="close_text" msgid="4986518933445178928">"ปิด"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"เปิดเมนู"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index de253665b3b9..822f7ebcac23 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"I-double tap para\nilipat 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Screenshot"</string> <string name="close_text" msgid="4986518933445178928">"Isara"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Buksan ang Menu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index bf4feda83121..26081e157086 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -94,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Bu uygulamayı taşımak için iki kez dokunun"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Bu uygulamayı taşımak için\niki kez dokunun"</string> <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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Ekran görüntüsü"</string> <string name="close_text" msgid="4986518933445178928">"Kapat"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Menüyü Aç"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index 2800e4cc8ce1..aacf1ffde371 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Двічі торкніться, щоб\nперемістити цей додаток"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Знімок екрана"</string> <string name="close_text" msgid="4986518933445178928">"Закрити"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Відкрити меню"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index f94ee98d513e..f494e08166a9 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"اس ایپ کو منتقل کرنے کیلئے\nدو بار تھپتھپائیں"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"اسکرین شاٹ"</string> <string name="close_text" msgid="4986518933445178928">"بند کریں"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"مینو کھولیں"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index ac7cc724d459..9b5aa6fcfade 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Bu ilovani siljitish uchun\nikki 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Skrinshot"</string> <string name="close_text" msgid="4986518933445178928">"Yopish"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Menyuni ochish"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index fab5ec162cab..fe5461ecd1d7 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -32,17 +32,13 @@ <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> - <!-- 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_forced_resizable" msgid="7429086980048964687">"Có thể ứng dụng không dùng được chế độ chia đôi màn hình"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Ứng dụng không hỗ trợ chế độ chia đôi màn hình"</string> <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> - <!-- no translation found for accessibility_divider (6407584574218956849) --> - <skip /> - <!-- no translation found for divider_title (1963391955593749442) --> - <skip /> + <string name="accessibility_divider" msgid="6407584574218956849">"Trình chia đôi màn hình"</string> + <string name="divider_title" msgid="1963391955593749442">"Trình chia đôi màn hình"</string> <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> @@ -89,8 +85,7 @@ <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> - <!-- no translation found for letterbox_education_split_screen_text (449233070804658627) --> - <skip /> + <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"Kéo một ứng dụng khác vào để chia đôi màn hình"</string> <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> @@ -99,7 +94,7 @@ <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> - <string name="letterbox_reachability_reposition_text" msgid="4507890186297500893">"Nhấn đúp để di chuyển ứng dụng này"</string> + <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Nhấn đúp để\ndi chuyển ứng dụng này"</string> <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> @@ -115,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Ảnh chụp màn hình"</string> <string name="close_text" msgid="4986518933445178928">"Đóng"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Mở Trình đơn"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index 5cf7ab27b5f1..040aff836a5a 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"点按两次\n即可移动此应用"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"屏幕截图"</string> <string name="close_text" msgid="4986518933445178928">"关闭"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"打开菜单"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index 03a14389b6b7..5fac19b4f316 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"輕按兩下\n即可移動此應用程式"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string> <string name="close_text" msgid="4986518933445178928">"關閉"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"打開選單"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index d0e52b4e8186..0a2533539867 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"輕觸兩下即可\n移動這個應用程式"</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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"螢幕截圖"</string> <string name="close_text" msgid="4986518933445178928">"關閉"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"開啟選單"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index 0eb314886055..5b85be2d262c 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -94,7 +94,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="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Thepha kabili ukuze\nuhambise 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> @@ -110,6 +110,5 @@ <string name="screenshot_text" msgid="1477704010087786671">"Isithombe-skrini"</string> <string name="close_text" msgid="4986518933445178928">"Vala"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string> - <!-- no translation found for expand_menu_text (3847736164494181168) --> - <skip /> + <string name="expand_menu_text" msgid="3847736164494181168">"Vula Imenyu"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index 87a7c3edf826..b192fdf245e2 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -146,8 +146,6 @@ <string name="bubbles_app_settings"><xliff:g id="notification_title" example="Android Messages">%1$s</xliff:g> settings</string> <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] --> <string name="bubble_dismiss_text">Dismiss bubble</string> - <!-- Button text to stop an app from bubbling [CHAR LIMIT=60]--> - <string name="bubbles_dont_bubble">Don\u2019t bubble</string> <!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]--> <string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string> <!-- Title text for the bubbles feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=60]--> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java index 521a65cc4df6..bfbddbbe4aa0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java @@ -22,6 +22,7 @@ import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; import static java.util.Objects.requireNonNull; import android.content.Context; +import android.graphics.Rect; import android.os.IBinder; import android.util.ArrayMap; import android.view.SurfaceControl; @@ -35,6 +36,9 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; +import com.android.wm.shell.util.TransitionUtil; + +import java.util.List; /** * Responsible for handling ActivityEmbedding related transitions. @@ -86,12 +90,13 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { boolean containsEmbeddingSplit = false; - for (TransitionInfo.Change change : info.getChanges()) { + boolean containsNonEmbeddedChange = false; + final List<TransitionInfo.Change> changes = info.getChanges(); + for (int i = changes.size() - 1; i >= 0; i--) { + final TransitionInfo.Change change = changes.get(i); if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) { - // Only animate the transition if all changes are in a Task with ActivityEmbedding. - return false; - } - if (!containsEmbeddingSplit && !change.hasFlags(FLAG_FILLS_TASK)) { + containsNonEmbeddedChange = true; + } else if (!change.hasFlags(FLAG_FILLS_TASK)) { // Whether the Task contains any ActivityEmbedding split before or after the // transition. containsEmbeddingSplit = true; @@ -103,6 +108,9 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle // such as the device is in a folded state. return false; } + if (containsNonEmbeddedChange && !handleNonEmbeddedChanges(changes)) { + return false; + } // Start ActivityEmbedding animation. mTransitionCallbacks.put(transition, finishCallback); @@ -110,6 +118,37 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle return true; } + private boolean handleNonEmbeddedChanges(List<TransitionInfo.Change> changes) { + final Rect nonClosingEmbeddedArea = new Rect(); + for (int i = changes.size() - 1; i >= 0; i--) { + final TransitionInfo.Change change = changes.get(i); + if (!TransitionUtil.isClosingType(change.getMode())) { + if (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) { + nonClosingEmbeddedArea.union(change.getEndAbsBounds()); + continue; + } + // Not able to handle non-embedded container if it is not closing. + return false; + } + } + for (int i = changes.size() - 1; i >= 0; i--) { + final TransitionInfo.Change change = changes.get(i); + if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY) + && !nonClosingEmbeddedArea.contains(change.getEndAbsBounds())) { + // Unknown to animate containers outside the area of embedded activities. + return false; + } + } + // Drop the non-embedded closing change because it is occluded by embedded activities. + for (int i = changes.size() - 1; i >= 0; i--) { + final TransitionInfo.Change change = changes.get(i); + if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) { + changes.remove(i); + } + } + return true; + } + @Nullable @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, 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 e84a78f42616..133fd87a2f63 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 @@ -33,12 +33,19 @@ public interface BackAnimation { * * @param touchX the X touch position of the {@link MotionEvent}. * @param touchY the Y touch position of the {@link MotionEvent}. + * @param velocityX the X velocity computed from the {@link MotionEvent}. + * @param velocityY the Y velocity computed from the {@link MotionEvent}. * @param keyAction the original {@link KeyEvent#getAction()} when the event was dispatched to * the process. This is forwarded separately because the input pipeline may mutate * the {#event} action state later. * @param swipeEdge the edge from which the swipe begins. */ - void onBackMotion(float touchX, float touchY, int keyAction, + void onBackMotion( + float touchX, + float touchY, + float velocityX, + float velocityY, + int keyAction, @BackEvent.SwipeEdge int swipeEdge); /** 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 210c9aab14d6..47d3a5c52074 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 @@ -256,8 +256,20 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private class BackAnimationImpl implements BackAnimation { @Override public void onBackMotion( - float touchX, float touchY, int keyAction, @BackEvent.SwipeEdge int swipeEdge) { - mShellExecutor.execute(() -> onMotionEvent(touchX, touchY, keyAction, swipeEdge)); + float touchX, + float touchY, + float velocityX, + float velocityY, + int keyAction, + @BackEvent.SwipeEdge int swipeEdge + ) { + mShellExecutor.execute(() -> onMotionEvent( + /* touchX = */ touchX, + /* touchY = */ touchY, + /* velocityX = */ velocityX, + /* velocityY = */ velocityY, + /* keyAction = */ keyAction, + /* swipeEdge = */ swipeEdge)); } @Override @@ -332,13 +344,18 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont * Called when a new motion event needs to be transferred to this * {@link BackAnimationController} */ - public void onMotionEvent(float touchX, float touchY, int keyAction, + public void onMotionEvent( + float touchX, + float touchY, + float velocityX, + float velocityY, + int keyAction, @BackEvent.SwipeEdge int swipeEdge) { if (mPostCommitAnimationInProgress) { return; } - mTouchTracker.update(touchX, touchY); + mTouchTracker.update(touchX, touchY, velocityX, velocityY); if (keyAction == MotionEvent.ACTION_DOWN) { if (!mBackGestureStarted) { mShouldStartOnNextMoveEvent = true; @@ -561,6 +578,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } if (runner.isWaitingAnimation()) { ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Gesture released, but animation didn't ready."); + // Supposed it is in post commit animation state, and start the timeout to watch + // if the animation is ready. + mShellExecutor.executeDelayed(mAnimationTimeoutRunnable, MAX_ANIMATION_DURATION); return; } else if (runner.isAnimationCancelled()) { invokeOrCancelBack(); @@ -577,6 +597,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont if (mPostCommitAnimationInProgress) { return; } + + mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable); ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: startPostCommitAnimation()"); mPostCommitAnimationInProgress = true; mShellExecutor.executeDelayed(mAnimationTimeoutRunnable, MAX_ANIMATION_DURATION); @@ -595,9 +617,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont */ @VisibleForTesting void onBackAnimationFinished() { - if (!mPostCommitAnimationInProgress) { - return; - } // Stop timeout runner. mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable); mPostCommitAnimationInProgress = false; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java index 695ef4e66302..904574b08562 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java @@ -42,11 +42,13 @@ class TouchTracker { */ private float mInitTouchX; private float mInitTouchY; + private float mLatestVelocityX; + private float mLatestVelocityY; private float mStartThresholdX; private int mSwipeEdge; private boolean mCancelled; - void update(float touchX, float touchY) { + void update(float touchX, float touchY, float velocityX, float velocityY) { /** * If back was previously cancelled but the user has started swiping in the forward * direction again, restart back. @@ -58,6 +60,8 @@ class TouchTracker { } mLatestTouchX = touchX; mLatestTouchY = touchY; + mLatestVelocityX = velocityX; + mLatestVelocityY = velocityY; } void setTriggerBack(boolean triggerBack) { @@ -84,7 +88,14 @@ class TouchTracker { } BackMotionEvent createStartEvent(RemoteAnimationTarget target) { - return new BackMotionEvent(mInitTouchX, mInitTouchY, 0, mSwipeEdge, target); + return new BackMotionEvent( + /* touchX = */ mInitTouchX, + /* touchY = */ mInitTouchY, + /* progress = */ 0, + /* velocityX = */ 0, + /* velocityY = */ 0, + /* swipeEdge = */ mSwipeEdge, + /* departingAnimationTarget = */ target); } BackMotionEvent createProgressEvent() { @@ -111,7 +122,14 @@ class TouchTracker { } BackMotionEvent createProgressEvent(float progress) { - return new BackMotionEvent(mLatestTouchX, mLatestTouchY, progress, mSwipeEdge, null); + return new BackMotionEvent( + /* touchX = */ mLatestTouchX, + /* touchY = */ mLatestTouchY, + /* progress = */ progress, + /* velocityX = */ mLatestVelocityX, + /* velocityY = */ mLatestVelocityY, + /* swipeEdge = */ mSwipeEdge, + /* departingAnimationTarget = */ null); } public void setProgressThreshold(float progressThreshold) { 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 8f364b448bf2..026ea069419d 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,8 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; +import com.android.launcher3.icons.BubbleBadgeIconFactory; +import com.android.launcher3.icons.BubbleIconFactory; import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; import com.android.wm.shell.common.bubbles.BubbleInfo; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleBadgeIconFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleBadgeIconFactory.java deleted file mode 100644 index 56b13b8dcd46..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleBadgeIconFactory.java +++ /dev/null @@ -1,120 +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.wm.shell.bubbles; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Path; -import android.graphics.Rect; -import android.graphics.drawable.AdaptiveIconDrawable; -import android.graphics.drawable.Drawable; - -import com.android.launcher3.icons.BaseIconFactory; -import com.android.launcher3.icons.BitmapInfo; -import com.android.wm.shell.R; - -/** - * Factory for creating app badge icons that are shown on bubbles. - */ -public class BubbleBadgeIconFactory extends BaseIconFactory { - - public BubbleBadgeIconFactory(Context context) { - super(context, context.getResources().getConfiguration().densityDpi, - context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size)); - } - - /** - * Returns a {@link BitmapInfo} for the app-badge that is shown on top of each bubble. This - * will include the workprofile indicator on the badge if appropriate. - */ - BitmapInfo getBadgeBitmap(Drawable userBadgedAppIcon, boolean isImportantConversation) { - if (userBadgedAppIcon instanceof AdaptiveIconDrawable) { - AdaptiveIconDrawable ad = (AdaptiveIconDrawable) userBadgedAppIcon; - userBadgedAppIcon = new CircularAdaptiveIcon(ad.getBackground(), ad.getForeground()); - } - if (isImportantConversation) { - userBadgedAppIcon = new CircularRingDrawable(userBadgedAppIcon); - } - Bitmap userBadgedBitmap = createIconBitmap( - userBadgedAppIcon, 1, MODE_WITH_SHADOW); - return createIconBitmap(userBadgedBitmap); - } - - private class CircularRingDrawable extends CircularAdaptiveIcon { - - final int mImportantConversationColor; - final int mRingWidth; - final Rect mInnerBounds = new Rect(); - - final Drawable mDr; - - CircularRingDrawable(Drawable dr) { - super(null, null); - mDr = dr; - mImportantConversationColor = mContext.getResources().getColor( - R.color.important_conversation, null); - mRingWidth = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.importance_ring_stroke_width); - } - - @Override - public void draw(Canvas canvas) { - int save = canvas.save(); - canvas.clipPath(getIconMask()); - canvas.drawColor(mImportantConversationColor); - mInnerBounds.set(getBounds()); - mInnerBounds.inset(mRingWidth, mRingWidth); - canvas.translate(mInnerBounds.left, mInnerBounds.top); - mDr.setBounds(0, 0, mInnerBounds.width(), mInnerBounds.height()); - mDr.draw(canvas); - canvas.restoreToCount(save); - } - } - - private static class CircularAdaptiveIcon extends AdaptiveIconDrawable { - - final Path mPath = new Path(); - - CircularAdaptiveIcon(Drawable bg, Drawable fg) { - super(bg, fg); - } - - @Override - public Path getIconMask() { - mPath.reset(); - Rect bounds = getBounds(); - mPath.addOval(bounds.left, bounds.top, bounds.right, bounds.bottom, Path.Direction.CW); - return mPath; - } - - @Override - public void draw(Canvas canvas) { - int save = canvas.save(); - canvas.clipPath(getIconMask()); - - Drawable d; - if ((d = getBackground()) != null) { - d.draw(canvas); - } - if ((d = getForeground()) != null) { - d.draw(canvas); - } - canvas.restoreToCount(save); - } - } -} 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 da8eb479a77b..fd66153c24c4 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 @@ -89,6 +89,9 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; +import com.android.launcher3.icons.BubbleBadgeIconFactory; +import com.android.launcher3.icons.BubbleIconFactory; +import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; @@ -317,8 +320,13 @@ public class BubbleController implements ConfigurationChangeListener, mBubblePositioner = positioner; mBubbleData = data; mSavedUserBubbleData = new SparseArray<>(); - mBubbleIconFactory = new BubbleIconFactory(context); - mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(context); + mBubbleIconFactory = new BubbleIconFactory(context, + context.getResources().getDimensionPixelSize(R.dimen.bubble_size)); + mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(context, + context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size), + context.getResources().getColor(R.color.important_conversation), + context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.importance_ring_stroke_width)); mDisplayController = displayController; mTaskViewTransitions = taskViewTransitions; mOneHandedOptional = oneHandedOptional; @@ -927,8 +935,13 @@ public class BubbleController implements ConfigurationChangeListener, if (mStackView != null) { mStackView.onThemeChanged(); } - mBubbleIconFactory = new BubbleIconFactory(mContext); - mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext); + mBubbleIconFactory = new BubbleIconFactory(mContext, + mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size)); + mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext, + mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size), + mContext.getResources().getColor(R.color.important_conversation), + mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.importance_ring_stroke_width)); // Reload each bubble for (Bubble b : mBubbleData.getBubbles()) { @@ -964,8 +977,13 @@ public class BubbleController implements ConfigurationChangeListener, mDensityDpi = newConfig.densityDpi; mScreenBounds.set(newConfig.windowConfiguration.getBounds()); mBubbleData.onMaxBubblesChanged(); - mBubbleIconFactory = new BubbleIconFactory(mContext); - mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext); + mBubbleIconFactory = new BubbleIconFactory(mContext, + mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size)); + mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext, + mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size), + mContext.getResources().getColor(R.color.important_conversation), + mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.importance_ring_stroke_width)); mStackView.onDisplaySizeChanged(); } if (newConfig.fontScale != mFontScale) { @@ -1052,7 +1070,27 @@ public class BubbleController implements ConfigurationChangeListener, * Expands and selects the provided bubble as long as it already exists in the stack or the * overflow. * - * This is currently only used when opening a bubble via clicking on a conversation widget. + * This is used by external callers (launcher). + */ + public void expandStackAndSelectBubbleFromLauncher(String key) { + Bubble b = mBubbleData.getAnyBubbleWithkey(key); + if (b == null) { + return; + } + if (mBubbleData.hasBubbleInStackWithKey(b.getKey())) { + // already in the stack + mBubbleData.setSelectedBubbleFromLauncher(b); + mLayerView.showExpandedView(b); + } else if (mBubbleData.hasOverflowBubbleWithKey(b.getKey())) { + // TODO: (b/271468319) handle overflow + } else { + Log.w(TAG, "didn't add bubble from launcher: " + key); + } + } + + /** + * Expands and selects the provided bubble as long as it already exists in the stack or the + * overflow. This is currently used when opening a bubble via clicking on a conversation widget. */ public void expandStackAndSelectBubble(Bubble b) { if (b == null) { @@ -1703,6 +1741,14 @@ public class BubbleController implements ConfigurationChangeListener, // Update the cached state for queries from SysUI mImpl.mCachedState.update(update); + + if (isShowingAsBubbleBar() && mBubbleStateListener != null) { + BubbleBarUpdate bubbleBarUpdate = update.toBubbleBarUpdate(); + // Some updates aren't relevant to the bubble bar so check first. + if (bubbleBarUpdate.anythingChanged()) { + mBubbleStateListener.onBubbleStateChange(bubbleBarUpdate); + } + } } }; @@ -1972,17 +2018,20 @@ public class BubbleController implements ConfigurationChangeListener, @Override public void showBubble(String key, boolean onLauncherHome) { - // TODO + mMainExecutor.execute(() -> { + mBubblePositioner.setShowingInBubbleBar(onLauncherHome); + mController.expandStackAndSelectBubbleFromLauncher(key); + }); } @Override public void removeBubble(String key, int reason) { - // TODO + // TODO (b/271466616) allow removals from launcher } @Override public void collapseBubbles() { - // TODO + mMainExecutor.execute(() -> mController.collapseStack()); } @Override 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 a26c0c487d19..f9cf9d34ec31 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 @@ -334,6 +334,35 @@ public class BubbleData { dispatchPendingChanges(); } + /** + * Sets the selected bubble and expands it, but doesn't dispatch changes + * to {@link BubbleData.Listener}. This is used for updates coming from launcher whose views + * will already be updated so we don't need to notify them again, but BubbleData should be + * updated to have the correct state. + */ + public void setSelectedBubbleFromLauncher(BubbleViewProvider bubble) { + if (DEBUG_BUBBLE_DATA) { + Log.d(TAG, "setSelectedBubbleFromLauncher: " + bubble); + } + mExpanded = true; + if (Objects.equals(bubble, mSelectedBubble)) { + return; + } + boolean isOverflow = bubble != null && BubbleOverflow.KEY.equals(bubble.getKey()); + if (bubble != null + && !mBubbles.contains(bubble) + && !mOverflowBubbles.contains(bubble) + && !isOverflow) { + Log.e(TAG, "Cannot select bubble which doesn't exist!" + + " (" + bubble + ") bubbles=" + mBubbles); + return; + } + if (bubble != null && !isOverflow) { + ((Bubble) bubble).markAsAccessedAt(mTimeSource.currentTimeMillis()); + } + mSelectedBubble = bubble; + } + public void setSelectedBubble(BubbleViewProvider bubble) { if (DEBUG_BUBBLE_DATA) { Log.d(TAG, "setSelectedBubble: " + bubble); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java deleted file mode 100644 index 4ded3ea951e5..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.wm.shell.bubbles; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.content.Intent; -import android.content.pm.LauncherApps; -import android.content.pm.ShortcutInfo; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; - -import androidx.annotation.VisibleForTesting; - -import com.android.launcher3.icons.BaseIconFactory; -import com.android.wm.shell.R; - -/** - * Factory for creating normalized bubble icons. - * We are not using Launcher's IconFactory because bubbles only runs on the UI thread, - * so there is no need to manage a pool across multiple threads. - */ -@VisibleForTesting -public class BubbleIconFactory extends BaseIconFactory { - - public BubbleIconFactory(Context context) { - super(context, context.getResources().getConfiguration().densityDpi, - context.getResources().getDimensionPixelSize(R.dimen.bubble_size)); - } - - /** - * Returns the drawable that the developer has provided to display in the bubble. - */ - Drawable getBubbleDrawable(@NonNull final Context context, - @Nullable final ShortcutInfo shortcutInfo, @Nullable final Icon ic) { - if (shortcutInfo != null) { - LauncherApps launcherApps = - (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); - int density = context.getResources().getConfiguration().densityDpi; - return launcherApps.getShortcutIconDrawable(shortcutInfo, density); - } else { - if (ic != null) { - if (ic.getType() == Icon.TYPE_URI - || ic.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) { - context.grantUriPermission(context.getPackageName(), - ic.getUri(), - Intent.FLAG_GRANT_READ_URI_PERMISSION); - } - return ic.loadDrawable(context); - } - return null; - } - } - - /** - * Creates the bitmap for the provided drawable and returns the scale used for - * drawing the actual drawable. - */ - public Bitmap createIconBitmap(@NonNull Drawable icon, float[] outScale) { - if (outScale == null) { - outScale = new float[1]; - } - icon = normalizeAndWrapToAdaptiveIcon(icon, - true /* shrinkNonAdaptiveIcons */, - null /* outscale */, - outScale); - return createIconBitmap(icon, outScale[0], MODE_WITH_SHADOW); - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt index 6cdb80b2bb93..c2a05b715f44 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt @@ -28,6 +28,7 @@ import android.util.PathParser import android.util.TypedValue import android.view.LayoutInflater import android.widget.FrameLayout +import com.android.launcher3.icons.BubbleIconFactory import com.android.wm.shell.R import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView @@ -93,7 +94,8 @@ class BubbleOverflow( val shapeColor = res.getColor(android.R.color.system_accent1_1000) overflowBtn?.iconDrawable?.setTint(shapeColor) - val iconFactory = BubbleIconFactory(context) + val iconFactory = BubbleIconFactory(context, + context.getResources().getDimensionPixelSize(R.dimen.bubble_size)) // Update bitmap val fg = InsetDrawable(overflowBtn?.iconDrawable, overflowIconInset) 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 66241628fc77..1b20f67e42ab 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 @@ -842,7 +842,7 @@ public class BubbleStackView extends FrameLayout private DismissView mDismissView; private ViewGroup mManageMenu; - private TextView mManageDontBubbleText; + private ViewGroup mManageDontBubbleView; private ViewGroup mManageSettingsView; private ImageView mManageSettingsIcon; private TextView mManageSettingsText; @@ -1217,8 +1217,8 @@ public class BubbleStackView extends FrameLayout mUnbubbleConversationCallback.accept(mBubbleData.getSelectedBubble().getKey()); }); - mManageDontBubbleText = mManageMenu - .findViewById(R.id.bubble_manage_menu_dont_bubble_text); + mManageDontBubbleView = mManageMenu + .findViewById(R.id.bubble_manage_menu_dont_bubble_container); mManageSettingsView = mManageMenu.findViewById(R.id.bubble_manage_menu_settings_container); mManageSettingsView.setOnClickListener( @@ -2890,14 +2890,16 @@ public class BubbleStackView extends FrameLayout final Bubble bubble = mBubbleData.getBubbleInStackWithKey(mExpandedBubble.getKey()); if (bubble != null && !bubble.isAppBubble()) { // Setup options for non app bubbles - mManageDontBubbleText.setText(R.string.bubbles_dont_bubble_conversation); + mManageDontBubbleView.setVisibility(VISIBLE); mManageSettingsIcon.setImageBitmap(bubble.getRawAppBadge()); mManageSettingsText.setText(getResources().getString( R.string.bubbles_app_settings, bubble.getAppName())); mManageSettingsView.setVisibility(VISIBLE); } else { // Setup options for app bubbles - mManageDontBubbleText.setText(R.string.bubbles_dont_bubble); + // App bubbles have no conversations + // so we don't show the option to not bubble conversation + mManageDontBubbleView.setVisibility(GONE); // App bubbles are not notification based // so we don't show the option to go to notification settings mManageSettingsView.setVisibility(GONE); @@ -2966,6 +2968,15 @@ public class BubbleStackView extends FrameLayout } /** + * Checks whether manage menu don't bubble conversation action is available and visible + * Used for testing + */ + @VisibleForTesting + public boolean isManageMenuDontBubbleVisible() { + return mManageDontBubbleView != null && mManageDontBubbleView.getVisibility() == VISIBLE; + } + + /** * Checks whether manage menu notification settings action is available and visible * Used for testing */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java index 1a97c0504b37..d1081de11f30 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java @@ -42,6 +42,8 @@ import android.view.LayoutInflater; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.launcher3.icons.BitmapInfo; +import com.android.launcher3.icons.BubbleBadgeIconFactory; +import com.android.launcher3.icons.BubbleIconFactory; import com.android.wm.shell.R; import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 670b24c176b5..0400963a47e8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -25,6 +25,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.app.WindowConfiguration.WindowingMode import android.content.Context +import android.graphics.Point import android.graphics.Rect import android.os.IBinder import android.os.SystemProperties @@ -193,6 +194,21 @@ class DesktopTasksController( } } + + /** + * Move a task to fullscreen after being dragged from fullscreen and released back into + * status bar area + */ + fun cancelMoveToFreeform(task: RunningTaskInfo, startPosition: Point) { + val wct = WindowContainerTransaction() + addMoveToFullscreenChanges(wct, task.token) + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition) + } else { + shellTaskOrganizer.applyTransaction(wct) + } + } + fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) { val wct = WindowContainerTransaction() addMoveToFullscreenChanges(wct, task.token) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java index 3df2340d4524..27eda16f4171 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java @@ -17,11 +17,13 @@ package com.android.wm.shell.desktopmode; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.ActivityManager; +import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.view.SurfaceControl; @@ -55,6 +57,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition public static final int FREEFORM_ANIMATION_DURATION = 336; private final List<IBinder> mPendingTransitionTokens = new ArrayList<>(); + private Point mStartPosition; public EnterDesktopTaskTransitionHandler( Transitions transitions) { @@ -79,6 +82,17 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition mPendingTransitionTokens.add(token); } + /** + * Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE + * @param wct WindowContainerTransaction for transition + * @param startPosition Position of task when transition is triggered + */ + public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct, + Point startPosition) { + mStartPosition = startPosition; + startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct); + } + @Override public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT, @@ -173,6 +187,37 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition return true; } + if (type == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE + && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + && mStartPosition != null) { + // This Transition animates a task to fullscreen after being dragged from the status + // bar and then released back into the status bar area + final SurfaceControl sc = change.getLeash(); + startT.setWindowCrop(sc, null); + startT.apply(); + + final ValueAnimator animator = new ValueAnimator(); + animator.setFloatValues(DRAG_FREEFORM_SCALE, 1f); + animator.setDuration(FREEFORM_ANIMATION_DURATION); + final SurfaceControl.Transaction t = mTransactionSupplier.get(); + animator.addUpdateListener(animation -> { + final float scale = animation.getAnimatedFraction(); + t.setPosition(sc, mStartPosition.x * (1 - scale), + mStartPosition.y * (1 - scale)); + t.setScale(sc, scale, scale); + t.apply(); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mTransitions.getMainExecutor().execute( + () -> finishCallback.onTransitionFinished(null, null)); + } + }); + animator.start(); + return true; + } + return false; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS index 926cfb3b12ef..deb7c6db338f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS @@ -1,2 +1,3 @@ # WM shell sub-module desktop owners +atsjenk@google.com madym@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS index 0c2d5c49f830..ccbb9cf298a2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS @@ -1,2 +1,3 @@ # WM shell sub-module freeform owners +atsjenk@google.com madym@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index f70df833cf4f..1d7e64988359 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -30,14 +30,17 @@ import android.app.TaskInfo; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Rect; +import android.os.SystemClock; import android.view.Surface; import android.view.SurfaceControl; import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; +import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.animation.Interpolators; +import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.transition.Transitions; import java.lang.annotation.Retention; @@ -61,6 +64,14 @@ public class PipAnimationController { @Retention(RetentionPolicy.SOURCE) public @interface AnimationType {} + /** + * The alpha type is set for swiping to home. But the swiped task may not enter PiP. And if + * another task enters PiP by non-swipe ways, e.g. call API in foreground or switch to 3-button + * navigation, then the alpha type is unexpected. So use a timeout to avoid applying wrong + * animation style to an unrelated task. + */ + private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 800; + public static final int TRANSITION_DIRECTION_NONE = 0; public static final int TRANSITION_DIRECTION_SAME = 1; public static final int TRANSITION_DIRECTION_TO_PIP = 2; @@ -109,6 +120,9 @@ public class PipAnimationController { }); private PipTransitionAnimator mCurrentAnimator; + @AnimationType + private int mOneShotAnimationType = ANIM_TYPE_BOUNDS; + private long mLastOneShotAlphaAnimationTime; public PipAnimationController(PipSurfaceTransactionHelper helper) { mSurfaceTransactionHelper = helper; @@ -222,6 +236,37 @@ public class PipAnimationController { } /** + * Sets the preferred enter animation type for one time. This is typically used to set the + * animation type to {@link PipAnimationController#ANIM_TYPE_ALPHA}. + * <p> + * For example, gesture navigation would first fade out the PiP activity, and the transition + * should be responsible to animate in (such as fade in) the PiP. + */ + public void setOneShotEnterAnimationType(@AnimationType int animationType) { + mOneShotAnimationType = animationType; + if (animationType == ANIM_TYPE_ALPHA) { + mLastOneShotAlphaAnimationTime = SystemClock.uptimeMillis(); + } + } + + /** Returns the preferred animation type and consumes the one-shot type if needed. */ + @AnimationType + public int takeOneShotEnterAnimationType() { + final int type = mOneShotAnimationType; + if (type == ANIM_TYPE_ALPHA) { + // Restore to default type. + mOneShotAnimationType = ANIM_TYPE_BOUNDS; + if (SystemClock.uptimeMillis() - mLastOneShotAlphaAnimationTime + > ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "Alpha animation is expired. Use bounds animation."); + return ANIM_TYPE_BOUNDS; + } + } + return type; + } + + /** * Additional callback interface for PiP animation */ public static class PipAnimationCallback { @@ -255,7 +300,7 @@ public class PipAnimationController { * @return true if handled by the handler, false otherwise. */ public boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, - Rect destinationBounds) { + Rect destinationBounds, float alpha) { return false; } } @@ -356,9 +401,10 @@ public class PipAnimationController { } boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, - Rect destinationBounds) { + Rect destinationBounds, float alpha) { if (mPipTransactionHandler != null) { - return mPipTransactionHandler.handlePipTransaction(leash, tx, destinationBounds); + return mPipTransactionHandler.handlePipTransaction( + leash, tx, destinationBounds, alpha); } return false; } @@ -503,7 +549,9 @@ public class PipAnimationController { getSurfaceTransactionHelper().alpha(tx, leash, alpha) .round(tx, leash, shouldApplyCornerRadius()) .shadow(tx, leash, shouldApplyShadowRadius()); - tx.apply(); + if (!handlePipTransaction(leash, tx, destinationBounds, alpha)) { + tx.apply(); + } } @Override @@ -618,7 +666,7 @@ public class PipAnimationController { .shadow(tx, leash, shouldApplyShadowRadius()); } } - if (!handlePipTransaction(leash, tx, bounds)) { + if (!handlePipTransaction(leash, tx, bounds, /* alpha= */ 1f)) { tx.apply(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java index 000624499f79..0775f5279e31 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java @@ -45,6 +45,13 @@ public interface PipMenuController { String MENU_WINDOW_TITLE = "PipMenuView"; /** + * Used with + * {@link PipMenuController#movePipMenu(SurfaceControl, SurfaceControl.Transaction, Rect, + * float)} to indicate that we don't want to affect the alpha value of the menu surfaces. + */ + float ALPHA_NO_CHANGE = -1f; + + /** * Called when * {@link PipTaskOrganizer#onTaskAppeared(RunningTaskInfo, SurfaceControl)} * is called. @@ -85,8 +92,8 @@ public interface PipMenuController { * need to synchronize the movements on the same frame as PiP. */ default void movePipMenu(@Nullable SurfaceControl pipLeash, - @Nullable SurfaceControl.Transaction t, - Rect destinationBounds) {} + @Nullable SurfaceControl.Transaction t, Rect destinationBounds, float alpha) { + } /** * Update the PiP menu with the given bounds for re-layout purposes. 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 a0bd064149d2..d04ce1540980 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 @@ -62,7 +62,6 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.os.RemoteException; -import android.os.SystemClock; import android.os.SystemProperties; import android.util.Log; import android.view.Choreographer; @@ -111,12 +110,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, DisplayController.OnDisplaysChangedListener, ShellTaskOrganizer.FocusListener { private static final String TAG = PipTaskOrganizer.class.getSimpleName(); private static final boolean DEBUG = false; - /** - * The alpha type is set for swiping to home. But the swiped task may not enter PiP. And if - * another task enters PiP by non-swipe ways, e.g. call API in foreground or switch to 3-button - * navigation, then the alpha type is unexpected. - */ - private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000; /** * The fixed start delay in ms when fading out the content overlay from bounds animation. @@ -256,7 +249,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, }, null); } - private boolean shouldSyncPipTransactionWithMenu() { + protected boolean shouldSyncPipTransactionWithMenu() { return mPipMenuController.isMenuVisible(); } @@ -284,9 +277,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, new PipAnimationController.PipTransactionHandler() { @Override public boolean handlePipTransaction(SurfaceControl leash, - SurfaceControl.Transaction tx, Rect destinationBounds) { + SurfaceControl.Transaction tx, Rect destinationBounds, float alpha) { if (shouldSyncPipTransactionWithMenu()) { - mPipMenuController.movePipMenu(leash, tx, destinationBounds); + mPipMenuController.movePipMenu(leash, tx, destinationBounds, alpha); return true; } return false; @@ -301,8 +294,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private WindowContainerToken mToken; private SurfaceControl mLeash; protected PipTransitionState mPipTransitionState; - private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; - private long mLastOneShotAlphaAnimationTime; private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; protected PictureInPictureParams mPictureInPictureParams; @@ -390,6 +381,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return mPipTransitionController; } + PipAnimationController.PipTransactionHandler getPipTransactionHandler() { + return mPipTransactionHandler; + } + public Rect getCurrentOrAnimatingBounds() { PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getCurrentAnimator(); @@ -422,18 +417,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } /** - * Sets the preferred animation type for one time. - * This is typically used to set the animation type to - * {@link PipAnimationController#ANIM_TYPE_ALPHA}. - */ - public void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) { - mOneShotAnimationType = animationType; - if (animationType == ANIM_TYPE_ALPHA) { - mLastOneShotAlphaAnimationTime = SystemClock.uptimeMillis(); - } - } - - /** * Override if the PiP should always use a fade-in animation during PiP entry. * * @return true if the mOneShotAnimationType should always be @@ -733,26 +716,18 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return; } - if (mOneShotAnimationType == ANIM_TYPE_ALPHA - && SystemClock.uptimeMillis() - mLastOneShotAlphaAnimationTime - > ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: Alpha animation is expired. Use bounds animation.", TAG); - mOneShotAnimationType = ANIM_TYPE_BOUNDS; - } - + final int animationType = shouldAlwaysFadeIn() + ? ANIM_TYPE_ALPHA + : mPipAnimationController.takeOneShotEnterAnimationType(); if (Transitions.ENABLE_SHELL_TRANSITIONS) { + mPipTransitionController.setEnterAnimationType(animationType); // For Shell transition, we will animate the window in PipTransition#startAnimation // instead of #onTaskAppeared. return; } - if (shouldAlwaysFadeIn()) { - mOneShotAnimationType = ANIM_TYPE_ALPHA; - } - if (mWaitForFixedRotation) { - onTaskAppearedWithFixedRotation(); + onTaskAppearedWithFixedRotation(animationType); return; } @@ -763,7 +738,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, Objects.requireNonNull(destinationBounds, "Missing destination bounds"); final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); - if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { + if (animationType == ANIM_TYPE_BOUNDS) { if (!shouldAttachMenuEarly()) { mPipMenuController.attach(mLeash); } @@ -773,16 +748,15 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, mEnterAnimationDuration, null /* updateBoundsCallback */); mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP); - } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { + } else if (animationType == ANIM_TYPE_ALPHA) { enterPipWithAlphaAnimation(destinationBounds, mEnterAnimationDuration); - mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { - throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); + throw new RuntimeException("Unrecognized animation type: " + animationType); } } - private void onTaskAppearedWithFixedRotation() { - if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { + private void onTaskAppearedWithFixedRotation(int animationType) { + if (animationType == ANIM_TYPE_ALPHA) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Defer entering PiP alpha animation, fixed rotation is ongoing", TAG); // If deferred, hside the surface till fixed rotation is completed. @@ -791,7 +765,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, tx.setAlpha(mLeash, 0f); tx.show(mLeash); tx.apply(); - mOneShotAnimationType = ANIM_TYPE_BOUNDS; return; } final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); @@ -1417,7 +1390,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, .scale(tx, mLeash, startBounds, toBounds, degrees) .round(tx, mLeash, startBounds, toBounds); if (shouldSyncPipTransactionWithMenu()) { - mPipMenuController.movePipMenu(mLeash, tx, toBounds); + mPipMenuController.movePipMenu(mLeash, tx, toBounds, PipMenuController.ALPHA_NO_CHANGE); } else { tx.apply(); } @@ -1583,7 +1556,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, if (!isInPip()) { return; } - mPipMenuController.movePipMenu(null, null, destinationBounds); + mPipMenuController.movePipMenu(null, null, destinationBounds, + PipMenuController.ALPHA_NO_CHANGE); mPipMenuController.updateMenuBounds(destinationBounds); } @@ -1895,7 +1869,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, + " binder=" + (mToken != null ? mToken.asBinder() : null)); pw.println(innerPrefix + "mLeash=" + mLeash); pw.println(innerPrefix + "mState=" + mPipTransitionState.getTransitionState()); - pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType); pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 4a76a502462c..5755a10897af 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -87,7 +87,7 @@ public class PipTransition extends PipTransitionController { private final int mEnterExitAnimationDuration; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final Optional<SplitScreenController> mSplitScreenOptional; - private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; + private @PipAnimationController.AnimationType int mEnterAnimationType = ANIM_TYPE_BOUNDS; private Transitions.TransitionFinishCallback mFinishCallback; private SurfaceControl.Transaction mFinishTransaction; private final Rect mExitDestinationBounds = new Rect(); @@ -133,20 +133,6 @@ public class PipTransition extends PipTransitionController { } @Override - public void setIsFullAnimation(boolean isFullAnimation) { - setOneShotAnimationType(isFullAnimation ? ANIM_TYPE_BOUNDS : ANIM_TYPE_ALPHA); - } - - /** - * Sets the preferred animation type for one time. - * This is typically used to set the animation type to - * {@link PipAnimationController#ANIM_TYPE_ALPHA}. - */ - private void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) { - mOneShotAnimationType = animationType; - } - - @Override public void startExitTransition(int type, WindowContainerTransaction out, @Nullable Rect destinationBounds) { if (destinationBounds != null) { @@ -288,7 +274,7 @@ public class PipTransition extends PipTransitionController { if (!requestHasPipEnter(request)) { throw new IllegalStateException("Called PiP augmentRequest when request has no PiP"); } - if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { + if (mEnterAnimationType == ANIM_TYPE_ALPHA) { mRequestedEnterTransition = transition; mRequestedEnterTask = request.getTriggerTask().token; outWCT.setActivityWindowingMode(request.getTriggerTask().token, @@ -308,7 +294,7 @@ public class PipTransition extends PipTransitionController { @Override public boolean handleRotateDisplay(int startRotation, int endRotation, WindowContainerTransaction wct) { - if (mRequestedEnterTransition != null && mOneShotAnimationType == ANIM_TYPE_ALPHA) { + if (mRequestedEnterTransition != null && mEnterAnimationType == ANIM_TYPE_ALPHA) { // A fade-in was requested but not-yet started. In this case, just recalculate the // initial state under the new rotation. int rotationDelta = deltaRotation(startRotation, endRotation); @@ -625,6 +611,7 @@ public class PipTransition extends PipTransitionController { 0 /* startingAngle */, rotationDelta); animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP) .setPipAnimationCallback(mPipAnimationCallback) + .setPipTransactionHandler(mPipOrganizer.getPipTransactionHandler()) .setDuration(mEnterExitAnimationDuration) .start(); } @@ -676,6 +663,11 @@ public class PipTransition extends PipTransitionController { return false; } + @Override + public void setEnterAnimationType(@PipAnimationController.AnimationType int type) { + mEnterAnimationType = type; + } + private void startEnterAnimation(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @@ -760,7 +752,6 @@ public class PipTransition extends PipTransitionController { if (taskInfo.pictureInPictureParams != null && taskInfo.pictureInPictureParams.isAutoEnterEnabled() && mPipTransitionState.getInSwipePipToHomeTransition()) { - mOneShotAnimationType = ANIM_TYPE_BOUNDS; final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay; startTransaction.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9]) .setPosition(leash, destinationBounds.left, destinationBounds.top) @@ -796,17 +787,14 @@ public class PipTransition extends PipTransitionController { startTransaction.setMatrix(leash, tmpTransform, new float[9]); } - if (mPipOrganizer.shouldAlwaysFadeIn()) { - mOneShotAnimationType = ANIM_TYPE_ALPHA; - } - - if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { + final int enterAnimationType = mEnterAnimationType; + if (enterAnimationType == ANIM_TYPE_ALPHA) { startTransaction.setAlpha(leash, 0f); } startTransaction.apply(); PipAnimationController.PipTransitionAnimator animator; - if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { + if (enterAnimationType == ANIM_TYPE_BOUNDS) { animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds, currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, 0 /* startingAngle */, rotationDelta); @@ -829,15 +817,14 @@ public class PipTransition extends PipTransitionController { animator.setColorContentOverlay(mContext); } } - } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { + } else if (enterAnimationType == ANIM_TYPE_ALPHA) { animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds, 0f, 1f); - mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { - throw new RuntimeException("Unrecognized animation type: " - + mOneShotAnimationType); + throw new RuntimeException("Unrecognized animation type: " + enterAnimationType); } animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) + .setPipTransactionHandler(mPipOrganizer.getPipTransactionHandler()) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration); if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) { @@ -897,7 +884,7 @@ public class PipTransition extends PipTransitionController { .setWindowCrop(leash, endBounds.width(), endBounds.height()); } } - mSplitScreenOptional.get().finishEnterSplitScreen(startTransaction); + mSplitScreenOptional.get().finishEnterSplitScreen(finishTransaction); startTransaction.apply(); mPipOrganizer.onExitPipFinished(taskInfo); @@ -964,7 +951,8 @@ public class PipTransition extends PipTransitionController { } private void finishResizeForMenu(Rect destinationBounds) { - mPipMenuController.movePipMenu(null, null, destinationBounds); + mPipMenuController.movePipMenu(null, null, destinationBounds, + PipMenuController.ALPHA_NO_CHANGE); mPipMenuController.updateMenuBounds(destinationBounds); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java index f51e247fe112..ff7ab8ba1d97 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java @@ -105,15 +105,6 @@ public abstract class PipTransitionController implements Transitions.TransitionH } /** - * Called to inform the transition that the animation should start with the assumption that - * PiP is not animating from its original bounds, but rather a continuation of another - * animation. For example, gesture navigation would first fade out the PiP activity, and the - * transition should be responsible to animate in (such as fade in) the PiP. - */ - public void setIsFullAnimation(boolean isFullAnimation) { - } - - /** * Called when the Shell wants to start an exit Pip transition/animation. */ public void startExitTransition(int type, WindowContainerTransaction out, @@ -234,6 +225,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH throw new IllegalStateException("Request isn't entering PiP"); } + /** Sets the type of animation when a PiP task appears. */ + public void setEnterAnimationType(@PipAnimationController.AnimationType int type) { + } + /** Play a transition animation for entering PiP on a specific PiP change. */ public void startEnterAnimation(@NonNull final TransitionInfo.Change pipChange, @NonNull final SurfaceControl.Transaction startTransaction, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java index 94e593b106a5..e7a1395f541c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java @@ -298,7 +298,8 @@ public class PhonePipMenuController implements PipMenuController { } // Sync the menu bounds before showing it in case it is out of sync. - movePipMenu(null /* pipLeash */, null /* transaction */, stackBounds); + movePipMenu(null /* pipLeash */, null /* transaction */, stackBounds, + PipMenuController.ALPHA_NO_CHANGE); updateMenuBounds(stackBounds); mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay, @@ -311,7 +312,7 @@ public class PhonePipMenuController implements PipMenuController { @Override public void movePipMenu(@Nullable SurfaceControl pipLeash, @Nullable SurfaceControl.Transaction t, - Rect destinationBounds) { + Rect destinationBounds, float alpha) { if (destinationBounds.isEmpty()) { return; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 463ad77d828f..b0bb14b49db6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -968,12 +968,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsState.setShelfVisibility(visible, shelfHeight); } - private void setPinnedStackAnimationType(int animationType) { - mPipTaskOrganizer.setOneShotAnimationType(animationType); - mPipTransitionController.setIsFullAnimation( - animationType == PipAnimationController.ANIM_TYPE_BOUNDS); - } - @VisibleForTesting void setPinnedStackAnimationListener(PipAnimationListener callback) { mPinnedStackAnimationRecentsCallback = callback; @@ -1337,7 +1331,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb @Override public void setPipAnimationTypeToAlpha() { executeRemoteCallWithTaskPermission(mController, "setPipAnimationTypeToAlpha", - (controller) -> controller.setPinnedStackAnimationType(ANIM_TYPE_ALPHA)); + (controller) -> controller.mPipAnimationController.setOneShotEnterAnimationType( + ANIM_TYPE_ALPHA)); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java index a7171fd5b220..82fe38ccc7b3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java @@ -21,6 +21,7 @@ import static com.android.wm.shell.pip.PipUtils.dpToPx; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; @@ -366,11 +367,8 @@ public class PipSizeSpecHandler { mContext = context; mPipDisplayLayoutState = pipDisplayLayoutState; - boolean enablePipSizeLargeScreen = SystemProperties - .getBoolean("persist.wm.debug.enable_pip_size_large_screen", true); - // choose between two implementations of size spec logic - if (enablePipSizeLargeScreen) { + if (supportsPipSizeLargeScreen()) { mSizeSpecSourceImpl = new SizeSpecLargeScreenOptimizedImpl(); } else { mSizeSpecSourceImpl = new SizeSpecDefaultImpl(); @@ -515,6 +513,18 @@ public class PipSizeSpecHandler { } } + @VisibleForTesting + boolean supportsPipSizeLargeScreen() { + // TODO(b/271468706): switch Tv to having a dedicated SizeSpecSource once the SizeSpecSource + // can be injected + return SystemProperties + .getBoolean("persist.wm.debug.enable_pip_size_large_screen", true) && !isTv(); + } + + private boolean isTv() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); + } + /** Dumps internal state. */ public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java index fa62a73ca9b4..3b44f10ebe62 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java @@ -186,16 +186,17 @@ public class TvPipActionsProvider implements TvPipAction.SystemActionsHandler { } @VisibleForTesting(visibility = PACKAGE) - public void onPipExpansionToggled(boolean expanded) { + public void updatePipExpansionState(boolean expanded) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: onPipExpansionToggled, expanded: %b", TAG, expanded); - mExpandCollapseAction.update( + boolean changed = mExpandCollapseAction.update( expanded ? R.string.pip_collapse : R.string.pip_expand, expanded ? R.drawable.pip_ic_collapse : R.drawable.pip_ic_expand); - - notifyActionsChanged(/* added= */ 0, /* updated= */ 1, - mActionsList.indexOf(mExpandCollapseAction)); + if (changed) { + notifyActionsChanged(/* added= */ 0, /* updated= */ 1, + mActionsList.indexOf(mExpandCollapseAction)); + } } List<TvPipAction> getActionsList() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java index 2f74fb636bc9..02eeb2ac4fd5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java @@ -502,7 +502,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal "%s: onPipTransition_Canceled(), state=%s", TAG, stateToName(mState)); mTvPipMenuController.onPipTransitionFinished( PipAnimationController.isInPipDirection(direction)); - mTvPipActionsProvider.onPipExpansionToggled(mTvPipBoundsState.isTvPipExpanded()); + mTvPipActionsProvider.updatePipExpansionState(mTvPipBoundsState.isTvPipExpanded()); } @Override @@ -515,7 +515,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal "%s: onPipTransition_Finished(), state=%s, direction=%d", TAG, stateToName(mState), direction); mTvPipMenuController.onPipTransitionFinished(enterPipTransition); - mTvPipActionsProvider.onPipExpansionToggled(mTvPipBoundsState.isTvPipExpanded()); + mTvPipActionsProvider.updatePipExpansionState(mTvPipBoundsState.isTvPipExpanded()); } private void updateExpansionState() { 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 b18e21c03c63..b2a189b45d6c 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 @@ -30,6 +30,7 @@ import android.os.Handler; import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; +import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.window.SurfaceSyncGroup; @@ -202,8 +203,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } private void addPipMenuViewToSystemWindows(View v, String title) { - mSystemWindows.addView(v, getPipMenuLayoutParams(mContext, title, 0 /* width */, - 0 /* height */), 0 /* displayId */, SHELL_ROOT_LAYER_PIP); + final WindowManager.LayoutParams layoutParams = + getPipMenuLayoutParams(mContext, title, 0 /* width */, 0 /* height */); + layoutParams.alpha = 0f; + mSystemWindows.addView(v, layoutParams, 0 /* displayId */, SHELL_ROOT_LAYER_PIP); } void onPipTransitionFinished(boolean enterTransition) { @@ -309,9 +312,9 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis @Override public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction pipTx, - Rect pipBounds) { + Rect pipBounds, float alpha) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: movePipMenu: %s", TAG, pipBounds.toShortString()); + "%s: movePipMenu: %s, alpha %s", TAG, pipBounds.toShortString(), alpha); if (pipBounds.isEmpty()) { if (pipTx == null) { @@ -333,6 +336,11 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis pipTx.setPosition(frontSurface, menuDestBounds.left, menuDestBounds.top); pipTx.setPosition(backSurface, menuDestBounds.left, menuDestBounds.top); + if (alpha != ALPHA_NO_CHANGE) { + pipTx.setAlpha(frontSurface, alpha); + pipTx.setAlpha(backSurface, alpha); + } + // Synchronize drawing the content in the front and back surfaces together with the pip // transaction and the position change for the front and back surfaces final SurfaceSyncGroup syncGroup = new SurfaceSyncGroup("TvPip"); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipSystemAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipSystemAction.java index 4b82e4bdb64a..f6dabb762c54 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipSystemAction.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipSystemAction.java @@ -52,9 +52,14 @@ public class TvPipSystemAction extends TvPipAction { broadcastAction); } - void update(@StringRes int title, @DrawableRes int icon) { + /** + * @return true if the title and/or icon were changed. + */ + boolean update(@StringRes int title, @DrawableRes int icon) { + boolean changed = title != mTitleResource || icon != mIconResource; mTitleResource = title; mIconResource = icon; + return changed; } void populateButton(@NonNull TvWindowMenuActionButton button, Handler mainHandler) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java index 0940490e9944..4819f665d6d3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java @@ -98,4 +98,11 @@ public class TvPipTaskOrganizer extends PipTaskOrganizer { protected boolean shouldAlwaysFadeIn() { return true; } + + @Override + protected boolean shouldSyncPipTransactionWithMenu() { + // We always have a menu visible and want to sync the pip transaction with the menu, even + // when the menu alpha is 0 (e.g. when a fade-in animation starts). + return true; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl index 81e118a31b73..f819bee2d5e0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl @@ -129,9 +129,10 @@ interface ISplitScreen { /** * Start a pair of intents in one transition. */ - oneway void startIntents(in PendingIntent pendingIntent1, in Bundle options1, - in PendingIntent pendingIntent2, in Bundle options2, int splitPosition, - float splitRatio, in RemoteTransition remoteTransition, in InstanceId instanceId) = 19; + oneway void startIntents(in PendingIntent pendingIntent1, in ShortcutInfo shortcutInfo1, + in Bundle options1, in PendingIntent pendingIntent2, in ShortcutInfo shortcutInfo2, + in Bundle options2, int splitPosition, float splitRatio, + in RemoteTransition remoteTransition, in InstanceId instanceId) = 19; /** * Blocking call that notifies and gets additional split-screen targets when entering diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 7d5ab8428a3e..498f95c8595e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -541,6 +541,34 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, instanceId); } + void startShortcutAndTask(ShortcutInfo shortcutInfo, @Nullable Bundle options1, + int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition, + float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { + if (options1 == null) options1 = new Bundle(); + final ActivityOptions activityOptions = ActivityOptions.fromBundle(options1); + final String packageName1 = shortcutInfo.getPackage(); + // NOTE: This doesn't correctly pull out packageName2 if taskId is referring to a task in + // recents that hasn't launched and is not being organized + final String packageName2 = SplitScreenUtils.getPackageName(taskId, mTaskOrganizer); + if (samePackage(packageName1, packageName2)) { + if (supportMultiInstancesSplit(packageName1)) { + activityOptions.setApplyMultipleTaskFlagForShortcut(true); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); + } else { + if (mRecentTasksOptional.isPresent()) { + mRecentTasksOptional.get().removeSplitPair(taskId); + } + taskId = INVALID_TASK_ID; + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, + "Cancel entering split as not supporting multi-instances"); + Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text, + Toast.LENGTH_SHORT).show(); + } + } + mStageCoordinator.startShortcutAndTask(shortcutInfo, options1, taskId, options2, + splitPosition, splitRatio, remoteTransition, instanceId); + } + /** * See {@link #startIntent(PendingIntent, Intent, int, Bundle)} * @param instanceId to be used by {@link SplitscreenEventLogger} @@ -580,6 +608,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { Intent fillInIntent = null; final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent); + // NOTE: This doesn't correctly pull out packageName2 if taskId is referring to a task in + // recents that hasn't launched and is not being organized final String packageName2 = SplitScreenUtils.getPackageName(taskId, mTaskOrganizer); if (samePackage(packageName1, packageName2)) { if (supportMultiInstancesSplit(packageName1)) { @@ -587,6 +617,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); } else { + if (mRecentTasksOptional.isPresent()) { + mRecentTasksOptional.get().removeSplitPair(taskId); + } + taskId = INVALID_TASK_ID; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Cancel entering split as not supporting multi-instances"); Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text, @@ -626,6 +660,35 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, splitPosition, splitRatio, adapter, instanceId); } + private void startIntents(PendingIntent pendingIntent1, + @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, + PendingIntent pendingIntent2, @Nullable ShortcutInfo shortcutInfo2, + @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio, + @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { + Intent fillInIntent1 = null; + Intent fillInIntent2 = null; + final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent1); + final String packageName2 = SplitScreenUtils.getPackageName(pendingIntent2); + if (samePackage(packageName1, packageName2)) { + if (supportMultiInstancesSplit(packageName1)) { + fillInIntent1 = new Intent(); + fillInIntent1.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + fillInIntent2 = new Intent(); + fillInIntent2.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK"); + } else { + pendingIntent2 = null; + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, + "Cancel entering split as not supporting multi-instances"); + Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text, + Toast.LENGTH_SHORT).show(); + } + } + mStageCoordinator.startIntents(pendingIntent1, fillInIntent1, shortcutInfo1, options1, + pendingIntent2, fillInIntent2, shortcutInfo2, options2, splitPosition, splitRatio, + remoteTransition, instanceId); + } + @Override public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent, @SplitPosition int position, @Nullable Bundle options) { @@ -1046,9 +1109,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startShortcutAndTask", - (controller) -> controller.mStageCoordinator.startShortcutAndTask(shortcutInfo, - options1, taskId, options2, splitPosition, splitRatio, remoteTransition, - instanceId)); + (controller) -> controller.startShortcutAndTask(shortcutInfo, options1, taskId, + options2, splitPosition, splitRatio, remoteTransition, instanceId)); } @Override @@ -1066,11 +1128,17 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, } @Override - public void startIntents(PendingIntent pendingIntent1, @Nullable Bundle options1, - PendingIntent pendingIntent2, @Nullable Bundle options2, + public void startIntents(PendingIntent pendingIntent1, @Nullable ShortcutInfo shortcutInfo1, + @Nullable Bundle options1, PendingIntent pendingIntent2, + @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { - // TODO(b/259368992): To be implemented. + executeRemoteCallWithTaskPermission(mController, "startIntents", + (controller) -> + controller.startIntents(pendingIntent1, shortcutInfo1, + options1, pendingIntent2, shortcutInfo2, options2, + splitPosition, splitRatio, remoteTransition, instanceId) + ); } @Override 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 22800ad8e8a8..51b8000f14bb 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 @@ -22,6 +22,7 @@ import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString; @@ -37,7 +38,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; -import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.view.SurfaceControl; @@ -138,25 +138,20 @@ class SplitScreenTransitions { t.setAlpha(parentChange.getLeash(), 1.f); // and then animate this layer outside the parent (since, for example, this is // the home task animating from fullscreen to part-screen). - t.reparent(leash, info.getRoot(rootIdx).getLeash()); - t.setLayer(leash, info.getChanges().size() - i); + t.reparent(parentChange.getLeash(), info.getRoot(rootIdx).getLeash()); + t.setLayer(parentChange.getLeash(), info.getChanges().size() - i); // build the finish reparent/reposition mFinishTransaction.reparent(leash, parentChange.getLeash()); mFinishTransaction.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y); } - // TODO(shell-transitions): screenshot here - final Rect startBounds = new Rect(change.getStartAbsBounds()); - final Rect endBounds = new Rect(change.getEndAbsBounds()); - final Point rootOffset = info.getRoot(rootIdx).getOffset(); - startBounds.offset(-rootOffset.x, -rootOffset.y); - endBounds.offset(-rootOffset.x, -rootOffset.y); - startExampleResizeAnimation(leash, startBounds, endBounds); } boolean isRootOrSplitSideRoot = change.getParent() == null || topRoot.equals(change.getParent()); - // For enter or exit, we only want to animate the side roots but not the top-root. - if (!isRootOrSplitSideRoot || topRoot.equals(change.getContainer())) { + boolean isDivider = change.getFlags() == FLAG_IS_DIVIDER_BAR; + // For enter or exit, we only want to animate side roots and the divider but not the + // top-root. + if (!isRootOrSplitSideRoot || topRoot.equals(change.getContainer()) || isDivider) { continue; } @@ -165,6 +160,10 @@ class SplitScreenTransitions { t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top); t.setWindowCrop(leash, change.getEndAbsBounds().width(), change.getEndAbsBounds().height()); + } else if (isDivider) { + t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top); + t.setLayer(leash, Integer.MAX_VALUE); + t.show(leash); } boolean isOpening = isOpeningTransition(info); if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { @@ -282,6 +281,12 @@ class SplitScreenTransitions { return null; } + void startFullscreenTransition(WindowContainerTransaction wct, + @Nullable RemoteTransition handler) { + mTransitions.startTransition(TRANSIT_OPEN, wct, + new OneShotRemoteHandler(mTransitions.getMainExecutor(), handler)); + } + /** Starts a transition to enter split with a remote transition animator. */ IBinder startEnterTransition( 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 dd91a37039e4..e4f27240b2cb 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 @@ -612,6 +612,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); + if (taskId2 == INVALID_TASK_ID) { + if (mMainStage.containsTask(taskId1) || mSideStage.containsTask(taskId1)) { + prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct); + } + if (mRecentTasks.isPresent()) { + mRecentTasks.get().removeSplitPair(taskId1); + } + options1 = options1 != null ? options1 : new Bundle(); + wct.startTask(taskId1, options1); + mSplitTransitions.startFullscreenTransition(wct, remoteTransition); + return; + } + prepareEvictChildTasksIfSplitActive(wct); setSideStagePosition(splitPosition, wct); options1 = options1 != null ? options1 : new Bundle(); @@ -627,6 +640,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @SplitPosition int splitPosition, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); + if (taskId == INVALID_TASK_ID) { + options1 = options1 != null ? options1 : new Bundle(); + wct.sendPendingIntent(pendingIntent, fillInIntent, options1); + mSplitTransitions.startFullscreenTransition(wct, remoteTransition); + return; + } + prepareEvictChildTasksIfSplitActive(wct); setSideStagePosition(splitPosition, wct); options1 = options1 != null ? options1 : new Bundle(); @@ -641,6 +661,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); + if (taskId == INVALID_TASK_ID) { + options1 = options1 != null ? options1 : new Bundle(); + wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1); + mSplitTransitions.startFullscreenTransition(wct, remoteTransition); + return; + } + prepareEvictChildTasksIfSplitActive(wct); setSideStagePosition(splitPosition, wct); options1 = options1 != null ? options1 : new Bundle(); @@ -682,6 +709,57 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, setEnterInstanceId(instanceId); } + void startIntents(PendingIntent pendingIntent1, Intent fillInIntent1, + @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, + PendingIntent pendingIntent2, Intent fillInIntent2, + @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, + @SplitPosition int splitPosition, float splitRatio, + @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + if (pendingIntent2 == null) { + options1 = options1 != null ? options1 : new Bundle(); + if (shortcutInfo1 != null) { + wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1); + } else { + wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1); + } + mSplitTransitions.startFullscreenTransition(wct, remoteTransition); + return; + } + + if (!mMainStage.isActive()) { + // Build a request WCT that will launch both apps such that task 0 is on the main stage + // while task 1 is on the side stage. + mMainStage.activate(wct, false /* reparent */); + } + + prepareEvictChildTasksIfSplitActive(wct); + mSplitLayout.setDivideRatio(splitRatio); + updateWindowBounds(mSplitLayout, wct); + wct.reorder(mRootTaskInfo.token, true); + setRootForceTranslucent(false, wct); + + setSideStagePosition(splitPosition, wct); + options1 = options1 != null ? options1 : new Bundle(); + addActivityOptions(options1, mSideStage); + if (shortcutInfo1 != null) { + wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1); + } else { + wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1); + } + options2 = options2 != null ? options2 : new Bundle(); + addActivityOptions(options2, mMainStage); + if (shortcutInfo2 != null) { + wct.startShortcut(mContext.getPackageName(), shortcutInfo2, options2); + } else { + wct.sendPendingIntent(pendingIntent2, fillInIntent2, options2); + } + + mSplitTransitions.startEnterTransition( + TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null, null); + setEnterInstanceId(instanceId); + } + /** Starts a pair of tasks using legacy transition. */ void startTasksWithLegacyTransition(int taskId1, @Nullable Bundle options1, int taskId2, @Nullable Bundle options2, @SplitPosition int splitPosition, @@ -690,6 +768,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (options1 == null) options1 = new Bundle(); if (taskId2 == INVALID_TASK_ID) { // Launching a solo task. + // Exit split first if this task under split roots. + if (mMainStage.containsTask(taskId1) || mSideStage.containsTask(taskId1)) { + exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT); + } ActivityOptions activityOptions = ActivityOptions.fromBundle(options1); activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter)); options1 = activityOptions.toBundle(); @@ -891,10 +973,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSyncQueue.queue(wrapAsSplitRemoteAnimation(adapter), WindowManager.TRANSIT_OPEN, wct); } - mSyncQueue.runInSync(t -> { - setDividerVisibility(true, t); - }); - setEnterInstanceId(instanceId); } @@ -933,6 +1011,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onAnimationCancelled(boolean isKeyguardOccluded) { onRemoteAnimationFinishedOrCancelled(evictWct); + setDividerVisibility(true, null); try { adapter.getRunner().onAnimationCancelled(isKeyguardOccluded); } catch (RemoteException e) { @@ -973,6 +1052,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, t.setPosition(apps[i].leash, 0, 0); } } + setDividerVisibility(true, t); t.apply(); IRemoteAnimationFinishedCallback wrapCallback = @@ -1463,6 +1543,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, void finishEnterSplitScreen(SurfaceControl.Transaction t) { mSplitLayout.init(); setDividerVisibility(true, t); + // Ensure divider surface are re-parented back into the hierarchy at the end of the + // transition. See Transition#buildFinishTransaction for more detail. + t.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash); + updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */); t.show(mRootTaskLeash); setSplitsVisible(true); @@ -1772,6 +1856,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, setDividerVisibility(mainStageVisible, null); } + // Set divider visibility flag and try to apply it, the param transaction is used to apply. + // See applyDividerVisibility for more detail. private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) { if (visible == mDividerVisible) { return; @@ -1798,14 +1884,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return; } - if (t != null) { - applyDividerVisibility(t); - } else { - mSyncQueue.runInSync(transaction -> applyDividerVisibility(transaction)); - } + applyDividerVisibility(t); } - private void applyDividerVisibility(SurfaceControl.Transaction t) { + // Apply divider visibility by current visibility flag. If param transaction is non-null, it + // will apply by that transaction, if it is null and visible, it will run a fade-in animation, + // otherwise hide immediately. + private void applyDividerVisibility(@Nullable SurfaceControl.Transaction t) { final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); if (dividerLeash == null) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, @@ -1822,7 +1907,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDividerFadeInAnimator.cancel(); } - if (mDividerVisible) { + mSplitLayout.getRefDividerBounds(mTempRect1); + if (t != null) { + t.setVisibility(dividerLeash, mDividerVisible); + t.setLayer(dividerLeash, Integer.MAX_VALUE); + t.setPosition(dividerLeash, mTempRect1.left, mTempRect1.top); + } else if (mDividerVisible) { final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); mDividerFadeInAnimator = ValueAnimator.ofFloat(0f, 1f); mDividerFadeInAnimator.addUpdateListener(animation -> { @@ -1862,7 +1952,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDividerFadeInAnimator.start(); } else { - t.hide(dividerLeash); + final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); + transaction.hide(dividerLeash); + transaction.apply(); + mTransactionPool.release(transaction); } } @@ -2321,9 +2414,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) { - // TODO(shell-transitions): Implement a fallback behavior for now. - throw new IllegalStateException("Somehow removed the last task in a stage" - + " outside of a proper transition"); + Log.e(TAG, "Somehow removed the last task in a stage outside of a proper " + + "transition."); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + final int dismissTop = mMainStage.getChildCount() == 0 + ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE; + prepareExitSplitScreen(dismissTop, wct); + mSplitTransitions.startDismissTransition(wct, this, dismissTop, + EXIT_REASON_UNKNOWN); // This can happen in some pathological cases. For example: // 1. main has 2 tasks [Task A (Single-task), Task B], side has one task [Task C] // 2. Task B closes itself and starts Task A in LAUNCH_ADJACENT at the same time @@ -2446,7 +2544,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } finishEnterSplitScreen(finishT); - addDividerBarToTransition(info, finishT, true /* show */); + addDividerBarToTransition(info, true /* show */); return true; } @@ -2589,7 +2687,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) { // TODO: Have a proper remote for this. Until then, though, reset state and use the // normal animation stuff (which falls back to the normal launcher remote). - t.hide(mSplitLayout.getDividerLeash()); + setDividerVisibility(false, t); mSplitLayout.release(t); mSplitTransitions.mPendingDismiss = null; return false; @@ -2607,7 +2705,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, }); } - addDividerBarToTransition(info, finishT, false /* show */); + addDividerBarToTransition(info, false /* show */); return true; } @@ -2648,11 +2746,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, logExit(EXIT_REASON_UNKNOWN); } - private void addDividerBarToTransition(@NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction finishT, boolean show) { + private void addDividerBarToTransition(@NonNull TransitionInfo info, boolean show) { final SurfaceControl leash = mSplitLayout.getDividerLeash(); final TransitionInfo.Change barChange = new TransitionInfo.Change(null /* token */, leash); mSplitLayout.getRefDividerBounds(mTempRect1); + barChange.setParent(mRootTaskInfo.token); barChange.setStartAbsBounds(mTempRect1); barChange.setEndAbsBounds(mTempRect1); barChange.setMode(show ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK); @@ -2660,15 +2758,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Technically this should be order-0, but this is running after layer assignment // and it's a special case, so just add to end. info.addChange(barChange); - - if (show) { - finishT.setLayer(leash, Integer.MAX_VALUE); - finishT.setPosition(leash, mTempRect1.left, mTempRect1.top); - finishT.show(leash); - // Ensure divider surface are re-parented back into the hierarchy at the end of the - // transition. See Transition#buildFinishTransaction for more detail. - finishT.reparent(leash, mRootTaskLeash); - } } RemoteAnimationTarget getDividerBarLegacyTarget() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 3dd10a098310..6e9ecdaf55e7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -327,6 +327,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { @ColorInt int backgroundColorForTransition = 0; final int wallpaperTransit = getWallpaperTransitType(info); + boolean isDisplayRotationAnimationStarted = false; for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.hasAllFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY @@ -350,6 +351,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) { startRotationAnimation(startTransaction, change, info, anim, animations, onAnimFinish); + isDisplayRotationAnimationStarted = true; continue; } } else { @@ -405,6 +407,14 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } } + // Hide the invisible surface directly without animating it if there is a display + // rotation animation playing. + if (isDisplayRotationAnimationStarted && TransitionUtil.isClosingType( + change.getMode())) { + startTransaction.hide(change.getLeash()); + continue; + } + // The back gesture has animated this change before transition happen, so here we don't // play the animation again. if (change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index fa4de16b37f1..bdb7d44bad32 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -143,6 +143,10 @@ public class Transitions implements RemoteCallable<Transitions> { /** Transition type to fullscreen from desktop mode. */ public static final int TRANSIT_EXIT_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 12; + /** Transition type to animate back to fullscreen when drag to freeform is cancelled. */ + public static final int TRANSIT_CANCEL_ENTERING_DESKTOP_MODE = + WindowManager.TRANSIT_FIRST_CUSTOM + 13; + private final WindowOrganizer mOrganizer; private final Context mContext; private final ShellExecutor mMainExecutor; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 060dc4e05b46..dfde7e6feff5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -110,19 +110,11 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final WindowContainerTransaction wct = new WindowContainerTransaction(); - final int outsetLeftId = R.dimen.freeform_resize_handle; - final int outsetTopId = R.dimen.freeform_resize_handle; - final int outsetRightId = R.dimen.freeform_resize_handle; - final int outsetBottomId = R.dimen.freeform_resize_handle; - mRelayoutParams.reset(); mRelayoutParams.mRunningTaskInfo = taskInfo; mRelayoutParams.mLayoutResId = R.layout.caption_window_decor; mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height; mRelayoutParams.mShadowRadiusId = shadowRadiusID; - if (isDragResizeable) { - mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId); - } relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo 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 f99821747fef..5226eeebcaa2 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 @@ -34,6 +34,7 @@ import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.content.Context; import android.content.res.Resources; +import android.graphics.Point; import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Handler; @@ -197,7 +198,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Override public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) { - if (mTransitionPausingRelayout.equals(merged)) { + if (merged.equals(mTransitionPausingRelayout)) { mTransitionPausingRelayout = playing; } } @@ -312,8 +313,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } else if (id == R.id.back_button) { mTaskOperations.injectBackKey(); } else if (id == R.id.caption_handle || id == R.id.open_menu_button) { - moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId)); - decoration.createHandleMenu(); + if (!decoration.isHandleMenuActive()) { + moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId)); + decoration.createHandleMenu(); + } else { + decoration.closeHandleMenu(); + } } else if (id == R.id.desktop_button) { mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true)); mDesktopTasksController.ifPresent(c -> c.moveToDesktop(mTaskId)); @@ -553,8 +558,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mDragToDesktopAnimationStarted = false; return; } else if (mDragToDesktopAnimationStarted) { - mDesktopTasksController.ifPresent(c -> - c.moveToFullscreen(relevantDecor.mTaskInfo)); + Point startPosition = new Point((int) ev.getX(), (int) ev.getY()); + mDesktopTasksController.ifPresent( + c -> c.cancelMoveToFreeform(relevantDecor.mTaskInfo, + startPosition)); mDragToDesktopAnimationStarted = false; return; } 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 efc90b5e63e1..67e99d73b811 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 @@ -42,6 +42,7 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import android.window.SurfaceSyncGroup; import android.window.WindowContainerTransaction; import com.android.launcher3.icons.IconProvider; @@ -208,11 +209,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final WindowContainerTransaction wct = new WindowContainerTransaction(); - final int outsetLeftId = R.dimen.freeform_resize_handle; - final int outsetTopId = R.dimen.freeform_resize_handle; - final int outsetRightId = R.dimen.freeform_resize_handle; - final int outsetBottomId = R.dimen.freeform_resize_handle; - final int windowDecorLayoutId = getDesktopModeWindowDecorLayoutId( taskInfo.getWindowingMode()); mRelayoutParams.reset(); @@ -220,9 +216,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mRelayoutParams.mLayoutResId = windowDecorLayoutId; mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height; mRelayoutParams.mShadowRadiusId = shadowRadiusID; - if (isDragResizeable) { - mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId); - } relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo @@ -319,51 +312,50 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin * Create and display handle menu window */ void createHandleMenu() { + final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG); final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); updateHandleMenuPillPositions(); - createAppInfoPill(t); + createAppInfoPill(t, ssg); // Only show windowing buttons in proto2. Proto1 uses a system-level mode only. final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled(); if (shouldShowWindowingPill) { - createWindowingPill(t); + createWindowingPill(t, ssg); } - createMoreActionsPill(t); + createMoreActionsPill(t, ssg); - mSyncQueue.runInSync(transaction -> { - transaction.merge(t); - t.close(); - }); + ssg.addTransaction(t); + ssg.markSyncReady(); setupHandleMenu(shouldShowWindowingPill); } - private void createAppInfoPill(SurfaceControl.Transaction t) { + private void createAppInfoPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { final int x = (int) mHandleMenuAppInfoPillPosition.x; final int y = (int) mHandleMenuAppInfoPillPosition.y; mHandleMenuAppInfoPill = addWindow( R.layout.desktop_mode_window_decor_handle_menu_app_info_pill, "Menu's app info pill", - t, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius); + t, ssg, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius); } - private void createWindowingPill(SurfaceControl.Transaction t) { + private void createWindowingPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { final int x = (int) mHandleMenuWindowingPillPosition.x; final int y = (int) mHandleMenuWindowingPillPosition.y; mHandleMenuWindowingPill = addWindow( R.layout.desktop_mode_window_decor_handle_menu_windowing_pill, "Menu's windowing pill", - t, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius); + t, ssg, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius); } - private void createMoreActionsPill(SurfaceControl.Transaction t) { + private void createMoreActionsPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { final int x = (int) mHandleMenuMoreActionsPillPosition.x; final int y = (int) mHandleMenuMoreActionsPillPosition.y; mHandleMenuMoreActionsPill = addWindow( R.layout.desktop_mode_window_decor_handle_menu_more_actions_pill, "Menu's more actions pill", - t, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius); + t, ssg, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius); } private void setupHandleMenu(boolean windowingPillShown) { @@ -424,13 +416,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_controls_window_decor) { // Align the handle menu to the left of the caption. - menuX = mRelayoutParams.mCaptionX - mResult.mDecorContainerOffsetX + mMarginMenuStart; - menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + mMarginMenuTop; + menuX = mRelayoutParams.mCaptionX + mMarginMenuStart; + menuY = mRelayoutParams.mCaptionY + mMarginMenuTop; } else { // Position the handle menu at the center of the caption. - menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (mMenuWidth / 2) - - mResult.mDecorContainerOffsetX; - menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + mMarginMenuStart; + menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (mMenuWidth / 2); + menuY = mRelayoutParams.mCaptionY + mMarginMenuStart; } // App Info pill setup. @@ -487,26 +478,30 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin if (mHandleMenuAppInfoPill.mWindowViewHost.getView().getWidth() == 0) return; PointF inputPoint = offsetCaptionLocation(ev); + + // If this is called before open_menu_button's onClick, we don't want to close + // the menu since it will just reopen in onClick. + final boolean pointInOpenMenuButton = pointInView( + mResult.mRootView.findViewById(R.id.open_menu_button), + inputPoint.x, + inputPoint.y); + final boolean pointInAppInfoPill = pointInView( mHandleMenuAppInfoPill.mWindowViewHost.getView(), - inputPoint.x - mHandleMenuAppInfoPillPosition.x - mResult.mDecorContainerOffsetX, - inputPoint.y - mHandleMenuAppInfoPillPosition.y - - mResult.mDecorContainerOffsetY); + inputPoint.x - mHandleMenuAppInfoPillPosition.x, + inputPoint.y - mHandleMenuAppInfoPillPosition.y); boolean pointInWindowingPill = false; if (mHandleMenuWindowingPill != null) { pointInWindowingPill = pointInView(mHandleMenuWindowingPill.mWindowViewHost.getView(), - inputPoint.x - mHandleMenuWindowingPillPosition.x - - mResult.mDecorContainerOffsetX, - inputPoint.y - mHandleMenuWindowingPillPosition.y - - mResult.mDecorContainerOffsetY); + inputPoint.x - mHandleMenuWindowingPillPosition.x, + inputPoint.y - mHandleMenuWindowingPillPosition.y); } final boolean pointInMoreActionsPill = pointInView( mHandleMenuMoreActionsPill.mWindowViewHost.getView(), - inputPoint.x - mHandleMenuMoreActionsPillPosition.x - - mResult.mDecorContainerOffsetX, - inputPoint.y - mHandleMenuMoreActionsPillPosition.y - - mResult.mDecorContainerOffsetY); - if (!pointInAppInfoPill && !pointInWindowingPill && !pointInMoreActionsPill) { + inputPoint.x - mHandleMenuMoreActionsPillPosition.x, + inputPoint.y - mHandleMenuMoreActionsPillPosition.y); + if (!pointInAppInfoPill && !pointInWindowingPill + && !pointInMoreActionsPill && !pointInOpenMenuButton) { closeHandleMenu(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index 8cb575cc96e3..d5437c72acac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -64,8 +64,8 @@ class DragResizeInputListener implements AutoCloseable { private final TaskResizeInputEventReceiver mInputEventReceiver; private final DragPositioningCallback mCallback; - private int mWidth; - private int mHeight; + private int mTaskWidth; + private int mTaskHeight; private int mResizeHandleThickness; private int mCornerSize; @@ -128,78 +128,84 @@ class DragResizeInputListener implements AutoCloseable { * This is also used to update the touch regions of this handler every event dispatched here is * a potential resize request. * - * @param width The width of the drag resize handler in pixels, including resize handle - * thickness. That is task width + 2 * resize handle thickness. - * @param height The height of the drag resize handler in pixels, including resize handle - * thickness. That is task height + 2 * resize handle thickness. + * @param taskWidth The width of the task. + * @param taskHeight The height of the task. * @param resizeHandleThickness The thickness of the resize handle in pixels. * @param cornerSize The size of the resize handle centered in each corner. * @param touchSlop The distance in pixels user has to drag with touch for it to register as * a resize action. */ - void setGeometry(int width, int height, int resizeHandleThickness, int cornerSize, + void setGeometry(int taskWidth, int taskHeight, int resizeHandleThickness, int cornerSize, int touchSlop) { - if (mWidth == width && mHeight == height + if (mTaskWidth == taskWidth && mTaskHeight == taskHeight && mResizeHandleThickness == resizeHandleThickness && mCornerSize == cornerSize) { return; } - mWidth = width; - mHeight = height; + mTaskWidth = taskWidth; + mTaskHeight = taskHeight; mResizeHandleThickness = resizeHandleThickness; mCornerSize = cornerSize; mDragDetector.setTouchSlop(touchSlop); Region touchRegion = new Region(); - final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness); + final Rect topInputBounds = new Rect( + -mResizeHandleThickness, + -mResizeHandleThickness, + mTaskWidth + mResizeHandleThickness, + 0); touchRegion.union(topInputBounds); - final Rect leftInputBounds = new Rect(0, mResizeHandleThickness, - mResizeHandleThickness, mHeight - mResizeHandleThickness); + final Rect leftInputBounds = new Rect( + -mResizeHandleThickness, + 0, + 0, + mTaskHeight); touchRegion.union(leftInputBounds); final Rect rightInputBounds = new Rect( - mWidth - mResizeHandleThickness, mResizeHandleThickness, - mWidth, mHeight - mResizeHandleThickness); + mTaskWidth, + 0, + mTaskWidth + mResizeHandleThickness, + mTaskHeight); touchRegion.union(rightInputBounds); - final Rect bottomInputBounds = new Rect(0, mHeight - mResizeHandleThickness, - mWidth, mHeight); + final Rect bottomInputBounds = new Rect( + -mResizeHandleThickness, + mTaskHeight, + mTaskWidth + mResizeHandleThickness, + mTaskHeight + mResizeHandleThickness); touchRegion.union(bottomInputBounds); // Set up touch areas in each corner. int cornerRadius = mCornerSize / 2; mLeftTopCornerBounds = new Rect( - mResizeHandleThickness - cornerRadius, - mResizeHandleThickness - cornerRadius, - mResizeHandleThickness + cornerRadius, - mResizeHandleThickness + cornerRadius - ); + -cornerRadius, + -cornerRadius, + cornerRadius, + cornerRadius); touchRegion.union(mLeftTopCornerBounds); mRightTopCornerBounds = new Rect( - mWidth - mResizeHandleThickness - cornerRadius, - mResizeHandleThickness - cornerRadius, - mWidth - mResizeHandleThickness + cornerRadius, - mResizeHandleThickness + cornerRadius - ); + mTaskWidth - cornerRadius, + -cornerRadius, + mTaskWidth + cornerRadius, + cornerRadius); touchRegion.union(mRightTopCornerBounds); mLeftBottomCornerBounds = new Rect( - mResizeHandleThickness - cornerRadius, - mHeight - mResizeHandleThickness - cornerRadius, - mResizeHandleThickness + cornerRadius, - mHeight - mResizeHandleThickness + cornerRadius - ); + -cornerRadius, + mTaskHeight - cornerRadius, + cornerRadius, + mTaskHeight + cornerRadius); touchRegion.union(mLeftBottomCornerBounds); mRightBottomCornerBounds = new Rect( - mWidth - mResizeHandleThickness - cornerRadius, - mHeight - mResizeHandleThickness - cornerRadius, - mWidth - mResizeHandleThickness + cornerRadius, - mHeight - mResizeHandleThickness + cornerRadius - ); + mTaskWidth - cornerRadius, + mTaskHeight - cornerRadius, + mTaskWidth + cornerRadius, + mTaskHeight + cornerRadius); touchRegion.union(mRightBottomCornerBounds); try { @@ -358,16 +364,16 @@ class DragResizeInputListener implements AutoCloseable { @TaskPositioner.CtrlType private int calculateResizeHandlesCtrlType(float x, float y) { int ctrlType = 0; - if (x < mResizeHandleThickness) { + if (x < 0) { ctrlType |= TaskPositioner.CTRL_TYPE_LEFT; } - if (x > mWidth - mResizeHandleThickness) { + if (x > mTaskWidth) { ctrlType |= TaskPositioner.CTRL_TYPE_RIGHT; } - if (y < mResizeHandleThickness) { + if (y < 0) { ctrlType |= TaskPositioner.CTRL_TYPE_TOP; } - if (y > mHeight - mResizeHandleThickness) { + if (y > mTaskHeight) { ctrlType |= TaskPositioner.CTRL_TYPE_BOTTOM; } return ctrlType; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 4ebd09fdecee..8b35694ff8fd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -34,6 +34,7 @@ import android.view.ViewRootImpl; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowlessWindowManager; +import android.window.SurfaceSyncGroup; import android.window.TaskConstants; import android.window.WindowContainerTransaction; @@ -90,7 +91,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> Display mDisplay; Context mDecorWindowContext; SurfaceControl mDecorationContainerSurface; - SurfaceControl mTaskBackgroundSurface; SurfaceControl mCaptionContainerSurface; private WindowlessWindowManager mCaptionWindowManager; @@ -98,7 +98,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> private final Binder mOwner = new Binder(); private final Rect mCaptionInsetsRect = new Rect(); - private final Rect mTaskSurfaceCrop = new Rect(); private final float[] mTmpColor = new float[3]; WindowDecoration( @@ -193,15 +192,20 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mDecorWindowContext = mContext.createConfigurationContext(taskConfig); if (params.mLayoutResId != 0) { outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext) - .inflate(params.mLayoutResId, null); + .inflate(params.mLayoutResId, null); } } if (outResult.mRootView == null) { outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext) - .inflate(params.mLayoutResId , null); + .inflate(params.mLayoutResId, null); } + final Resources resources = mDecorWindowContext.getResources(); + final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); + outResult.mWidth = taskBounds.width(); + outResult.mHeight = taskBounds.height(); + // DecorationContainerSurface if (mDecorationContainerSurface == null) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); @@ -216,46 +220,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> TaskConstants.TASK_CHILD_LAYER_WINDOW_DECORATIONS); } - final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); - final Resources resources = mDecorWindowContext.getResources(); - outResult.mDecorContainerOffsetX = -loadDimensionPixelSize(resources, params.mOutsetLeftId); - outResult.mDecorContainerOffsetY = -loadDimensionPixelSize(resources, params.mOutsetTopId); - outResult.mWidth = taskBounds.width() - + loadDimensionPixelSize(resources, params.mOutsetRightId) - - outResult.mDecorContainerOffsetX; - outResult.mHeight = taskBounds.height() - + loadDimensionPixelSize(resources, params.mOutsetBottomId) - - outResult.mDecorContainerOffsetY; - startT.setPosition( - mDecorationContainerSurface, - outResult.mDecorContainerOffsetX, outResult.mDecorContainerOffsetY) - .setWindowCrop(mDecorationContainerSurface, - outResult.mWidth, outResult.mHeight) + startT.setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight) .show(mDecorationContainerSurface); - // TaskBackgroundSurface - if (mTaskBackgroundSurface == null) { - final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); - mTaskBackgroundSurface = builder - .setName("Background of Task=" + mTaskInfo.taskId) - .setEffectLayer() - .setParent(mTaskSurface) - .build(); - - startT.setLayer(mTaskBackgroundSurface, TaskConstants.TASK_CHILD_LAYER_TASK_BACKGROUND); - } - - float shadowRadius = loadDimension(resources, params.mShadowRadiusId); - int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); - mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; - mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; - mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; - startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), - taskBounds.height()) - .setShadowRadius(mTaskBackgroundSurface, shadowRadius) - .setColor(mTaskBackgroundSurface, mTmpColor) - .show(mTaskBackgroundSurface); - // CaptionContainerSurface, CaptionWindowManager if (mCaptionContainerSurface == null) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); @@ -268,12 +235,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId); final int captionWidth = taskBounds.width(); - - startT.setPosition( - mCaptionContainerSurface, - -outResult.mDecorContainerOffsetX + params.mCaptionX, - -outResult.mDecorContainerOffsetY + params.mCaptionY) - .setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight) + startT.setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight) .show(mCaptionContainerSurface); if (mCaptionWindowManager == null) { @@ -313,15 +275,18 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } // Task surface itself + float shadowRadius = loadDimension(resources, params.mShadowRadiusId); + int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); + mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; + mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; + mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; Point taskPosition = mTaskInfo.positionInParent; - mTaskSurfaceCrop.set( - outResult.mDecorContainerOffsetX, - outResult.mDecorContainerOffsetY, - outResult.mWidth + outResult.mDecorContainerOffsetX, - outResult.mHeight + outResult.mDecorContainerOffsetY); - startT.show(mTaskSurface); + startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight) + .setShadowRadius(mTaskSurface, shadowRadius) + .setColor(mTaskSurface, mTmpColor) + .show(mTaskSurface); finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y) - .setCrop(mTaskSurface, mTaskSurfaceCrop); + .setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight); } /** @@ -361,12 +326,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> released = true; } - if (mTaskBackgroundSurface != null) { - t.remove(mTaskBackgroundSurface); - mTaskBackgroundSurface = null; - released = true; - } - if (released) { t.apply(); } @@ -400,18 +359,20 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> /** * Create a window associated with this WindowDecoration. * Note that subclass must dispose of this when the task is hidden/closed. - * @param layoutId layout to make the window from - * @param t the transaction to apply - * @param xPos x position of new window - * @param yPos y position of new window - * @param width width of new window - * @param height height of new window + * + * @param layoutId layout to make the window from + * @param t the transaction to apply + * @param xPos x position of new window + * @param yPos y position of new window + * @param width width of new window + * @param height height of new window * @param shadowRadius radius of the shadow of the new window * @param cornerRadius radius of the corners of the new window * @return the {@link AdditionalWindow} that was added. */ AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, - int xPos, int yPos, int width, int height, int shadowRadius, int cornerRadius) { + SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height, int shadowRadius, + int cornerRadius) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); SurfaceControl windowSurfaceControl = builder .setName(namePrefix + " of Task=" + mTaskInfo.taskId) @@ -435,49 +396,27 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> windowSurfaceControl, null /* hostInputToken */); SurfaceControlViewHost viewHost = mSurfaceControlViewHostFactory .create(mDecorWindowContext, mDisplay, windowManager); - viewHost.setView(v, lp); + ssg.add(viewHost.getSurfacePackage(), () -> viewHost.setView(v, lp)); return new AdditionalWindow(windowSurfaceControl, viewHost, mSurfaceControlTransactionSupplier); } - static class RelayoutParams{ + static class RelayoutParams { RunningTaskInfo mRunningTaskInfo; int mLayoutResId; int mCaptionHeightId; int mCaptionWidthId; int mShadowRadiusId; - int mOutsetTopId; - int mOutsetBottomId; - int mOutsetLeftId; - int mOutsetRightId; - int mCaptionX; int mCaptionY; - void setOutsets(int leftId, int topId, int rightId, int bottomId) { - mOutsetLeftId = leftId; - mOutsetTopId = topId; - mOutsetRightId = rightId; - mOutsetBottomId = bottomId; - } - - void setCaptionPosition(int left, int top) { - mCaptionX = left; - mCaptionY = top; - } - void reset() { mLayoutResId = Resources.ID_NULL; mCaptionHeightId = Resources.ID_NULL; mCaptionWidthId = Resources.ID_NULL; mShadowRadiusId = Resources.ID_NULL; - mOutsetTopId = Resources.ID_NULL; - mOutsetBottomId = Resources.ID_NULL; - mOutsetLeftId = Resources.ID_NULL; - mOutsetRightId = Resources.ID_NULL; - mCaptionX = 0; mCaptionY = 0; } @@ -487,14 +426,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> int mWidth; int mHeight; T mRootView; - int mDecorContainerOffsetX; - int mDecorContainerOffsetY; void reset() { mWidth = 0; mHeight = 0; - mDecorContainerOffsetX = 0; - mDecorContainerOffsetY = 0; mRootView = null; } } diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS index 1c28c3d58ccb..64dfc3ef845d 100644 --- a/libs/WindowManager/Shell/tests/OWNERS +++ b/libs/WindowManager/Shell/tests/OWNERS @@ -7,3 +7,4 @@ lbill@google.com madym@google.com hwwang@google.com chenghsiuchang@google.com +atsjenk@google.com diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml index 67ca9a1a17f7..b6d92814ad43 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml @@ -29,6 +29,7 @@ <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" /> <option name="teardown-command" value="settings delete system show_touches" /> <option name="teardown-command" value="settings delete system pointer_location" /> + <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true"/> 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 e986ee127708..c416ad011c4e 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 @@ -137,7 +137,7 @@ fun FlickerTest.splitAppLayerBoundsBecomesVisible( portraitPosTop: Boolean ) { assertLayers { - this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component)) + this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component), isOptional = true) .then() .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component)) .then() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java index cbbb29199d75..b8f615a1855f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java @@ -16,6 +16,7 @@ package com.android.wm.shell.activityembedding; +import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OPEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; @@ -82,10 +83,13 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation @Test public void testStartAnimation_containsNonActivityEmbeddingChange() { + final TransitionInfo.Change nonEmbeddedOpen = createChange(0 /* flags */); + final TransitionInfo.Change embeddedOpen = createEmbeddedChange( + EMBEDDED_LEFT_BOUNDS, EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS); + nonEmbeddedOpen.setMode(TRANSIT_OPEN); final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) - .addChange(createEmbeddedChange( - EMBEDDED_LEFT_BOUNDS, EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS)) - .addChange(createChange(0 /* flags */)) + .addChange(embeddedOpen) + .addChange(nonEmbeddedOpen) .build(); // No-op because it contains non-embedded change. @@ -95,6 +99,22 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation verifyNoMoreInteractions(mStartTransaction); verifyNoMoreInteractions(mFinishTransaction); verifyNoMoreInteractions(mFinishCallback); + + final TransitionInfo.Change nonEmbeddedClose = createChange(0 /* flags */); + nonEmbeddedClose.setMode(TRANSIT_CLOSE); + nonEmbeddedClose.setEndAbsBounds(TASK_BOUNDS); + final TransitionInfo.Change embeddedOpen2 = createEmbeddedChange( + EMBEDDED_RIGHT_BOUNDS, EMBEDDED_RIGHT_BOUNDS, TASK_BOUNDS); + final TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_OPEN, 0) + .addChange(embeddedOpen) + .addChange(embeddedOpen2) + .addChange(nonEmbeddedClose) + .build(); + // Ok to animate because nonEmbeddedClose is occluded by embeddedOpen and embeddedOpen2. + assertTrue(mController.startAnimation(mTransition, info2, mStartTransaction, + mFinishTransaction, mFinishCallback)); + // The non-embedded change is dropped to avoid affecting embedded animation. + assertFalse(info2.getChanges().contains(nonEmbeddedClose)); } @Test 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 806bffebd4cb..d95c7a488ea1 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 @@ -166,6 +166,9 @@ public class BackAnimationControllerTest extends ShellTestCase { doMotionEvent(MotionEvent.ACTION_DOWN, 0); doMotionEvent(MotionEvent.ACTION_MOVE, 0); mController.setTriggerBack(true); + } + + private void releaseBackGesture() { doMotionEvent(MotionEvent.ACTION_UP, 0); } @@ -201,6 +204,8 @@ public class BackAnimationControllerTest extends ShellTestCase { .setOnBackNavigationDone(new RemoteCallback(result))); triggerBackGesture(); simulateRemoteAnimationStart(type); + mShellExecutor.flushAll(); + releaseBackGesture(); simulateRemoteAnimationFinished(); mShellExecutor.flushAll(); @@ -252,6 +257,7 @@ public class BackAnimationControllerTest extends ShellTestCase { createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, false); triggerBackGesture(); + releaseBackGesture(); verify(mAppCallback, times(1)).onBackInvoked(); @@ -269,6 +275,8 @@ public class BackAnimationControllerTest extends ShellTestCase { triggerBackGesture(); simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME); + releaseBackGesture(); + // Check that back invocation is dispatched. verify(mAnimatorCallback).onBackInvoked(); verify(mBackAnimationRunner).onAnimationStart(anyInt(), any(), any(), any(), any()); @@ -308,6 +316,9 @@ public class BackAnimationControllerTest extends ShellTestCase { triggerBackGesture(); simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME); + mShellExecutor.flushAll(); + + releaseBackGesture(); // Simulate transition timeout. mShellExecutor.flushAll(); @@ -369,6 +380,9 @@ public class BackAnimationControllerTest extends ShellTestCase { simulateRemoteAnimationStart(type); mShellExecutor.flushAll(); + releaseBackGesture(); + mShellExecutor.flushAll(); + assertTrue("Navigation Done callback not called for " + BackNavigationInfo.typeToString(type), result.mBackNavigationDone); assertTrue("TriggerBack should have been true", result.mTriggerBack); @@ -395,6 +409,8 @@ public class BackAnimationControllerTest extends ShellTestCase { .setOnBackNavigationDone(new RemoteCallback(result))); triggerBackGesture(); mShellExecutor.flushAll(); + releaseBackGesture(); + mShellExecutor.flushAll(); assertTrue("Navigation Done callback not called for " + BackNavigationInfo.typeToString(type), result.mBackNavigationDone); @@ -458,9 +474,12 @@ public class BackAnimationControllerTest extends ShellTestCase { private void doMotionEvent(int actionDown, int coordinate) { mController.onMotionEvent( - coordinate, coordinate, - actionDown, - BackEvent.EDGE_LEFT); + /* touchX */ coordinate, + /* touchY */ coordinate, + /* velocityX = */ 0, + /* velocityY = */ 0, + /* keyAction */ actionDown, + /* swipeEdge */ BackEvent.EDGE_LEFT); } private void simulateRemoteAnimationStart(int type) throws RemoteException { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java index 3608474bd90e..874ef80c29f0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java @@ -16,8 +16,6 @@ package com.android.wm.shell.back; -import static android.window.BackEvent.EDGE_LEFT; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -48,12 +46,21 @@ public class BackProgressAnimatorTest { private CountDownLatch mTargetProgressCalled = new CountDownLatch(1); private Handler mMainThreadHandler; + private BackMotionEvent backMotionEventFrom(float touchX, float progress) { + return new BackMotionEvent( + /* touchX = */ touchX, + /* touchY = */ 0, + /* progress = */ progress, + /* velocityX = */ 0, + /* velocityY = */ 0, + /* swipeEdge = */ BackEvent.EDGE_LEFT, + /* departingAnimationTarget = */ null); + } + @Before public void setUp() throws Exception { mMainThreadHandler = new Handler(Looper.getMainLooper()); - final BackMotionEvent backEvent = new BackMotionEvent( - 0, 0, - 0, EDGE_LEFT, null); + final BackMotionEvent backEvent = backMotionEventFrom(0, 0); mMainThreadHandler.post( () -> { mProgressAnimator = new BackProgressAnimator(); @@ -63,9 +70,7 @@ public class BackProgressAnimatorTest { @Test public void testBackProgressed() throws InterruptedException { - final BackMotionEvent backEvent = new BackMotionEvent( - 100, 0, - mTargetProgress, EDGE_LEFT, null); + final BackMotionEvent backEvent = backMotionEventFrom(100, mTargetProgress); mMainThreadHandler.post( () -> mProgressAnimator.onBackProgressed(backEvent)); @@ -78,9 +83,7 @@ public class BackProgressAnimatorTest { @Test public void testBackCancelled() throws InterruptedException { // Give the animator some progress. - final BackMotionEvent backEvent = new BackMotionEvent( - 100, 0, - mTargetProgress, EDGE_LEFT, null); + final BackMotionEvent backEvent = backMotionEventFrom(100, mTargetProgress); mMainThreadHandler.post( () -> mProgressAnimator.onBackProgressed(backEvent)); mTargetProgressCalled.await(1, TimeUnit.SECONDS); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java index ba9c159bad28..d62e6601723a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java @@ -47,43 +47,45 @@ public class TouchTrackerTest { public void generatesProgress_leftEdge() { mTouchTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0, BackEvent.EDGE_LEFT); float touchX = 10; + float velocityX = 0; + float velocityY = 0; // Pre-commit - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f); // Post-commit touchX += 100; mTouchTracker.setTriggerBack(true); - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f); // Cancel touchX -= 10; mTouchTracker.setTriggerBack(false); - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), 0, 0f); // Cancel more touchX -= 10; - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), 0, 0f); // Restart touchX += 10; - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), 0, 0f); // Restarted, but pre-commit float restartX = touchX; touchX += 10; - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), (touchX - restartX) / FAKE_THRESHOLD, 0f); // Restarted, post-commit touchX += 10; mTouchTracker.setTriggerBack(true); - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f); } @@ -91,43 +93,45 @@ public class TouchTrackerTest { public void generatesProgress_rightEdge() { mTouchTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0, BackEvent.EDGE_RIGHT); float touchX = INITIAL_X_RIGHT_EDGE - 10; // Fake right edge + float velocityX = 0f; + float velocityY = 0f; // Pre-commit - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f); // Post-commit touchX -= 100; mTouchTracker.setTriggerBack(true); - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f); // Cancel touchX += 10; mTouchTracker.setTriggerBack(false); - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), 0, 0f); // Cancel more touchX += 10; - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), 0, 0f); // Restart touchX -= 10; - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), 0, 0f); // Restarted, but pre-commit float restartX = touchX; touchX -= 10; - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), (restartX - touchX) / FAKE_THRESHOLD, 0f); // Restarted, post-commit touchX -= 10; mTouchTracker.setTriggerBack(true); - mTouchTracker.update(touchX, 0); + mTouchTracker.update(touchX, 0, velocityX, velocityY); assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java index 15bb10ed4f2b..842c699fa42d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java @@ -262,7 +262,8 @@ public class PipTaskOrganizerTest extends ShellTestCase { DisplayLayout layout = new DisplayLayout(info, mContext.getResources(), true, true); mPipDisplayLayoutState.setDisplayLayout(layout); - mPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA); + doReturn(PipAnimationController.ANIM_TYPE_ALPHA).when(mMockPipAnimationController) + .takeOneShotEnterAnimationType(); mPipTaskOrganizer.setSurfaceControlTransactionFactory( MockSurfaceControlHelper::createMockSurfaceControlTransaction); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java index 390c830069eb..425bbf056b85 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java @@ -18,7 +18,6 @@ package com.android.wm.shell.pip.phone; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -76,7 +75,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase { @Mock private Resources mResources; private PipDisplayLayoutState mPipDisplayLayoutState; - private PipSizeSpecHandler mPipSizeSpecHandler; + private TestPipSizeSpecHandler mPipSizeSpecHandler; /** * Sets up static Mockito session for SystemProperties and mocks necessary static methods. @@ -84,8 +83,6 @@ public class PipSizeSpecHandlerTest extends ShellTestCase { private static void setUpStaticSystemPropertiesSession() { sStaticMockitoSession = mockitoSession() .mockStatic(SystemProperties.class).startMocking(); - // make sure the feature flag is on - when(SystemProperties.getBoolean(anyString(), anyBoolean())).thenReturn(true); when(SystemProperties.get(anyString(), anyString())).thenAnswer(invocation -> { String property = invocation.getArgument(0); if (property.equals("com.android.wm.shell.pip.phone.def_percentage")) { @@ -161,7 +158,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase { mPipDisplayLayoutState.setDisplayLayout(displayLayout); setUpStaticSystemPropertiesSession(); - mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState); + mPipSizeSpecHandler = new TestPipSizeSpecHandler(mContext, mPipDisplayLayoutState); // no overridden min edge size by default mPipSizeSpecHandler.setOverrideMinSize(null); @@ -214,4 +211,16 @@ public class PipSizeSpecHandlerTest extends ShellTestCase { Assert.assertEquals(expectedSize, actualSize); } + + static class TestPipSizeSpecHandler extends PipSizeSpecHandler { + + TestPipSizeSpecHandler(Context context, PipDisplayLayoutState displayLayoutState) { + super(context, displayLayoutState); + } + + @Override + boolean supportsPipSizeLargeScreen() { + return true; + } + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java index e5b61ed2fd25..02e6b8c71663 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java @@ -158,19 +158,73 @@ public class TvPipActionProviderTest extends ShellTestCase { new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE})); } - @Test - public void expandedPip_toggleExpansion() { - assumeTelevision(); - // PiP has expanded PiP enabled, but is in a collapsed state + private void check_expandedPip_updateExpansionState( + boolean startExpansion, boolean endExpansion, boolean updateExpected) { + mActionsProvider.updateExpansionEnabled(true); - mActionsProvider.onPipExpansionToggled(/* expanded= */ false); + mActionsProvider.updatePipExpansionState(startExpansion); mActionsProvider.addListener(mMockListener); - mActionsProvider.onPipExpansionToggled(/* expanded= */ true); + mActionsProvider.updatePipExpansionState(endExpansion); assertTrue(checkActionsMatch(mActionsProvider.getActionsList(), new int[]{ACTION_FULLSCREEN, ACTION_CLOSE, ACTION_MOVE, ACTION_EXPAND_COLLAPSE})); - verify(mMockListener).onActionsChanged(0, 1, 3); + + if (updateExpected) { + verify(mMockListener).onActionsChanged(0, 1, 3); + } else { + verify(mMockListener, times(0)) + .onActionsChanged(anyInt(), anyInt(), anyInt()); + } + } + + @Test + public void expandedPip_toggleExpansion_collapse() { + assumeTelevision(); + check_expandedPip_updateExpansionState( + /* startExpansion= */ true, + /* endExpansion= */ false, + /* updateExpected= */ true); + } + + @Test + public void expandedPip_toggleExpansion_expand() { + assumeTelevision(); + check_expandedPip_updateExpansionState( + /* startExpansion= */ false, + /* endExpansion= */ true, + /* updateExpected= */ true); + } + + @Test + public void expandedPiP_updateExpansionState_alreadyExpanded() { + assumeTelevision(); + check_expandedPip_updateExpansionState( + /* startExpansion= */ true, + /* endExpansion= */ true, + /* updateExpected= */ false); + } + + @Test + public void expandedPiP_updateExpansionState_alreadyCollapsed() { + assumeTelevision(); + check_expandedPip_updateExpansionState( + /* startExpansion= */ false, + /* endExpansion= */ false, + /* updateExpected= */ false); + } + + @Test + public void regularPiP_updateExpansionState_setCollapsed() { + assumeTelevision(); + mActionsProvider.updateExpansionEnabled(false); + mActionsProvider.updatePipExpansionState(/* expanded= */ false); + + mActionsProvider.addListener(mMockListener); + mActionsProvider.updatePipExpansionState(/* expanded= */ false); + + verify(mMockListener, times(0)) + .onActionsChanged(anyInt(), anyInt(), anyInt()); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index eda6fdc4dbd4..e6219d1aa792 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -113,6 +113,7 @@ public class StageCoordinatorTests extends ShellTestCase { private SurfaceSession mSurfaceSession = new SurfaceSession(); private SurfaceControl mRootLeash; + private SurfaceControl mDividerLeash; private ActivityManager.RunningTaskInfo mRootTask; private StageCoordinator mStageCoordinator; private Transitions mTransitions; @@ -129,12 +130,14 @@ public class StageCoordinatorTests extends ShellTestCase { mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mMainExecutor, Optional.empty())); + mDividerLeash = new SurfaceControl.Builder(mSurfaceSession).setName("fakeDivider").build(); when(mSplitLayout.getBounds1()).thenReturn(mBounds1); when(mSplitLayout.getBounds2()).thenReturn(mBounds2); when(mSplitLayout.getRootBounds()).thenReturn(mRootBounds); when(mSplitLayout.isLandscape()).thenReturn(false); when(mSplitLayout.applyTaskChanges(any(), any(), any())).thenReturn(true); + when(mSplitLayout.getDividerLeash()).thenReturn(mDividerLeash); mRootTask = new TestRunningTaskInfoBuilder().build(); mRootLeash = new SurfaceControl.Builder(mSurfaceSession).setName("test").build(); 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 dfa3c1010eed..c1e53a90b7e0 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 @@ -49,7 +49,7 @@ import android.view.View; import android.view.ViewRootImpl; import android.view.WindowInsets; import android.view.WindowManager.LayoutParams; -import android.window.TaskConstants; +import android.window.SurfaceSyncGroup; import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; @@ -100,6 +100,8 @@ public class WindowDecorationTests extends ShellTestCase { private TestView mMockView; @Mock private WindowContainerTransaction mMockWindowContainerTransaction; + @Mock + private SurfaceSyncGroup mMockSurfaceSyncGroup; private final List<SurfaceControl.Transaction> mMockSurfaceControlTransactions = new ArrayList<>(); @@ -159,14 +161,8 @@ public class WindowDecorationTests extends ShellTestCase { .setVisible(false) .build(); taskInfo.isFocused = false; - // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is - // 64px. + // Density is 2. Shadow radius is 10px. Caption height is 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; - mRelayoutParams.setOutsets( - R.dimen.test_window_decor_left_outset, - R.dimen.test_window_decor_top_outset, - R.dimen.test_window_decor_right_outset, - R.dimen.test_window_decor_bottom_outset); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); @@ -193,10 +189,6 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); - final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class); - final SurfaceControl.Builder taskBackgroundSurfaceBuilder = - createMockSurfaceControlBuilder(taskBackgroundSurface); - mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder); final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); final SurfaceControl.Builder captionContainerSurfaceBuilder = createMockSurfaceControlBuilder(captionContainerSurface); @@ -213,14 +205,8 @@ public class WindowDecorationTests extends ShellTestCase { .setVisible(true) .build(); taskInfo.isFocused = true; - // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is - // 64px. + // Density is 2. Shadow radius is 10px. Caption height is 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; - mRelayoutParams.setOutsets( - R.dimen.test_window_decor_left_outset, - R.dimen.test_window_decor_top_outset, - R.dimen.test_window_decor_right_outset, - R.dimen.test_window_decor_bottom_outset); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); @@ -229,22 +215,10 @@ public class WindowDecorationTests extends ShellTestCase { verify(decorContainerSurfaceBuilder).setParent(taskSurface); verify(decorContainerSurfaceBuilder).setContainerLayer(); verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true); - verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -20, -40); - verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 380, 220); - - verify(taskBackgroundSurfaceBuilder).setParent(taskSurface); - verify(taskBackgroundSurfaceBuilder).setEffectLayer(); - verify(mMockSurfaceControlStartT).setWindowCrop(taskBackgroundSurface, 300, 100); - verify(mMockSurfaceControlStartT) - .setColor(taskBackgroundSurface, new float[] {1.f, 1.f, 0.f}); - verify(mMockSurfaceControlStartT).setShadowRadius(taskBackgroundSurface, 10); - verify(mMockSurfaceControlStartT).setLayer(taskBackgroundSurface, - TaskConstants.TASK_CHILD_LAYER_TASK_BACKGROUND); - verify(mMockSurfaceControlStartT).show(taskBackgroundSurface); + verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 300, 100); verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface); verify(captionContainerSurfaceBuilder).setContainerLayer(); - verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40); verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64); verify(mMockSurfaceControlStartT).show(captionContainerSurface); @@ -268,12 +242,15 @@ public class WindowDecorationTests extends ShellTestCase { verify(mMockSurfaceControlFinishT) .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y); verify(mMockSurfaceControlFinishT) - .setCrop(taskSurface, new Rect(-20, -40, 360, 180)); + .setWindowCrop(taskSurface, 300, 100); verify(mMockSurfaceControlStartT) .show(taskSurface); + verify(mMockSurfaceControlStartT) + .setColor(taskSurface, new float[] {1.f, 1.f, 0.f}); + verify(mMockSurfaceControlStartT).setShadowRadius(taskSurface, 10); - assertEquals(380, mRelayoutResult.mWidth); - assertEquals(220, mRelayoutResult.mHeight); + assertEquals(300, mRelayoutResult.mWidth); + assertEquals(100, mRelayoutResult.mHeight); } @Test @@ -286,10 +263,6 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); - final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class); - final SurfaceControl.Builder taskBackgroundSurfaceBuilder = - createMockSurfaceControlBuilder(taskBackgroundSurface); - mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder); final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); final SurfaceControl.Builder captionContainerSurfaceBuilder = createMockSurfaceControlBuilder(captionContainerSurface); @@ -309,14 +282,8 @@ public class WindowDecorationTests extends ShellTestCase { .setVisible(true) .build(); taskInfo.isFocused = true; - // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is - // 64px. + // Density is 2. Shadow radius is 10px. Caption height is 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; - mRelayoutParams.setOutsets( - R.dimen.test_window_decor_left_outset, - R.dimen.test_window_decor_top_outset, - R.dimen.test_window_decor_right_outset, - R.dimen.test_window_decor_bottom_outset); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); @@ -335,7 +302,6 @@ public class WindowDecorationTests extends ShellTestCase { releaseOrder.verify(mMockSurfaceControlViewHost).release(); releaseOrder.verify(t).remove(captionContainerSurface); releaseOrder.verify(t).remove(decorContainerSurface); - releaseOrder.verify(t).remove(taskBackgroundSurface); releaseOrder.verify(t).apply(); verify(mMockWindowContainerTransaction) .removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt()); @@ -396,10 +362,6 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); - final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class); - final SurfaceControl.Builder taskBackgroundSurfaceBuilder = - createMockSurfaceControlBuilder(taskBackgroundSurface); - mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder); final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); final SurfaceControl.Builder captionContainerSurfaceBuilder = createMockSurfaceControlBuilder(captionContainerSurface); @@ -419,11 +381,6 @@ public class WindowDecorationTests extends ShellTestCase { .build(); taskInfo.isFocused = true; taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; - mRelayoutParams.setOutsets( - R.dimen.test_window_decor_left_outset, - R.dimen.test_window_decor_top_outset, - R.dimen.test_window_decor_right_outset, - R.dimen.test_window_decor_bottom_outset); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); windowDecor.relayout(taskInfo); @@ -438,7 +395,7 @@ public class WindowDecorationTests extends ShellTestCase { verify(additionalWindowSurfaceBuilder).setContainerLayer(); verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface); verify(additionalWindowSurfaceBuilder).build(); - verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 20, 40); + verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 0, 0); final int width = WindowDecoration.loadDimensionPixelSize( mContext.getResources(), mCaptionMenuWidthId); final int height = WindowDecoration.loadDimensionPixelSize( @@ -473,10 +430,6 @@ public class WindowDecorationTests extends ShellTestCase { final SurfaceControl.Builder decorContainerSurfaceBuilder = createMockSurfaceControlBuilder(decorContainerSurface); mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); - final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class); - final SurfaceControl.Builder taskBackgroundSurfaceBuilder = - createMockSurfaceControlBuilder(taskBackgroundSurface); - mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder); final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); final SurfaceControl.Builder captionContainerSurfaceBuilder = createMockSurfaceControlBuilder(captionContainerSurface); @@ -496,11 +449,6 @@ public class WindowDecorationTests extends ShellTestCase { .build(); taskInfo.isFocused = true; taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; - mRelayoutParams.setOutsets( - R.dimen.test_window_decor_left_outset, - R.dimen.test_window_decor_top_outset, - R.dimen.test_window_decor_right_outset, - R.dimen.test_window_decor_bottom_outset); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); @@ -508,7 +456,6 @@ public class WindowDecorationTests extends ShellTestCase { verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface); verify(captionContainerSurfaceBuilder).setContainerLayer(); - verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40); // Width of the captionContainerSurface should match the width of TASK_BOUNDS verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64); verify(mMockSurfaceControlStartT).show(captionContainerSurface); @@ -584,9 +531,7 @@ public class WindowDecorationTests extends ShellTestCase { String name = "Test Window"; WindowDecoration.AdditionalWindow additionalWindow = addWindow(R.layout.desktop_mode_window_decor_handle_menu_app_info_pill, name, - mMockSurfaceControlAddWindowT, - x - mRelayoutResult.mDecorContainerOffsetX, - y - mRelayoutResult.mDecorContainerOffsetY, + mMockSurfaceControlAddWindowT, mMockSurfaceSyncGroup, x, y, width, height, shadowRadius, cornerRadius); return additionalWindow; } diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 0b58406516e3..924fbd659824 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -51,6 +51,9 @@ #include "include/gpu/GrDirectContext.h" #include "pipeline/skia/AnimatedDrawables.h" #include "pipeline/skia/FunctorDrawable.h" +#ifdef __ANDROID__ +#include "renderthread/CanvasContext.h" +#endif namespace android { namespace uirenderer { @@ -489,7 +492,19 @@ struct DrawPoints final : Op { size_t count; SkPaint paint; void draw(SkCanvas* c, const SkMatrix&) const { - c->drawPoints(mode, count, pod<SkPoint>(this), paint); + if (paint.isAntiAlias()) { + c->drawPoints(mode, count, pod<SkPoint>(this), paint); + } else { + c->save(); +#ifdef __ANDROID__ + auto pixelSnap = renderthread::CanvasContext::getActiveContext()->getPixelSnapMatrix(); + auto transform = c->getLocalToDevice(); + transform.postConcat(pixelSnap); + c->setMatrix(transform); +#endif + c->drawPoints(mode, count, pod<SkPoint>(this), paint); + c->restore(); + } } }; struct DrawVertices final : Op { diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp index d08bc5c583c2..8049dc946c9e 100644 --- a/libs/hwui/hwui/AnimatedImageDrawable.cpp +++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp @@ -29,9 +29,10 @@ namespace android { -AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed) - : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) { - mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration()); +AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed, + SkEncodedImageFormat format) + : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed), mFormat(format) { + mTimeToShowNextSnapshot = ms2ns(currentFrameDuration()); setStagingBounds(mSkAnimatedImage->getBounds()); } @@ -92,7 +93,7 @@ bool AnimatedImageDrawable::isDirty(nsecs_t* outDelay) { // directly from mSkAnimatedImage. lock.unlock(); std::unique_lock imageLock{mImageLock}; - *outDelay = ms2ns(mSkAnimatedImage->currentFrameDuration()); + *outDelay = ms2ns(currentFrameDuration()); return true; } else { // The next snapshot has not yet been decoded, but we've already passed @@ -109,7 +110,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::decodeNextFrame() { Snapshot snap; { std::unique_lock lock{mImageLock}; - snap.mDurationMS = mSkAnimatedImage->decodeNextFrame(); + snap.mDurationMS = adjustFrameDuration(mSkAnimatedImage->decodeNextFrame()); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); } @@ -123,7 +124,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() { std::unique_lock lock{mImageLock}; mSkAnimatedImage->reset(); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); - snap.mDurationMS = mSkAnimatedImage->currentFrameDuration(); + snap.mDurationMS = currentFrameDuration(); } return snap; @@ -274,7 +275,7 @@ int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { { std::unique_lock lock{mImageLock}; mSkAnimatedImage->reset(); - durationMS = mSkAnimatedImage->currentFrameDuration(); + durationMS = currentFrameDuration(); } { std::unique_lock lock{mSwapLock}; @@ -306,7 +307,7 @@ int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { { std::unique_lock lock{mImageLock}; if (update) { - durationMS = mSkAnimatedImage->decodeNextFrame(); + durationMS = adjustFrameDuration(mSkAnimatedImage->decodeNextFrame()); } canvas->drawDrawable(mSkAnimatedImage.get()); @@ -336,4 +337,20 @@ SkRect AnimatedImageDrawable::onGetBounds() { return SkRectMakeLargest(); } +int AnimatedImageDrawable::adjustFrameDuration(int durationMs) { + if (durationMs == SkAnimatedImage::kFinished) { + return SkAnimatedImage::kFinished; + } + + if (mFormat == SkEncodedImageFormat::kGIF) { + // Match Chrome & Firefox behavior that gifs with a duration <= 10ms is bumped to 100ms + return durationMs <= 10 ? 100 : durationMs; + } + return durationMs; +} + +int AnimatedImageDrawable::currentFrameDuration() { + return adjustFrameDuration(mSkAnimatedImage->currentFrameDuration()); +} + } // namespace android diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h index 8ca3c7e125f1..1e965abc82b5 100644 --- a/libs/hwui/hwui/AnimatedImageDrawable.h +++ b/libs/hwui/hwui/AnimatedImageDrawable.h @@ -16,16 +16,16 @@ #pragma once -#include <cutils/compiler.h> -#include <utils/Macros.h> -#include <utils/RefBase.h> -#include <utils/Timers.h> - #include <SkAnimatedImage.h> #include <SkCanvas.h> #include <SkColorFilter.h> #include <SkDrawable.h> +#include <SkEncodedImageFormat.h> #include <SkPicture.h> +#include <cutils/compiler.h> +#include <utils/Macros.h> +#include <utils/RefBase.h> +#include <utils/Timers.h> #include <future> #include <mutex> @@ -48,7 +48,8 @@ class AnimatedImageDrawable : public SkDrawable { public: // bytesUsed includes the approximate sizes of the SkAnimatedImage and the SkPictures in the // Snapshots. - AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed); + AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed, + SkEncodedImageFormat format); /** * This updates the internal time and returns true if the image needs @@ -115,6 +116,7 @@ protected: private: sk_sp<SkAnimatedImage> mSkAnimatedImage; const size_t mBytesUsed; + const SkEncodedImageFormat mFormat; bool mRunning = false; bool mStarting = false; @@ -157,6 +159,9 @@ private: Properties mProperties; std::unique_ptr<OnAnimationEndListener> mEndListener; + + int adjustFrameDuration(int); + int currentFrameDuration(); }; } // namespace android diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp index 373e893b9a25..a7f5aa83e624 100644 --- a/libs/hwui/jni/AnimatedImageDrawable.cpp +++ b/libs/hwui/jni/AnimatedImageDrawable.cpp @@ -97,7 +97,7 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/, bytesUsed += picture->approximateBytesUsed(); } - + SkEncodedImageFormat format = imageDecoder->mCodec->getEncodedFormat(); sk_sp<SkAnimatedImage> animatedImg = SkAnimatedImage::Make(std::move(imageDecoder->mCodec), info, subset, std::move(picture)); @@ -108,8 +108,8 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/, bytesUsed += sizeof(animatedImg.get()); - sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(std::move(animatedImg), - bytesUsed)); + sk_sp<AnimatedImageDrawable> drawable( + new AnimatedImageDrawable(std::move(animatedImg), bytesUsed, format)); return reinterpret_cast<jlong>(drawable.release()); } diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index cc987bcd8f0e..c4d3f5cedfa8 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -53,6 +53,8 @@ SkiaOpenGLPipeline::~SkiaOpenGLPipeline() { } MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() { + bool wasSurfaceless = mEglManager.isCurrent(EGL_NO_SURFACE); + // In case the surface was destroyed (e.g. a previous trimMemory call) we // need to recreate it here. if (mHardwareBuffer) { @@ -65,6 +67,37 @@ MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() { if (!mEglManager.makeCurrent(mEglSurface, &error)) { return MakeCurrentResult::AlreadyCurrent; } + + // Make sure read/draw buffer state of default framebuffer is GL_BACK. Vendor implementations + // disagree on the draw/read buffer state if the default framebuffer transitions from a surface + // to EGL_NO_SURFACE and vice-versa. There was a related discussion within Khronos on this topic. + // See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13534. + // The discussion was not resolved with a clear consensus + if (error == 0 && wasSurfaceless && mEglSurface != EGL_NO_SURFACE) { + GLint curReadFB = 0; + GLint curDrawFB = 0; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &curReadFB); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &curDrawFB); + + GLint buffer = GL_NONE; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glGetIntegerv(GL_DRAW_BUFFER0, &buffer); + if (buffer == GL_NONE) { + const GLenum drawBuffer = GL_BACK; + glDrawBuffers(1, &drawBuffer); + } + + glGetIntegerv(GL_READ_BUFFER, &buffer); + if (buffer == GL_NONE) { + glReadBuffer(GL_BACK); + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, curReadFB); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, curDrawFB); + + GL_CHECKPOINT(LOW); + } + return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded; } @@ -104,7 +137,8 @@ IRenderPipeline::DrawResult SkiaOpenGLPipeline::draw( GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, fboInfo); - SkSurfaceProps props(0, kUnknown_SkPixelGeometry); + SkSurfaceProps props(mColorMode == ColorMode::Default ? 0 : SkSurfaceProps::kAlwaysDither_Flag, + kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); sk_sp<SkSurface> surface; diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 940d6bfdb83c..f0461bef170c 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -53,6 +53,14 @@ public: bool isSurfaceReady() override; bool isContextReady() override; + const SkM44& getPixelSnapMatrix() const override { + // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the + // desired fragment + static const SkScalar kOffset = 0.063f; + static const SkM44 sSnapMatrix = SkM44::Translate(kOffset, kOffset); + return sSnapMatrix; + } + static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); protected: diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 1f929685b62c..b020e966e05a 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -28,7 +28,6 @@ #include <SkMultiPictureDocument.h> #include <SkOverdrawCanvas.h> #include <SkOverdrawColorFilter.h> -#include <SkPaintFilterCanvas.h> #include <SkPicture.h> #include <SkPictureRecorder.h> #include <SkRect.h> @@ -450,23 +449,6 @@ void SkiaPipeline::endCapture(SkSurface* surface) { } } -class ForceDitherCanvas : public SkPaintFilterCanvas { -public: - ForceDitherCanvas(SkCanvas* canvas) : SkPaintFilterCanvas(canvas) {} - -protected: - bool onFilter(SkPaint& paint) const override { - paint.setDither(true); - return true; - } - - void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override { - // We unroll the drawable using "this" canvas, so that draw calls contained inside will - // get dithering applied - drawable->draw(this, matrix); - } -}; - void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip, const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect& contentDrawBounds, sk_sp<SkSurface> surface, @@ -521,12 +503,6 @@ void SkiaPipeline::renderFrameImpl(const SkRect& clip, canvas->clear(SK_ColorTRANSPARENT); } - std::optional<ForceDitherCanvas> forceDitherCanvas; - if (shouldForceDither()) { - forceDitherCanvas.emplace(canvas); - canvas = &forceDitherCanvas.value(); - } - if (1 == nodes.size()) { if (!nodes[0]->nothingToDraw()) { RenderNodeDrawable root(nodes[0].get(), canvas); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 0763b06b53ef..befee8989383 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -98,8 +98,6 @@ protected: bool isCapturingSkp() const { return mCaptureMode != CaptureMode::None; } - virtual bool shouldForceDither() const { return mColorMode != ColorMode::Default; } - private: void renderFrameImpl(const SkRect& clip, const std::vector<sp<RenderNode>>& nodes, bool opaque, diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 6f1b99b95bbd..86096d5bd01c 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -203,11 +203,6 @@ sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThr return nullptr; } -bool SkiaVulkanPipeline::shouldForceDither() const { - if (mVkSurface && mVkSurface->isBeyond8Bit()) return false; - return SkiaPipeline::shouldForceDither(); -} - void SkiaVulkanPipeline::onContextDestroyed() { if (mVkSurface) { vulkanManager().destroySurface(mVkSurface); @@ -215,6 +210,10 @@ void SkiaVulkanPipeline::onContextDestroyed() { } } +const SkM44& SkiaVulkanPipeline::getPixelSnapMatrix() const { + return mVkSurface->getPixelSnapMatrix(); +} + } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 0713e93bccde..284cde537ec0 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -53,8 +53,8 @@ public: void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; - bool supportsExtendedRangeHdr() const override { return true; } void setTargetSdrHdrRatio(float ratio) override; + const SkM44& getPixelSnapMatrix() const override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread, @@ -63,8 +63,6 @@ public: protected: void onContextDestroyed() override; - bool shouldForceDither() const override; - private: renderthread::VulkanManager& vulkanManager(); renderthread::VulkanSurface* mVkSurface = nullptr; diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 23611efccd73..7e9d44fbdbd1 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -117,12 +117,8 @@ void CacheManager::trimMemory(TrimLevel mode) { // flush and submit all work to the gpu and wait for it to finish mGrContext->flushAndSubmit(/*syncCpu=*/true); - if (!Properties::isHighEndGfx && mode >= TrimLevel::MODERATE) { - mode = TrimLevel::COMPLETE; - } - switch (mode) { - case TrimLevel::COMPLETE: + case TrimLevel::BACKGROUND: mGrContext->freeGpuResources(); SkGraphics::PurgeAllCaches(); mRenderThread.destroyRenderingContext(); diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 6b2c99534a4c..f60c1f3c6ad8 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -236,7 +236,6 @@ void CanvasContext::setupPipelineSurface() { if (mNativeSurface && !mNativeSurface->didSetExtraBuffers()) { setBufferCount(mNativeSurface->getNativeWindow()); - } mFrameNumber = 0; @@ -301,10 +300,6 @@ void CanvasContext::setOpaque(bool opaque) { float CanvasContext::setColorMode(ColorMode mode) { if (mode != mColorMode) { - const bool isHdr = mode == ColorMode::Hdr || mode == ColorMode::Hdr10; - if (isHdr && !mRenderPipeline->supportsExtendedRangeHdr()) { - mode = ColorMode::WideColorGamut; - } mColorMode = mode; mRenderPipeline->setSurfaceColorProperties(mode); setupPipelineSurface(); @@ -871,6 +866,10 @@ SkISize CanvasContext::getNextFrameSize() const { return size; } +const SkM44& CanvasContext::getPixelSnapMatrix() const { + return mRenderPipeline->getPixelSnapMatrix(); +} + void CanvasContext::prepareAndDraw(RenderNode* node) { ATRACE_CALL(); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 3f2533959c20..d7215de92375 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -200,6 +200,9 @@ public: SkISize getNextFrameSize() const; + // Returns the matrix to use to nudge non-AA'd points/lines towards the fragment center + const SkM44& getPixelSnapMatrix() const; + // Called when SurfaceStats are available. static void onSurfaceStatsAvailable(void* context, int32_t surfaceControlId, ASurfaceControlStats* stats); diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 4fb114b71bf5..94f35fd9eaf2 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -423,6 +423,7 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window, EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE}; EGLConfig config = mEglConfig; + bool overrideWindowDataSpaceForHdr = false; if (colorMode == ColorMode::A8) { // A8 doesn't use a color space if (!mEglConfigA8) { @@ -450,12 +451,13 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window, case ColorMode::Default: attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; break; - // Extended Range HDR requires being able to manipulate the dataspace in ways - // we cannot easily do while going through EGLSurface. Given this requires - // composer3 support, just treat HDR as equivalent to wide color gamut if - // the GLES path is still being hit + // We don't have an EGL colorspace for extended range P3 that's used for HDR + // So override it after configuring the EGL context case ColorMode::Hdr: case ColorMode::Hdr10: + overrideWindowDataSpaceForHdr = true; + attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT; + break; case ColorMode::WideColorGamut: { skcms_Matrix3x3 colorGamut; LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut), @@ -491,6 +493,16 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window, (void*)window, eglErrorString()); } + if (overrideWindowDataSpaceForHdr) { + // This relies on knowing that EGL will not re-set the dataspace after the call to + // eglCreateWindowSurface. Since the handling of the colorspace extension is largely + // implemented in libEGL in the platform, we can safely assume this is the case + int32_t err = ANativeWindow_setBuffersDataSpace( + window, + static_cast<android_dataspace>(STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_EXTENDED)); + LOG_ALWAYS_FATAL_IF(err, "Failed to ANativeWindow_setBuffersDataSpace %d", err); + } + return surface; } diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index c68fcdfc76f2..6c2cb9d71c55 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -95,8 +95,8 @@ public: virtual void setPictureCapturedCallback( const std::function<void(sk_sp<SkPicture>&&)>& callback) = 0; - virtual bool supportsExtendedRangeHdr() const { return false; } virtual void setTargetSdrHdrRatio(float ratio) = 0; + virtual const SkM44& getPixelSnapMatrix() const = 0; virtual ~IRenderPipeline() {} }; diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 718d4a16d5c8..96bfc1061d4e 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -42,6 +42,36 @@ namespace android { namespace uirenderer { namespace renderthread { +static std::array<std::string_view, 18> sEnableExtensions{ + VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, + VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, + VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + VK_KHR_MAINTENANCE1_EXTENSION_NAME, + VK_KHR_MAINTENANCE2_EXTENSION_NAME, + VK_KHR_MAINTENANCE3_EXTENSION_NAME, + VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, + VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, + VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, + VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, + VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, +}; + +static bool shouldEnableExtension(const std::string_view& extension) { + for (const auto& it : sEnableExtensions) { + if (it == extension) { + return true; + } + } + return false; +} + static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) { // All Vulkan structs that could be part of the features chain will start with the // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader @@ -139,6 +169,11 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe bool hasKHRSurfaceExtension = false; bool hasKHRAndroidSurfaceExtension = false; for (const VkExtensionProperties& extension : mInstanceExtensionsOwner) { + if (!shouldEnableExtension(extension.extensionName)) { + ALOGV("Not enabling instance extension %s", extension.extensionName); + continue; + } + ALOGV("Enabling instance extension %s", extension.extensionName); mInstanceExtensions.push_back(extension.extensionName); if (!strcmp(extension.extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) { hasKHRSurfaceExtension = true; @@ -219,6 +254,11 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err); bool hasKHRSwapchainExtension = false; for (const VkExtensionProperties& extension : mDeviceExtensionsOwner) { + if (!shouldEnableExtension(extension.extensionName)) { + ALOGV("Not enabling device extension %s", extension.extensionName); + continue; + } + ALOGV("Enabling device extension %s", extension.extensionName); mDeviceExtensions.push_back(extension.extensionName); if (!strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { hasKHRSwapchainExtension = true; diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp index ae4f0572576e..10f456745147 100644 --- a/libs/hwui/renderthread/VulkanSurface.cpp +++ b/libs/hwui/renderthread/VulkanSurface.cpp @@ -63,6 +63,18 @@ static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) { return SkMatrix::I(); } +static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) { + // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the + // desired fragment + static const SkScalar kOffset = 0.063f; + SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform); + SkMatrix invert; + LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert)); + return SkM44::Translate(kOffset, kOffset) + .postConcat(SkM44(preRotation)) + .preConcat(SkM44(invert)); +} + static bool ConnectAndSetWindowDefaults(ANativeWindow* window) { ATRACE_CALL(); @@ -178,6 +190,8 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode outWindowInfo->preTransform = GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform); + outWindowInfo->pixelSnapMatrix = + GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform); err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); if (err != 0 || query_value < 0) { @@ -413,6 +427,7 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { } mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform); + mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform); } uint32_t idx; @@ -438,9 +453,15 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx]; if (bufferInfo->skSurface.get() == nullptr) { + SkSurfaceProps surfaceProps; + if (mWindowInfo.colorMode != ColorMode::Default) { + surfaceProps = SkSurfaceProps(SkSurfaceProps::kAlwaysDither_Flag | surfaceProps.flags(), + surfaceProps.pixelGeometry()); + } bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer( mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()), - kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, nullptr, /*from_window=*/true); + kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, &surfaceProps, + /*from_window=*/true); if (bufferInfo->skSurface.get() == nullptr) { ALOGE("SkSurface::MakeFromAHardwareBuffer failed"); mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, @@ -530,16 +551,6 @@ void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) { } } -bool VulkanSurface::isBeyond8Bit() const { - switch (mWindowInfo.bufferFormat) { - case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: - case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: - return true; - default: - return false; - } -} - } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h index 3b69b73bcab3..6f5280105e55 100644 --- a/libs/hwui/renderthread/VulkanSurface.h +++ b/libs/hwui/renderthread/VulkanSurface.h @@ -47,8 +47,7 @@ public: const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; } void setColorSpace(sk_sp<SkColorSpace> colorSpace); - - bool isBeyond8Bit() const; + const SkM44& getPixelSnapMatrix() const { return mWindowInfo.pixelSnapMatrix; } private: /* @@ -107,6 +106,7 @@ private: SkISize actualSize; // transform to be applied to the SkSurface to map the coordinates to the provided transform SkMatrix preTransform; + SkM44 pixelSnapMatrix; }; VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, GrDirectContext* grContext); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b1d2e33df3f7..4759689335e9 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3730,7 +3730,12 @@ public class AudioManager { @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) public void setA2dpSuspended(boolean enable) { - AudioSystem.setParameters("A2dpSuspended=" + enable); + final IAudioService service = getService(); + try { + service.setA2dpSuspended(enable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -3743,7 +3748,12 @@ public class AudioManager { @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) public void setLeAudioSuspended(boolean enable) { - AudioSystem.setParameters("LeAudioSuspended=" + enable); + final IAudioService service = getService(); + try { + service.setLeAudioSuspended(enable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index e73cf87ba9f3..3123ee6dd4d7 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -1237,6 +1237,9 @@ public class AudioSystem public static final Set<Integer> DEVICE_IN_ALL_SCO_SET; /** @hide */ public static final Set<Integer> DEVICE_IN_ALL_USB_SET; + /** @hide */ + public static final Set<Integer> DEVICE_IN_ALL_BLE_SET; + static { DEVICE_IN_ALL_SET = new HashSet<>(); DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION); @@ -1276,6 +1279,66 @@ public class AudioSystem DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY); DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE); DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET); + + DEVICE_IN_ALL_BLE_SET = new HashSet<>(); + DEVICE_IN_ALL_BLE_SET.add(DEVICE_IN_BLE_HEADSET); + } + + /** @hide */ + public static boolean isBluetoothDevice(int deviceType) { + return isBluetoothA2dpOutDevice(deviceType) + || isBluetoothScoDevice(deviceType) + || isBluetoothLeDevice(deviceType); + } + + /** @hide */ + public static boolean isBluetoothOutDevice(int deviceType) { + return isBluetoothA2dpOutDevice(deviceType) + || isBluetoothScoOutDevice(deviceType) + || isBluetoothLeOutDevice(deviceType); + } + + /** @hide */ + public static boolean isBluetoothInDevice(int deviceType) { + return isBluetoothScoInDevice(deviceType) + || isBluetoothLeInDevice(deviceType); + } + + /** @hide */ + public static boolean isBluetoothA2dpOutDevice(int deviceType) { + return DEVICE_OUT_ALL_A2DP_SET.contains(deviceType); + } + + /** @hide */ + public static boolean isBluetoothScoOutDevice(int deviceType) { + return DEVICE_OUT_ALL_SCO_SET.contains(deviceType); + } + + /** @hide */ + public static boolean isBluetoothScoInDevice(int deviceType) { + return DEVICE_IN_ALL_SCO_SET.contains(deviceType); + } + + /** @hide */ + public static boolean isBluetoothScoDevice(int deviceType) { + return isBluetoothScoOutDevice(deviceType) + || isBluetoothScoInDevice(deviceType); + } + + /** @hide */ + public static boolean isBluetoothLeOutDevice(int deviceType) { + return DEVICE_OUT_ALL_BLE_SET.contains(deviceType); + } + + /** @hide */ + public static boolean isBluetoothLeInDevice(int deviceType) { + return DEVICE_IN_ALL_BLE_SET.contains(deviceType); + } + + /** @hide */ + public static boolean isBluetoothLeDevice(int deviceType) { + return isBluetoothLeOutDevice(deviceType) + || isBluetoothLeInDevice(deviceType); } /** @hide */ diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index fe5afc5a717e..7ce189ba85d5 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -231,6 +231,12 @@ interface IAudioService { void setBluetoothScoOn(boolean on); + @EnforcePermission("BLUETOOTH_STACK") + void setA2dpSuspended(boolean on); + + @EnforcePermission("BLUETOOTH_STACK") + void setLeAudioSuspended(boolean enable); + boolean isBluetoothScoOn(); void setBluetoothA2dpOn(boolean on); diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java index 1a3e54d54ee7..afa0a3271906 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java +++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java @@ -391,8 +391,26 @@ public final class SoundTriggerDetector { * @hide */ @Override - public void onError(int status) { - Slog.d(TAG, "onError()" + status); + public void onRecognitionPaused() { + Slog.d(TAG, "onRecognitionPaused()"); + mHandler.sendEmptyMessage(MSG_DETECTION_PAUSE); + } + + /** + * @hide + */ + @Override + public void onRecognitionResumed() { + Slog.d(TAG, "onRecognitionResumed()"); + mHandler.sendEmptyMessage(MSG_DETECTION_RESUME); + } + + /** + * @hide + */ + @Override + public void onPreempted() { + Slog.d(TAG, "onPreempted()"); mHandler.sendEmptyMessage(MSG_DETECTION_ERROR); } @@ -400,18 +418,27 @@ public final class SoundTriggerDetector { * @hide */ @Override - public void onRecognitionPaused() { - Slog.d(TAG, "onRecognitionPaused()"); - mHandler.sendEmptyMessage(MSG_DETECTION_PAUSE); + public void onModuleDied() { + Slog.d(TAG, "onModuleDied()"); + mHandler.sendEmptyMessage(MSG_DETECTION_ERROR); } /** * @hide */ @Override - public void onRecognitionResumed() { - Slog.d(TAG, "onRecognitionResumed()"); - mHandler.sendEmptyMessage(MSG_DETECTION_RESUME); + public void onResumeFailed(int status) { + Slog.d(TAG, "onResumeFailed()" + status); + mHandler.sendEmptyMessage(MSG_DETECTION_ERROR); + } + + /** + * @hide + */ + @Override + public void onPauseFailed(int status) { + Slog.d(TAG, "onPauseFailed()" + status); + mHandler.sendEmptyMessage(MSG_DETECTION_ERROR); } } diff --git a/media/java/android/media/soundtrigger/SoundTriggerInstrumentation.java b/media/java/android/media/soundtrigger/SoundTriggerInstrumentation.java new file mode 100644 index 000000000000..80bc5c07dd66 --- /dev/null +++ b/media/java/android/media/soundtrigger/SoundTriggerInstrumentation.java @@ -0,0 +1,630 @@ +/** + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.soundtrigger; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.TestApi; +import android.hardware.soundtrigger.ConversionUtil; +import android.hardware.soundtrigger.SoundTrigger; +import android.media.soundtrigger_middleware.IAcknowledgeEvent; +import android.media.soundtrigger_middleware.IInjectGlobalEvent; +import android.media.soundtrigger_middleware.IInjectModelEvent; +import android.media.soundtrigger_middleware.IInjectRecognitionEvent; +import android.media.soundtrigger_middleware.ISoundTriggerInjection; +import android.os.IBinder; +import android.os.RemoteException; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.app.ISoundTriggerService; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * Used to inject/observe events when using a fake SoundTrigger HAL for test purposes. + * Created by {@link SoundTriggerManager#getInjection(Executor, GlobalCallback)}. + * Only one instance of this class is valid at any given time, old instances will be delivered + * {@link GlobalCallback#onPreempted()}. + * @hide + */ +@TestApi +public final class SoundTriggerInstrumentation { + + private final Object mLock = new Object(); + @GuardedBy("mLock") + private IInjectGlobalEvent mInjectGlobalEvent = null; + + @GuardedBy("mLock") + private Map<IBinder, ModelSession> mModelSessionMap = new HashMap<>(); + @GuardedBy("mLock") + private Map<IBinder, RecognitionSession> mRecognitionSessionMap = new HashMap<>(); + @GuardedBy("mLock") + private IBinder mClientToken = null; + + private final GlobalCallback mClientCallback; + private final Executor mGlobalCallbackExecutor; + + /** + * Callback interface for un-sessioned events observed from the fake STHAL. + * Registered upon construction of {@link SoundTriggerInstrumentation} + * @hide + */ + @TestApi + public interface GlobalCallback { + /** + * Called when the created {@link SoundTriggerInstrumentation} object is invalidated + * by another client creating an {@link SoundTriggerInstrumentation} to instrument the + * fake STHAL. Only one client may inject at a time. + * All sessions are invalidated, no further events will be received, and no + * injected events will be delivered. + */ + default void onPreempted() {} + /** + * Called when the STHAL has been restarted by the framework, due to unexpected + * error conditions. + * Not called when {@link SoundTriggerInstrumentation#triggerRestart()} is injected. + */ + default void onRestarted() {} + /** + * Called when the framework detaches from the fake HAL. + * This is not transmitted to real HALs, but it indicates that the + * framework has flushed its global state. + */ + default void onFrameworkDetached() {} + /** + * Called when a client application attaches to the framework. + * This is not transmitted to real HALs, but it represents the state of + * the framework. + */ + default void onClientAttached() {} + /** + * Called when a client application detaches from the framework. + * This is not transmitted to real HALs, but it represents the state of + * the framework. + */ + default void onClientDetached() {} + /** + * Called when the fake HAL receives a model load from the framework. + * @param modelSession - A session which exposes additional injection + * functionality associated with the newly loaded + * model. See {@link ModelSession}. + */ + void onModelLoaded(@NonNull ModelSession modelSession); + } + + /** + * Callback for HAL events related to a loaded model. Register with + * {@link ModelSession#setModelCallback(Executor, ModelCallback)} + * Note, callbacks will not be delivered for events triggered by the injection. + * @hide + */ + @TestApi + public interface ModelCallback { + /** + * Called when the model associated with the {@link ModelSession} this callback + * was registered for was unloaded by the framework. + */ + default void onModelUnloaded() {} + /** + * Called when the model associated with the {@link ModelSession} this callback + * was registered for receives a set parameter call from the framework. + * @param param - Parameter being set. + * See {@link SoundTrigger.ModelParamTypes} + * @param value - Value the model parameter was set to. + */ + default void onParamSet(@SoundTrigger.ModelParamTypes int param, int value) {} + /** + * Called when the model associated with the {@link ModelSession} this callback + * was registered for receives a recognition start request. + * @param recognitionSession - A session which exposes additional injection + * functionality associated with the newly started + * recognition. See {@link RecognitionSession} + */ + void onRecognitionStarted(@NonNull RecognitionSession recognitionSession); + } + + /** + * Callback for HAL events related to a started recognition. Register with + * {@link RecognitionSession#setRecognitionCallback(Executor, RecognitionCallback)} + * Note, callbacks will not be delivered for events triggered by the injection. + * @hide + */ + @TestApi + public interface RecognitionCallback { + /** + * Called when the recognition associated with the {@link RecognitionSession} this + * callback was registered for was stopped by the framework. + */ + void onRecognitionStopped(); + } + + /** + * Session associated with a loaded model in the fake STHAL. + * Can be used to query details about the loaded model, register a callback for future + * model events, or trigger HAL events associated with a loaded model. + * This session is invalid once the model is unloaded, caused by a + * {@link ModelSession#triggerUnloadModel()}, + * the client unloading recognition, or if a {@link GlobalCallback#onRestarted()} is + * received. + * Further injections on an invalidated session will not be respected, and no future + * callbacks will be delivered. + * @hide + */ + @TestApi + public class ModelSession { + + /** + * Trigger the HAL to preemptively unload the model associated with this session. + * Typically occurs when a higher priority model is loaded which utilizes the same + * resources. + */ + public void triggerUnloadModel() { + synchronized (SoundTriggerInstrumentation.this.mLock) { + try { + mInjectModelEvent.triggerUnloadModel(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mModelSessionMap.remove(mInjectModelEvent.asBinder()); + } + } + + /** + * Get the {@link SoundTriggerManager.Model} associated with this session. + * @return - The model associated with this session. + */ + public @NonNull SoundTriggerManager.Model getSoundModel() { + return mModel; + } + + /** + * Get the list of {@link SoundTrigger.Keyphrase} associated with this session. + * @return - The keyphrases associated with this session. + */ + public @NonNull List<SoundTrigger.Keyphrase> getPhrases() { + if (mPhrases == null) { + return new ArrayList<>(); + } else { + return new ArrayList<>(Arrays.asList(mPhrases)); + } + } + + /** + * Get whether this model is of keyphrase type. + * @return - true if the model is a keyphrase model, false otherwise + */ + public boolean isKeyphrase() { + return (mPhrases != null); + } + + /** + * Registers the model callback associated with this session. Events associated + * with this model session will be reported via this callback. + * See {@link ModelCallback} + * @param executor - Executor which the callback is dispatched on + * @param callback - Model callback for reporting model session events. + */ + public void setModelCallback(@NonNull @CallbackExecutor Executor executor, @NonNull + ModelCallback callback) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + mModelCallback = Objects.requireNonNull(callback); + mModelExecutor = Objects.requireNonNull(executor); + } + } + + /** + * Clear the model callback associated with this session, if any has been + * set by {@link #setModelCallback(Executor, ModelCallback)}. + */ + public void clearModelCallback() { + synchronized (SoundTriggerInstrumentation.this.mLock) { + mModelCallback = null; + mModelExecutor = null; + } + } + + private ModelSession(SoundModel model, Phrase[] phrases, + IInjectModelEvent injection) { + mModel = SoundTriggerManager.Model.create(UUID.fromString(model.uuid), + UUID.fromString(model.vendorUuid), + ConversionUtil.sharedMemoryToByteArray(model.data, model.dataSize)); + if (phrases != null) { + mPhrases = new SoundTrigger.Keyphrase[phrases.length]; + int i = 0; + for (var phrase : phrases) { + mPhrases[i++] = ConversionUtil.aidl2apiPhrase(phrase); + } + } else { + mPhrases = null; + } + mInjectModelEvent = injection; + } + + private void wrap(Consumer<ModelCallback> consumer) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + if (mModelCallback != null && mModelExecutor != null) { + final ModelCallback callback = mModelCallback; + mModelExecutor.execute(() -> consumer.accept(callback)); + } + } + } + + private final SoundTriggerManager.Model mModel; + private final SoundTrigger.Keyphrase[] mPhrases; + private final IInjectModelEvent mInjectModelEvent; + + @GuardedBy("SoundTriggerInstrumentation.this.mLock") + private ModelCallback mModelCallback = null; + @GuardedBy("SoundTriggerInstrumentation.this.mLock") + private Executor mModelExecutor = null; + } + + /** + * Session associated with a recognition start in the fake STHAL. + * Can be used to get information about the started recognition, register a callback + * for future events associated with this recognition, and triggering + * recognition events or aborts. + * This session is invalid once the recognition is stopped, caused by a + * {@link RecognitionSession#triggerAbortRecognition()}, + * {@link RecognitionSession#triggerRecognitionEvent(byte[], List)}, + * the client stopping recognition, or any operation which invalidates the + * {@link ModelSession} which the session was created from. + * Further injections on an invalidated session will not be respected, and no future + * callbacks will be delivered. + * @hide + */ + @TestApi + public class RecognitionSession { + + /** + * Get an integer token representing the audio session associated with this + * recognition in the STHAL. + * @return - The session token. + */ + public int getAudioSession() { + return mAudioSession; + } + + /** + * Get the recognition config used to start this recognition. + * @return - The config passed to the HAL for startRecognition. + */ + public @NonNull SoundTrigger.RecognitionConfig getRecognitionConfig() { + return mRecognitionConfig; + } + + /** + * Trigger a recognition in the fake STHAL. + * @param data - The opaque data buffer included in the recognition event. + * @param phraseExtras - Keyphrase metadata included in the event. The + * event must include metadata for the keyphrase id + * associated with this model to be received by the + * client application. + */ + public void triggerRecognitionEvent(@NonNull byte[] data, @Nullable + List<SoundTrigger.KeyphraseRecognitionExtra> phraseExtras) { + PhraseRecognitionExtra[] converted = null; + if (phraseExtras != null) { + converted = new PhraseRecognitionExtra[phraseExtras.size()]; + int i = 0; + for (var phraseExtra : phraseExtras) { + converted[i++] = ConversionUtil.api2aidlPhraseRecognitionExtra(phraseExtra); + } + } + synchronized (SoundTriggerInstrumentation.this.mLock) { + mRecognitionSessionMap.remove(mInjectRecognitionEvent.asBinder()); + try { + mInjectRecognitionEvent.triggerRecognitionEvent(data, converted); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Trigger an abort recognition event in the fake HAL. This represents a + * preemptive ending of the recognition session by the HAL, despite no + * recognition detection. Typically occurs during contention for microphone + * usage, or if model limits are hit. + * See {@link SoundTriggerInstrumentation#setResourceContention(boolean)} to block + * subsequent downward calls for contention reasons. + */ + public void triggerAbortRecognition() { + synchronized (SoundTriggerInstrumentation.this.mLock) { + mRecognitionSessionMap.remove(mInjectRecognitionEvent.asBinder()); + try { + mInjectRecognitionEvent.triggerAbortRecognition(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Registers the recognition callback associated with this session. Events associated + * with this recognition session will be reported via this callback. + * See {@link RecognitionCallback} + * @param executor - Executor which the callback is dispatched on + * @param callback - Recognition callback for reporting recognition session events. + */ + public void setRecognitionCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull RecognitionCallback callback) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + mRecognitionCallback = callback; + mRecognitionExecutor = executor; + } + } + + /** + * Clear the recognition callback associated with this session, if any has been + * set by {@link #setRecognitionCallback(Executor, RecognitionCallback)}. + */ + public void clearRecognitionCallback() { + synchronized (SoundTriggerInstrumentation.this.mLock) { + mRecognitionCallback = null; + mRecognitionExecutor = null; + } + } + + private RecognitionSession(int audioSession, + RecognitionConfig recognitionConfig, + IInjectRecognitionEvent injectRecognitionEvent) { + mAudioSession = audioSession; + mRecognitionConfig = ConversionUtil.aidl2apiRecognitionConfig(recognitionConfig); + mInjectRecognitionEvent = injectRecognitionEvent; + } + + private void wrap(Consumer<RecognitionCallback> consumer) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + if (mRecognitionCallback != null && mRecognitionExecutor != null) { + final RecognitionCallback callback = mRecognitionCallback; + mRecognitionExecutor.execute(() -> consumer.accept(callback)); + } + } + } + + private final int mAudioSession; + private final SoundTrigger.RecognitionConfig mRecognitionConfig; + private final IInjectRecognitionEvent mInjectRecognitionEvent; + + @GuardedBy("SoundTriggerInstrumentation.this.mLock") + private Executor mRecognitionExecutor = null; + @GuardedBy("SoundTriggerInstrumentation.this.mLock") + private RecognitionCallback mRecognitionCallback = null; + } + + // Implementation of injection interface passed to the HAL. + // This class will re-associate events received on this callback interface + // with sessions, to avoid staleness issues. + private class Injection extends ISoundTriggerInjection.Stub { + @Override + public void registerGlobalEventInjection(IInjectGlobalEvent globalInjection) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + mInjectGlobalEvent = globalInjection; + } + } + + @Override + public void onSoundModelLoaded(SoundModel model, @Nullable Phrase[] phrases, + IInjectModelEvent modelInjection, IInjectGlobalEvent globalSession) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + if (globalSession.asBinder() != mInjectGlobalEvent.asBinder()) return; + ModelSession modelSession = new ModelSession(model, phrases, modelInjection); + mModelSessionMap.put(modelInjection.asBinder(), modelSession); + mGlobalCallbackExecutor.execute(() -> mClientCallback.onModelLoaded(modelSession)); + } + } + + @Override + public void onSoundModelUnloaded(IInjectModelEvent modelSession) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + ModelSession clientModelSession = mModelSessionMap.remove(modelSession.asBinder()); + if (clientModelSession == null) return; + clientModelSession.wrap((ModelCallback cb) -> cb.onModelUnloaded()); + } + } + + @Override + public void onRecognitionStarted(int audioSessionHandle, RecognitionConfig config, + IInjectRecognitionEvent recognitionInjection, IInjectModelEvent modelSession) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + ModelSession clientModelSession = mModelSessionMap.get(modelSession.asBinder()); + if (clientModelSession == null) return; + RecognitionSession recogSession = new RecognitionSession( + audioSessionHandle, config, recognitionInjection); + mRecognitionSessionMap.put(recognitionInjection.asBinder(), recogSession); + clientModelSession.wrap((ModelCallback cb) -> + cb.onRecognitionStarted(recogSession)); + } + } + + @Override + public void onRecognitionStopped(IInjectRecognitionEvent recognitionSession) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + RecognitionSession clientRecognitionSession = + mRecognitionSessionMap.remove(recognitionSession.asBinder()); + if (clientRecognitionSession == null) return; + clientRecognitionSession.wrap((RecognitionCallback cb) + -> cb.onRecognitionStopped()); + } + } + + @Override + public void onParamSet(int modelParam, int value, IInjectModelEvent modelSession) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + ModelSession clientModelSession = mModelSessionMap.get(modelSession.asBinder()); + if (clientModelSession == null) return; + clientModelSession.wrap((ModelCallback cb) -> cb.onParamSet(modelParam, value)); + } + } + + + @Override + public void onRestarted(IInjectGlobalEvent globalSession) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + if (globalSession.asBinder() != mInjectGlobalEvent.asBinder()) return; + mRecognitionSessionMap.clear(); + mModelSessionMap.clear(); + mGlobalCallbackExecutor.execute(() -> mClientCallback.onRestarted()); + } + } + + @Override + public void onFrameworkDetached(IInjectGlobalEvent globalSession) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + if (globalSession.asBinder() != mInjectGlobalEvent.asBinder()) return; + mGlobalCallbackExecutor.execute(() -> mClientCallback.onFrameworkDetached()); + } + } + + @Override + public void onClientAttached(IBinder token, IInjectGlobalEvent globalSession) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + if (globalSession.asBinder() != mInjectGlobalEvent.asBinder()) return; + mClientToken = token; + mGlobalCallbackExecutor.execute(() -> mClientCallback.onClientAttached()); + } + } + + @Override + public void onClientDetached(IBinder token) { + synchronized (SoundTriggerInstrumentation.this.mLock) { + if (token != mClientToken) return; + mClientToken = null; + mGlobalCallbackExecutor.execute(() -> mClientCallback.onClientDetached()); + } + } + + @Override + public void onPreempted() { + // This is always valid, independent of session + mGlobalCallbackExecutor.execute(() -> mClientCallback.onPreempted()); + // Callbacks will no longer be delivered, and injection will be silently dropped. + } + } + + /** + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) + public SoundTriggerInstrumentation(ISoundTriggerService service, + @CallbackExecutor @NonNull Executor executor, + @NonNull GlobalCallback callback) { + mClientCallback = Objects.requireNonNull(callback); + mGlobalCallbackExecutor = Objects.requireNonNull(executor); + try { + service.attachInjection(new Injection()); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Simulate a HAL restart, typically caused by the framework on an unexpected error, + * or a restart of the core audio HAL. + * Application sessions will be detached, and all state will be cleared. The framework + * will re-attach to the HAL following restart. + * @hide + */ + @TestApi + public void triggerRestart() { + synchronized (mLock) { + if (mInjectGlobalEvent == null) { + throw new IllegalStateException( + "Attempted to trigger HAL restart before registration"); + } + try { + mInjectGlobalEvent.triggerRestart(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Trigger a resource available callback from the fake SoundTrigger HAL to the framework. + * This callback notifies the framework that methods which previously failed due to + * resource contention may now succeed. + * @hide + */ + @TestApi + public void triggerOnResourcesAvailable() { + synchronized (mLock) { + if (mInjectGlobalEvent == null) { + throw new IllegalStateException( + "Attempted to trigger HAL resources available before registration"); + } + try { + mInjectGlobalEvent.triggerOnResourcesAvailable(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Simulate resource contention, similar to when HAL which does not + * support concurrent capture opens a capture stream, or when a HAL + * has reached its maximum number of models. + * Subsequent model loads and recognition starts will gracefully error. + * Since this call does not trigger a callback through the framework, the + * call will block until the fake HAL has acknowledged the state change. + * @param isResourceContended - true to enable contention, false to return + * to normal functioning. + * @hide + */ + @TestApi + public void setResourceContention(boolean isResourceContended) { + synchronized (mLock) { + if (mInjectGlobalEvent == null) { + throw new IllegalStateException("Injection interface not set up"); + } + IInjectGlobalEvent current = mInjectGlobalEvent; + final CountDownLatch signal = new CountDownLatch(1); + try { + current.setResourceContention(isResourceContended, new IAcknowledgeEvent.Stub() { + @Override + public void eventReceived() { + signal.countDown(); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + // Block until we get a callback from the service that our request was serviced. + try { + // Rely on test timeout if we don't get a response. + signal.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } +} + diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java index ae8121a59abf..c41bd1bc3094 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerManager.java +++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java @@ -18,11 +18,13 @@ package android.media.soundtrigger; import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -45,6 +47,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; +import android.os.ServiceManager; import android.provider.Settings; import android.util.Slog; @@ -53,9 +56,9 @@ import com.android.internal.app.ISoundTriggerSession; import com.android.internal.util.Preconditions; import java.util.HashMap; -import java.util.List; import java.util.Objects; import java.util.UUID; +import java.util.concurrent.Executor; /** * This class provides management of non-voice (general sound trigger) based sound recognition @@ -609,4 +612,24 @@ public final class SoundTriggerManager { throw e.rethrowFromSystemServer(); } } + + /** + * Create a {@link SoundTriggerInstrumentation} for test purposes, which instruments a fake + * STHAL. Clients must attach to the appropriate underlying ST module. + * @param executor - Executor to dispatch global callbacks on + * @param callback - Callback for unsessioned events received by the fake STHAL + * @return - A {@link SoundTriggerInstrumentation} for observation/injection. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) + @NonNull + public static SoundTriggerInstrumentation attachInstrumentation( + @CallbackExecutor @NonNull Executor executor, + @NonNull SoundTriggerInstrumentation.GlobalCallback callback) { + ISoundTriggerService service = ISoundTriggerService.Stub.asInterface( + ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE)); + return new SoundTriggerInstrumentation(service, executor, callback); + } + } diff --git a/media/java/android/media/voice/KeyphraseModelManager.java b/media/java/android/media/voice/KeyphraseModelManager.java index 8ec8967a353e..5a690a57dbb2 100644 --- a/media/java/android/media/voice/KeyphraseModelManager.java +++ b/media/java/android/media/voice/KeyphraseModelManager.java @@ -21,7 +21,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.hardware.soundtrigger.SoundTrigger; +import android.os.Binder; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.Slog; @@ -154,4 +156,23 @@ public final class KeyphraseModelManager { throw e.rethrowFromSystemServer(); } } + + /** + * Override the persistent enrolled model database with an in-memory + * fake for testing purposes. + * + * @param enabled - {@code true} if the model enrollment database should be overridden with an + * in-memory fake. {@code false} if the real, persistent model enrollment database should be + * used. + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) + @TestApi + public void setModelDatabaseForTestEnabled(boolean enabled) { + try { + mVoiceInteractionManagerService.setModelDatabaseForTestEnabled(enabled, new Binder()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/media/jni/android_media_MediaCodecLinearBlock.h b/media/jni/android_media_MediaCodecLinearBlock.h index c7530207d1fa..060abfdc1ee5 100644 --- a/media/jni/android_media_MediaCodecLinearBlock.h +++ b/media/jni/android_media_MediaCodecLinearBlock.h @@ -44,12 +44,19 @@ struct JMediaCodecLinearBlock { std::shared_ptr<C2Buffer> toC2Buffer(size_t offset, size_t size) const { if (mBuffer) { + // TODO: if returned C2Buffer is different from mBuffer, we should + // find a way to connect the life cycle between this C2Buffer and + // mBuffer. if (mBuffer->data().type() != C2BufferData::LINEAR) { return nullptr; } C2ConstLinearBlock block = mBuffer->data().linearBlocks().front(); if (offset == 0 && size == block.capacity()) { - return mBuffer; + // Let C2Buffer be new one to queue to MediaCodec. It will allow + // the related input slot to be released by onWorkDone from C2 + // Component. Currently, the life cycle of mBuffer should be + // protected by different flows. + return std::make_shared<C2Buffer>(*mBuffer); } std::shared_ptr<C2Buffer> buffer = diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index 116237f6b998..609c7a40bb36 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -196,6 +196,15 @@ status_t JMediaExtractor::readSampleData( dstSize = (size_t) env->GetDirectBufferCapacity(byteBuf); } + // unlikely, but GetByteArrayElements() can fail + if (dst == nullptr) { + ALOGE("no buffer into which to read the data"); + if (byteArray != NULL) { + env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); + } + return -ENOMEM; + } + if (dstSize < offset) { if (byteArray != NULL) { env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); @@ -204,8 +213,10 @@ status_t JMediaExtractor::readSampleData( return -ERANGE; } + // passes in the backing memory to use, so it doesn't fail sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset); + buffer->setRange(0, 0); // mark it empty status_t err = mImpl->readSampleData(buffer); if (byteArray != NULL) { diff --git a/native/android/input.cpp b/native/android/input.cpp index 432e21cb5c08..1bff97dfdada 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -33,6 +33,7 @@ #include <errno.h> using android::InputEvent; +using android::InputEventType; using android::InputQueue; using android::KeyEvent; using android::Looper; @@ -41,7 +42,8 @@ using android::sp; using android::Vector; int32_t AInputEvent_getType(const AInputEvent* event) { - return static_cast<const InputEvent*>(event)->getType(); + const InputEventType eventType = static_cast<const InputEvent*>(event)->getType(); + return static_cast<int32_t>(eventType); } int32_t AInputEvent_getDeviceId(const AInputEvent* event) { diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml index 61d8dc8712ff..4fad22414225 100644 --- a/packages/CarrierDefaultApp/res/values-bs/strings.xml +++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"Komunikacije putem operatera"</string> + <string name="app_name" msgid="2809080280462257271">"Obavještenja operatera"</string> <string name="android_system_label" msgid="2797790869522345065">"Mobilni operater"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Mobilni internet je potrošen"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Prijenos podataka na mobilnoj mreži je deaktiviran"</string> diff --git a/packages/CarrierDefaultApp/res/values-eu/strings.xml b/packages/CarrierDefaultApp/res/values-eu/strings.xml index 86e12915a23c..90346b33d90d 100644 --- a/packages/CarrierDefaultApp/res/values-eu/strings.xml +++ b/packages/CarrierDefaultApp/res/values-eu/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"Operadorearekiko komunikazioa"</string> + <string name="app_name" msgid="2809080280462257271">"Operadorearen jakinarazpenak"</string> <string name="android_system_label" msgid="2797790869522345065">"Telefonia mugikorreko operadorea"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Agortu egin da datu-konexioa"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Desaktibatu da datu-konexioa"</string> diff --git a/packages/CarrierDefaultApp/res/values-fa/strings.xml b/packages/CarrierDefaultApp/res/values-fa/strings.xml index 89c184cf2e73..abf47fbfe2cd 100644 --- a/packages/CarrierDefaultApp/res/values-fa/strings.xml +++ b/packages/CarrierDefaultApp/res/values-fa/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"ارتباطات شرکت مخابراتی"</string> + <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> diff --git a/packages/CarrierDefaultApp/res/values-km/strings.xml b/packages/CarrierDefaultApp/res/values-km/strings.xml index 18524899af1f..ee9a6ac7f994 100644 --- a/packages/CarrierDefaultApp/res/values-km/strings.xml +++ b/packages/CarrierDefaultApp/res/values-km/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"ទំនាក់ទំនងរបស់ក្រុមហ៊ុនសេវាទូរសព្ទ"</string> + <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> diff --git a/packages/CarrierDefaultApp/res/values-ro/strings.xml b/packages/CarrierDefaultApp/res/values-ro/strings.xml index 78b910e074f3..9692a7f60dcc 100644 --- a/packages/CarrierDefaultApp/res/values-ro/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ro/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"Comunicări de la operator"</string> + <string name="app_name" msgid="2809080280462257271">"Notificări de la operator"</string> <string name="android_system_label" msgid="2797790869522345065">"Operator de telefonie mobilă"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Datele mobile au expirat"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Datele mobile au fost dezactivate"</string> diff --git a/packages/CarrierDefaultApp/res/values-ru/strings.xml b/packages/CarrierDefaultApp/res/values-ru/strings.xml index 936a6faa5fc0..a3c9f19245ef 100644 --- a/packages/CarrierDefaultApp/res/values-ru/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ru/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"Оператор связи"</string> + <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> diff --git a/packages/CarrierDefaultApp/res/values-vi/strings.xml b/packages/CarrierDefaultApp/res/values-vi/strings.xml index d99aa22ad002..402d4251a7c6 100644 --- a/packages/CarrierDefaultApp/res/values-vi/strings.xml +++ b/packages/CarrierDefaultApp/res/values-vi/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"Nhà cung cấp dịch vụ truyền thông"</string> + <string name="app_name" msgid="2809080280462257271">"Thông báo của nhà mạng"</string> <string name="android_system_label" msgid="2797790869522345065">"Nhà cung cấp dịch vụ di động"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Dữ liệu di động đã hết"</string> <string name="no_data_notification_id" msgid="668400731803969521">"Dữ liệu di động của bạn đã bị hủy kích hoạt"</string> diff --git a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml index b05835deaf65..63cae2fc72b2 100644 --- a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml +++ b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"运营商通信"</string> + <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> diff --git a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml index e8a679c11e91..0578256d52f9 100644 --- a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml +++ b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml @@ -1,7 +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"> - <string name="app_name" msgid="2809080280462257271">"流動網絡供應商最新消息"</string> + <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> diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml index b897f7fe3474..181e8ee219ee 100644 --- a/packages/CompanionDeviceManager/res/values-af/strings.xml +++ b/packages/CompanionDeviceManager/res/values-af/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Metgeseltoestel-bestuurder"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string> <string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> bestuur te word"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Hierdie app is nodig om jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="APP_NAME">%2$s</xliff:g> sal toegelaat word om inligting te sinkroniseer, soos die naam van iemand wat bel, interaksie met jou kennisgewings te hê, en sal toegang tot jou Foon-, SMS-, Kontakte-, Kalender-, Oproeprekords-, en Toestelle in die Omtrek-toestemmings hê."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Laat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toe om <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> te bestuur?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"bril"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Hierdie app is nodig om <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="APP_NAME">%2$s</xliff:g> sal toegelaat word om interaksie met jou kennisgewings te hê en sal toegang tot jou Foon-, SMS-, Kontakte-, Mikrofoon-, en Toestelle in die Omtrek-toestemmings hê."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot hierdie inligting op jou foon"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Oorkruistoestel-dienste"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toestemming om programme tussen jou toestelle te stroom"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot hierdie inligting op jou foon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Dienste"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toegang tot jou foon se foto\'s, media en kennisgewings"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Laat <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> toe om hierdie handeling uit te voer?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en ander stelselkenmerke na toestelle in die omtrek te stroom"</string> <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Hierdie app sal inligting kan sinkroniseer, soos die naam van iemand wat bel, tussen jou foon en <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Hierdie app sal inligting kan sinkroniseer, soos die naam van iemand wat bel, tussen jou foon en die gekose toestel"</string> <string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string> <string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string> <string name="consent_back" msgid="2560683030046918882">"Terug"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stroom jou foon se apps"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Stroom apps en ander stelselkenmerke van jou foon af"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"foon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml index 23a6cb0f42db..9b66027694c7 100644 --- a/packages/CompanionDeviceManager/res/values-am/strings.xml +++ b/packages/CompanionDeviceManager/res/values-am/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"አጃቢ የመሣሪያ አስተዳዳሪ"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ን እንዲደርስ ይፈቀድለት?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string> <string name="chooser_title" msgid="2262294130493605839">"በ<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"የእርስዎን <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ለማስተዳደር ይህ መተግበሪያ ያስፈልጋል። <xliff:g id="APP_NAME">%2$s</xliff:g> እንደ የሚደውል ሰው ስም፣ ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ ዕውቅያዎች፣ የቀን መቁጠሪያ፣ የጥሪ ምዝግብ ማስታወሻዎች እና በአቅራቢያ ያሉ መሣሪያዎችን መድረስ ያሉ መረጃዎችን እንዲያሰምር ይፈቀድለታል።"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ን እንዲያስተዳድር ይፈቅዳሉ?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"መነጽሮች"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"ይህ መተግበሪያ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ን ለማስተዳደር ያስፈልጋል። <xliff:g id="APP_NAME">%2$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ ዕውቂያዎች፣ ማይክሮፎን እና በአቅራቢያ ያሉ መሣሪያዎች ፈቃዶችን እንዲደርስ ይፈቀድለታል።"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ይህን መረጃ ከስልክዎ እንዲደርስበት ይፍቀዱለት"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"መሣሪያ ተሻጋሪ አገልግሎቶች"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> በእርስዎ መሣሪያዎች መካከል መተግበሪያዎችን በዥረት ለመልቀቅ የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ወክሎ ፈቃድ እየጠየቀ ነው"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ይህን መረጃ ከስልክዎ ላይ እንዲደርስ ይፍቀዱለት"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"የGoogle Play አገልግሎቶች"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> የስልክዎን ፎቶዎች፣ ሚዲያ እና ማሳወቂያዎች ለመድረስ የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ወክሎ ፈቃድ እየጠየቀ ነው"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ይህን እርምጃ እንዲወስድ ፈቃድ ይሰጠው?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> በመወከል በአቅራቢያ ላሉ መሣሪያዎች መተግበሪያዎች እና ሌሎች የስርዓት ባህሪያትን በዥረት ለመልቀቅ ፈቃድ እየጠየቀ ነው"</string> <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን በስልክዎ እና <xliff:g id="DEVICE_NAME">%1$s</xliff:g> መካከል ማስመር ይችላል"</string> + <string name="summary_generic" msgid="1761976003668044801">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን በስልክዎ እና በተመረጠው መሣሪያ መካከል ማስመር ይችላል"</string> <string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string> <string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string> <string name="consent_back" msgid="2560683030046918882">"ተመለስ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"የስልክዎን መተግበሪያዎች በዥረት ይልቀቁ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"ከስልክዎ ሆነው መተግበሪያዎች እና ሌሎች የስርዓት ባህሪያትን በዥረት ይልቀቁ"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ስልክ"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ጡባዊ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml index 728767e0c0d1..4c46af0c71cb 100644 --- a/packages/CompanionDeviceManager/res/values-ar/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml @@ -17,28 +17,29 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"تطبيق \"مدير الجهاز المصاحب\""</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"هل تريد السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>؟"</string> <string name="profile_name_watch" msgid="576290739483672360">"الساعة"</string> <string name="chooser_title" msgid="2262294130493605839">"اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديرها تطبيق <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <!-- no translation found for summary_watch (898569637110705523) --> <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بإدارة <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"النظارة"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"يجب توفّر هذا التطبيق لإدارة \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". سيتم السماح لتطبيق \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والميكروفون والأجهزة المجاورة."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى هذه المعلومات من هاتفك"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"الخدمات التي تعمل بين الأجهزة"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"يطلب تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> الحصول على إذن نيابةً عن <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> لمشاركة التطبيقات بين أجهزتك."</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى هذه المعلومات من هاتفك"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"خدمات Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"يطلب تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> الحصول على إذن نيابةً عن <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> للوصول إلى الصور والوسائط والإشعارات في هاتفك."</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"هل تريد السماح للتطبيق <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> باتّخاذ هذا الإجراء؟"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" لبثّ التطبيقات وميزات النظام الأخرى إلى أجهزتك المجاورة."</string> <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string> @@ -75,8 +76,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"بث تطبيقات هاتفك"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"بثّ التطبيقات وميزات النظام الأخرى من هاتفك"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"هاتف"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"جهاز لوحي"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml index b651bda75beb..091864efc68c 100644 --- a/packages/CompanionDeviceManager/res/values-as/strings.xml +++ b/packages/CompanionDeviceManager/res/values-as/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"কম্পেনিয়ন ডিভাইচ মেনেজাৰ"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> এক্সেছ কৰিবলৈ দিবনে?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এই এপ্টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক কল কৰোঁতাৰ নামৰ দৰে তথ্য ছিংক কৰিবলৈ, আপোনাৰ জাননীৰ সৈতে ভাব-বিনিময় কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক, কেলেণ্ডাৰ, কল লগ আৰু নিকটৱৰ্তী ডিভাইচৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> পৰিচালনা কৰিবলৈ দিবনে?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"চছ্মা"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এই এপ্টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক আপোনাৰ অনুমতিসমূহৰ সৈতে ভাব-বিনিময় কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক, মাইক্ৰ’ফ’ন আৰু নিকটৱৰ্তী ডিভাইচৰ অনুমতিসমূহ এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্ৰছ-ডিভাইচ সেৱাসমূহ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ হৈ আপোনাৰ ডিভাইচসমূহৰ মাজত এপ্ ষ্ট্ৰীম কৰাৰ বাবে অনুৰোধ জনাইছে"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play সেৱা"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ হৈ আপোনাৰ ফ’নৰ ফট’, মিডিয়া আৰু জাননী এক্সেছ কৰাৰ বাবে অনুৰোধ জনাইছে"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ক এই কাৰ্যটো সম্পাদন কৰিবলৈ দিবনে?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ নিকটৱৰ্তী ডিভাইচত এপ্ আৰু ছিষ্টেমৰ অন্য সুবিধাসমূহ ষ্ট্ৰীম কৰাৰ অনুমতি দিবলৈ অনুৰোধ জনাইছে"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"এই এপ্টোৱে আপোনাৰ ফ’ন আৰু বাছনি কৰা <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ মাজত কল কৰোঁতাৰ নামৰ দৰে তথ্য ছিংক কৰিব পাৰিব"</string> + <string name="summary_generic" msgid="1761976003668044801">"এই এপ্টোৱে আপোনাৰ ফ’ন আৰু বাছনি কৰা ডিভাইচটোৰ মাজত কল কৰোঁতাৰ নামৰ দৰে তথ্য ছিংক কৰিব পাৰিব"</string> <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string> <string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string> <string name="consent_back" msgid="2560683030046918882">"উভতি যাওক"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"আপোনাৰ ফ’নৰ এপ্ ষ্ট্ৰীম কৰক"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"আপোনাৰ ফ’নৰ পৰা এপ্ আৰু ছিষ্টেমৰ অন্য সুবিধাসমূহ ষ্ট্ৰীম কৰক"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ফ’ন"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"টেবলেট"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml index 1052c9e0102a..9f28a5a81794 100644 --- a/packages/CompanionDeviceManager/res/values-az/strings.xml +++ b/packages/CompanionDeviceManager/res/values-az/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Kompanyon Cihaz Meneceri"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazına daxil olmaq icazəsi verilsin?"</string> <string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazını idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> zəng edənin adı kimi məlumatları sinxronlaşdıracaq, bildirişlərə giriş edəcək, habelə Telefon, SMS, Kontaktlar, Təqvim, Zəng qeydləri və Yaxınlıqdakı cihazlar üzrə icazələrə daxil olacaq."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazını idarə etmək icazəsi verilsin?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"eynək"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Bu tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazını idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> bildirişlərə, Telefon, SMS, Kontaktlar, Mikrofon və Yaxınlıqdakı cihazlar icazələrinə giriş əldə edəcək."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmətlər"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> adından cihazlarınız arasında tətbiqləri yayımlamaq üçün icazə istəyir"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xidmətləri"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> adından telefonunuzun fotoları, mediası və bildirişlərinə giriş üçün icazə istəyir"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> cihazına bu əməliyyatı yerinə yetirmək icazəsi verilsin?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından tətbiq və digər sistem funksiyalarını yaxınlıqdakı cihazlara yayımlamaq icazəsi sitəyir"</string> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Tətbiq zəng edənin adı kimi məlumatları telefon ilə <xliff:g id="DEVICE_NAME">%1$s</xliff:g> arasında sinxronlaşdıracaq"</string> + <string name="summary_generic" msgid="1761976003668044801">"Tətbiq zəng edənin adı kimi məlumatları telefon ilə seçilmiş cihaz arasında sinxronlaşdıracaq"</string> <string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string> <string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string> <string name="consent_back" msgid="2560683030046918882">"Geriyə"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefonunuzun tətbiqlərini yayımlayın"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Telefondan tətbiq və digər sistem funksiyalarını yayımlayın"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefonda"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"planşetdə"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml index 2569a83090c3..c612a1b9f0db 100644 --- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Menadžer pridruženog uređaja"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_watch" msgid="576290739483672360">"sat"</string> <string name="chooser_title" msgid="2262294130493605839">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> će dobiti dozvolu za sinhronizovanje informacija, poput osobe koja upućuje poziv, za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS, kontakte, kalendar, evidencije poziva i uređaje u blizini."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite li da dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"naočare"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS, kontakte, mikrofon i uređaje u blizini."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za strimovanje aplikacija između uređaja"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za pristup slikama, medijskom sadržaju i obaveštenjima sa telefona"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Želite li da dozvolite da <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> obavi ovu radnju?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da strimuje aplikacije i druge sistemske funkcije na uređaje u blizini"</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ova aplikacija će moći da sinhronizuje podatke, poput imena osobe koja upućuje poziv, između telefona i uređaja <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija će moći da sinhronizuje podatke, poput imena osobe koja upućuje poziv, između telefona i odabranog uređaja"</string> <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string> <string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string> <string name="consent_back" msgid="2560683030046918882">"Nazad"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Strimujte aplikacije na telefonu"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Strimujte aplikacije i druge sistemske funkcije sa telefona"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefonu"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tabletu"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml index 5cee5c37775d..ea62cd5f417a 100644 --- a/packages/CompanionDeviceManager/res/values-be/strings.xml +++ b/packages/CompanionDeviceManager/res/values-be/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Менеджар спадарожнай прылады"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ да прылады <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string> <string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Гэта праграма неабходная для кіравання прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць), узаемадзейнічаць з вашымі апавяшчэннямі, а таксама атрымае доступ да тэлефона, SMS, кантактаў, календара, журналаў выклікаў і прылад паблізу."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кіраваць прыладай <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"акуляры"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Гэта праграма неабходная для кіравання прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> зможа ўзаемадзейнічаць з вашымі апавяшчэннямі і атрымае доступ да тэлефона, SMS, кантактаў, мікрафона і прылад паблізу."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> мець доступ да гэтай інфармацыі з вашага тэлефона"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сэрвісы для некалькіх прылад"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на трансляцыю праграм паміж вашымі прыладамі"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> мець доступ да гэтай інфармацыі з вашага тэлефона"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Сэрвісы Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на доступ да фота, медыяфайлаў і апавяшчэнняў на вашым тэлефоне"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Дазволіць прыладзе <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> выканаць гэта дзеянне?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на перадачу плынню змесціва праграм і іншых функцый сістэмы на прылады паблізу"</string> <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) паміж тэлефонам і прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\""</string> + <string name="summary_generic" msgid="1761976003668044801">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) паміж тэлефонам і выбранай прыладай"</string> <string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string> <string name="consent_no" msgid="2640796915611404382">"Не дазваляць"</string> <string name="consent_back" msgid="2560683030046918882">"Назад"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Трансляцыя змесціва праграм з вашага тэлефона"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Перадача плынню змесціва праграм і іншых функцый сістэмы з вашага тэлефона"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"тэлефон"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"планшэт"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml index 34a88ed2e0c6..0dbfb7782c51 100644 --- a/packages/CompanionDeviceManager/res/values-bg/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Да се разреши ли на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до устройството <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string> <string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Това приложение е необходимо за управление на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ще получи право да синхронизира различна информация, като например името на обаждащия се, да взаимодейства с известията ви и достъп до разрешенията за телефона, SMS съобщенията, контактите, календара, списъците с обажданията и устройствата в близост."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Разрешавате ли на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управлява устройството <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"очилата"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Това приложение е необходимо за управление на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Приложението <xliff:g id="APP_NAME">%2$s</xliff:g> ще получи право да взаимодейства с известията ви, както и достъп до разрешенията за телефона, SMS съобщенията, контактите, микрофона и устройствата в близост."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до тази информация от телефона ви"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ иска разрешение от името на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> да предава поточно приложения между устройствата ви"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до тази информация от телефона ви"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Услуги за Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за достъп до снимките, мултимедията и известията на телефона ви"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Разрешавате ли на <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> да предприема това действие?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да предава поточно приложения и други системни функции към устройства в близост"</string> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Това приложение ще може да синхронизира различна информация, като например името на обаждащия се, между телефона ви и <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Това приложение ще може да синхронизира различна информация, като например името на обаждащия се, между телефона ви и избраното устройство"</string> <string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string> <string name="consent_no" msgid="2640796915611404382">"Забраняване"</string> <string name="consent_back" msgid="2560683030046918882">"Назад"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Поточно предаване на приложенията на телефона ви"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Поточно предаване на приложения и други системни функции от телефона ви"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"телефон"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"таблет"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml index 0fc220b94da3..a4e5a3a6afd8 100644 --- a/packages/CompanionDeviceManager/res/values-bn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> অ্যাপকে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> অ্যাক্সেস করার অনুমতি দেবেন?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string> <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ম্যানেজ করবে"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"আপনার <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ম্যানেজ করতে এই অ্যাপটি প্রয়োজন। <xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপকে কলারের নাম ও আপনার বিজ্ঞপ্তির সাথে ইন্টার্যাক্ট করা সংক্রান্ত তথ্য সিঙ্কের অনুমতি দেওয়া হবে এবং আপনার ফোন, এসএমএস, পরিচিতি, ক্যালেন্ডার, কল লগ এবং আশেপাশের ডিভাইস ব্যবহার করার অনুমতির মতো তথ্যে অ্যাক্সেস দেওয়া হবে।"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"আপনি কি <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ম্যানেজ করার জন্য <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-কে অনুমতি দেবেন?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"চশমা"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ম্যানেজ করতে এই অ্যাপ দরকার। <xliff:g id="APP_NAME">%2$s</xliff:g>-কে আপনার বিজ্ঞপ্তির সাথে ইন্টার্যাক্ট করার এবং ফোন, এসএমএস, পরিচিতি, মাইক্রোফোন ও আশেপাশের ডিভাইসের অনুমতি অ্যাক্সেস করতে দেওয়া হবে।"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"আপনার ফোন থেকে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> অ্যাপকে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্রস-ডিভাইস পরিষেবা"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"আপনার ডিভাইসগুলির মধ্যে অ্যাপ স্ট্রিম করার জন্য <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর হয়ে অনুমতি চাইছে"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"আপনার ফোন থেকে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-কে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play পরিষেবা"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"আপনার ফোনের ফটো, মিডিয়া এবং তথ্য অ্যাক্সেস করার জন্য <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর হয়ে অনুমতি চাইছে"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>কে এই অ্যাকশন করতে দেবেন?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"আশেপাশের ডিভাইসে অ্যাপ ও অন্যান্য সিস্টেম ফিচার স্ট্রিম করার জন্য আপনার <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-এর হয়ে <xliff:g id="APP_NAME">%1$s</xliff:g> অনুমতি চেয়ে অনুরোধ করছে"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"এই অ্যাপ, আপনার ফোন এবং <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ডিভাইসের মধ্যে তথ্য সিঙ্ক করতে পারবে, যেমন কোনও কলারের নাম"</string> + <string name="summary_generic" msgid="1761976003668044801">"এই অ্যাপ, আপনার ফোন এবং বেছে নেওয়া ডিভাইসের মধ্যে তথ্য সিঙ্ক করতে পারবে, যেমন কোনও কলারের নাম"</string> <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string> <string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string> <string name="consent_back" msgid="2560683030046918882">"ফিরুন"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"আপনার ফোনের অ্যাপ স্ট্রিম করুন"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"আপনার ফোন থেকে অ্যাপ ও অন্যান্য সিস্টেম ফিচার স্ট্রিম করে"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ফোন"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ট্যাবলেট"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml index 869e3c62d83d..d49778b9186c 100644 --- a/packages/CompanionDeviceManager/res/values-bs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Prateći upravitelj uređaja"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"sat"</string> <string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\" kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> će biti dozvoljeni sinhroniziranje informacija, kao što je ime osobe koja upućuje poziv, interakcija s obavještenjima i pristup odobrenjima za Telefon, SMS, Kontakte, Kalendar, Zapisnike poziva i Uređaje u blizini."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"naočale"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> će biti dozvoljena interakcija s obavještenjima i pristup odobrenjima za Telefon, SMS, Kontakte, Mikrofon i Uređaje u blizini."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama s telefona"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zahtijeva odobrenje da prenosi aplikacije između vaših uređaja"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa ovim informacijama s vašeg telefona"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zahtijeva odobrenje da pristupi fotografijama, medijima i odobrenjima na vašem telefonu"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Dozvoliti uređaju <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> da poduzme ovu radnju?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> traži odobrenje da prenosi aplikacije i druge funkcije sistema na uređajima u blizini"</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ova aplikacija će moći sinhronizirati informacije, kao što je ime osobe koja upućuje poziv, između vašeg telefona i uređaja <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija će moći sinhronizirati informacije, kao što je ime osobe koja upućuje poziv, između vašeg telefona i odabranog uređaja"</string> <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string> <string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string> <string name="consent_back" msgid="2560683030046918882">"Nazad"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Prenosite aplikacije s telefona"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Prijenos aplikacija i drugih funkcija sistema s vašeg telefona"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml index 4e89780f2b7a..7ca608f1b832 100644 --- a/packages/CompanionDeviceManager/res/values-ca/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gestor de dispositius complementaris"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string> <string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Aquesta aplicació es necessita per gestionar el dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> tindrà permís per sincronitzar informació, com ara el nom d\'algú que truca, per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes, al calendari, als registres de trucades i als dispositius propers."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestioni <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ulleres"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Aquesta aplicació es necessita per gestionar el dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes, al micròfon i als dispositius propers."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a aquesta informació del telèfon"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serveis multidispositiu"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> per reproduir en continu aplicacions entre els dispositius"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a aquesta informació del telèfon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Serveis de Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> per accedir a les fotos, el contingut multimèdia i les notificacions del telèfon"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vols permetre que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dugui a terme aquesta acció?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> sol·licita permís en nom del teu dispositiu (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) per reproduir en continu aplicacions i altres funcions del sistema en dispositius propers"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, entre el teu telèfon i el dispositiu (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string> + <string name="summary_generic" msgid="1761976003668044801">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, entre el teu telèfon i el dispositiu triat"</string> <string name="consent_yes" msgid="8344487259618762872">"Permet"</string> <string name="consent_no" msgid="2640796915611404382">"No permetis"</string> <string name="consent_back" msgid="2560683030046918882">"Enrere"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Reprodueix en continu aplicacions del telèfon"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Reprodueix en continu aplicacions i altres funcions del sistema des del telèfon"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telèfon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tauleta"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml index 0e6bf0ecd242..13e71dd2a4cf 100644 --- a/packages/CompanionDeviceManager/res/values-cs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Správce doprovodných zařízení"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string> <string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Tato aplikace je nutná ke správě zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude moci synchronizovat údaje, jako je jméno volajícího, interagovat s vašimi oznámeními a získat přístup k vašim oprávněním k telefonu, SMS, kontaktům, kalendáři, seznamům hovorů a zařízením v okolí."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> spravovat zařízení <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"brýle"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Tato aplikace je nutná ke správě zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude moci interagovat s vašimi oznámeními a získat přístup k vašim oprávněním k telefonu, SMS, kontaktům, mikrofonu a zařízením v okolí."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k těmto informacím z vašeho telefonu"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pro více zařízení"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> oprávnění ke streamování aplikací mezi zařízeními"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k těmto informacím z vašeho telefonu"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> oprávnění k přístupu k fotkám, médiím a oznámením v telefonu"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Povolit zařízení <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> podniknout tuto akci?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> žádá jménem vašeho zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o oprávnění streamovat aplikace a další systémové funkce do zařízení v okolí"</string> <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, mezi vaším telefonem a zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, mezi vaším telefonem a vybraným zařízením"</string> <string name="consent_yes" msgid="8344487259618762872">"Povolit"</string> <string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string> <string name="consent_back" msgid="2560683030046918882">"Zpět"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streamujte aplikace v telefonu"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Streamování aplikací a dalších systémových funkcí z telefonu"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefonu"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tabletu"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml index b78deee1864a..de8ee48307cf 100644 --- a/packages/CompanionDeviceManager/res/values-da/strings.xml +++ b/packages/CompanionDeviceManager/res/values-da/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Medfølgende enhedsadministrator"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Vil du give <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ur"</string> <string name="chooser_title" msgid="2262294130493605839">"Vælg det <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, som skal administreres af <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Du skal bruge denne app for at administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilladelse til at interagere med dine notifikationer og synkronisere oplysninger som f.eks. navnet på en person, der ringer, og appen får adgang til dine tilladelser for Opkald, Sms, Kalender, Opkaldshistorik og Enheder i nærheden."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du tillade, at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administrerer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"briller"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Du skal bruge denne app for at administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilladelse til at interagere med dine notifikationer og tilgå tilladelserne Telefon, Sms, Kontakter, Mikrofon og Enheder i nærheden."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Giv <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til disse oplysninger fra din telefon"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til at streame apps mellem dine enheder"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Tillad, at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> får adgang til disse oplysninger fra din telefon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til at få adgang til din telefons billeder, medier og notifikationer"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vil du tillade, at <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> foretager denne handling?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at streame apps og andre systemfunktioner til enheder i nærheden"</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Denne app vil kunne synkronisere oplysninger som f.eks. navnet på en person, der ringer, mellem din telefon og <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Denne app vil kunne synkronisere oplysninger som f.eks. navnet på en person, der ringer, mellem din telefon og den valgte enhed"</string> <string name="consent_yes" msgid="8344487259618762872">"Tillad"</string> <string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string> <string name="consent_back" msgid="2560683030046918882">"Tilbage"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream din telefons apps"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Stream apps og andre systemfunktioner fra din telefon"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml index 1d20a4d1fcfa..736ef5f19537 100644 --- a/packages/CompanionDeviceManager/res/values-de/strings.xml +++ b/packages/CompanionDeviceManager/res/values-de/strings.xml @@ -17,28 +17,29 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Begleitgerät-Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Zulassen, dass <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> auf das Gerät <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> zugreifen darf?"</string> <string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string> <string name="chooser_title" msgid="2262294130493605839">"Gerät „<xliff:g id="PROFILE_NAME">%1$s</xliff:g>“ auswählen, das von <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> verwaltet werden soll"</string> <!-- no translation found for summary_watch (898569637110705523) --> <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Zulassen, dass <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> das Gerät <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> verwalten darf"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"Glass-Geräte"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Diese App wird zur Verwaltung deines Geräts (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) benötigt. <xliff:g id="APP_NAME">%2$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“, „Mikrofon“ und „Geräte in der Nähe“ zugreifen."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-Dienste"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Zugriff auf die Fotos, Medien und Benachrichtigungen deines Smartphones"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Darf das Gerät <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> diese Aktion ausführen?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein Gerät (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) um die Berechtigung, Apps und andere Systemfunktionen auf Geräte in der Nähe zu streamen"</string> <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string> @@ -75,8 +76,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Smartphone-Apps streamen"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Apps und andere Systemfunktionen von deinem Smartphone streamen"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"Smartphone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"Tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml index 8cb6e6376bf0..f0d9d8c5a556 100644 --- a/packages/CompanionDeviceManager/res/values-el/strings.xml +++ b/packages/CompanionDeviceManager/res/values-el/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Διαχείριση συνοδευτικής εφαρμογής"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να έχει πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ;"</string> <string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string> <string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Αυτή η εφαρμογή είναι απαραίτητη για τη διαχείριση της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Η εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> θα μπορεί να συγχρονίζει πληροφορίες, όπως το όνομα ενός ατόμου που σας καλεί, να αλληλεπιδρά με τις ειδοποιήσεις σας και να αποκτά πρόσβαση στις άδειες Τηλέφωνο, SMS, Επαφές, Ημερολόγιο, Αρχεία καταγρ. κλήσ. και Συσκευές σε κοντινή απόσταση."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να διαχειρίζεται τη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ;"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"γυαλιά"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Αυτή η εφαρμογή είναι απαραίτητη για τη διαχείριση της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Θα επιτρέπεται στην εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> να αλληλεπιδρά με τις ειδοποιήσεις σας και να αποκτά πρόσβαση στις άδειες για το Τηλέφωνο, τα SMS, τις Επαφές, το Μικρόφωνο και τις Συσκευές σε κοντινή απόσταση."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Να επιτρέπεται στο <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> η πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Υπηρεσίες πολλών συσκευών"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μέρους της συσκευής σας <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> άδεια για ροή εφαρμογών μεταξύ των συσκευών σας"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να έχει πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Υπηρεσίες Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μέρους της συσκευής σας <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> άδεια για πρόσβαση στις φωτογραφίες, τα αρχεία μέσων και τις ειδοποιήσεις του τηλεφώνου σας"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Να επιτρέπεται στη συσκευή <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> να εκτελεί αυτήν την ενέργεια;"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους της συσκευής σας <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για ροή εφαρμογών και άλλων λειτουργιών του συστήματος σε συσκευές σε κοντινή απόσταση"</string> <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες μεταξύ του τηλεφώνου και της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, όπως το όνομα ενός ατόμου που σας καλεί."</string> + <string name="summary_generic" msgid="1761976003668044801">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες μεταξύ του τηλεφώνου και της επιλεγμένης συσκευής σας, όπως το όνομα ενός ατόμου που σας καλεί."</string> <string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string> <string name="consent_no" msgid="2640796915611404382">"Να μην επιτρέπεται"</string> <string name="consent_back" msgid="2560683030046918882">"Πίσω"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Μεταδώστε σε ροή τις εφαρμογές του τηλεφώνου σας"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Ροή εφαρμογών και άλλων λειτουργιών του συστήματος από το τηλέφωνό σας"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"τηλέφωνο"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml index ff1394d149ec..2e3bddc7a53a 100644 --- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%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> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, microphone and Nearby devices permissions."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"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="1761976003668044801">"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_back" msgid="2560683030046918882">"Back"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Stream apps and other system features from your phone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"phone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml index 21255751bdfd..4afe1a889710 100644 --- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml @@ -17,27 +17,24 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%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> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> - <skip /> + <string name="summary_watch_single_device" msgid="3173948915947011333">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> - <skip /> + <string name="summary_glasses_single_device" msgid="3000909894067413398">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string> + <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media, and notifications"</string> + <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to access your phone’s photos, media, and notifications"</string> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> @@ -72,8 +69,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Stream apps and other system features from your phone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"phone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml index ff1394d149ec..2e3bddc7a53a 100644 --- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%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> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, microphone and Nearby devices permissions."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"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="1761976003668044801">"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_back" msgid="2560683030046918882">"Back"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Stream apps and other system features from your phone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"phone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml index ff1394d149ec..2e3bddc7a53a 100644 --- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%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> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, microphone and Nearby devices permissions."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"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="1761976003668044801">"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_back" msgid="2560683030046918882">"Back"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Stream apps and other system features from your phone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"phone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml index b012b6f9710a..e5d11dc47c7f 100644 --- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml @@ -17,27 +17,24 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="summary_watch" msgid="898569637110705523">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%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> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> - <skip /> + <string name="summary_watch_single_device" msgid="3173948915947011333">"This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"This app is needed to manage <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> - <skip /> + <string name="summary_glasses_single_device" msgid="3000909894067413398">"This app will be allowed to access these permissions on your <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string> + <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to stream apps between your devices"</string> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media, and notifications"</string> + <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> to access your phone’s photos, media, and notifications"</string> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Allow <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> to take this action?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps and other system features to nearby devices"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> @@ -72,8 +69,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Stream apps and other system features from your phone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"phone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml index 578af1d855bb..7a6524fce3f4 100644 --- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Administrador de dispositivo complementario"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"¿Quieres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string> <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que la app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> lo administre"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Esta app es necesaria para administrar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá sincronizar información, como el nombre de la persona que llama, interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos, Calendario, Llamadas y Dispositivos cercanos."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administre <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"Gafas"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Esta app es necesaria para administrar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos, Micrófono y Dispositivos cercanos."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para transmitir apps entre dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acceder a las fotos, el contenido multimedia y las notificaciones de tu teléfono"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"¿Permites que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realice esta acción?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para transmitir apps y otras funciones del sistema a dispositivos cercanos"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Esta app podrá sincronizar información, como el nombre de la persona que llama, entre el teléfono y <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Esta app podrá sincronizar información, como el nombre de la persona que llama, entre el teléfono y el dispositivo elegido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"No permitir"</string> <string name="consent_back" msgid="2560683030046918882">"Atrás"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Transmitir las apps de tu teléfono"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Transmite apps y otras funciones del sistema desde tu teléfono"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"teléfono"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml index 19c556fe1f66..e416999b80f5 100644 --- a/packages/CompanionDeviceManager/res/values-es/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos complementario"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a tu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string> <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Se necesita esta aplicación para gestionar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá sincronizar información (por ejemplo, el nombre de la persona que te llama), interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos, calendario, registros de llamadas y dispositivos cercanos."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestione <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"gafas"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Se necesita esta aplicación para gestionar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos, micrófono y dispositivos cercanos."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para emitir aplicaciones en otros dispositivos tuyos"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acceder a las fotos, los archivos multimedia y las notificaciones de tu teléfono"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"¿Permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realice esta acción?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para emitir aplicaciones y otras funciones del sistema en dispositivos cercanos"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Esta aplicación podrá sincronizar información (por ejemplo, el nombre de la persona que te llama) entre tu teléfono y <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Esta aplicación podrá sincronizar información (por ejemplo, el nombre de la persona que te llama) entre tu teléfono y el dispositivo que elijas"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"No permitir"</string> <string name="consent_back" msgid="2560683030046918882">"Atrás"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Muestra en streaming las aplicaciones de tu teléfono"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Emite aplicaciones y otras funciones del sistema desde tu teléfono"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"teléfono"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml index bbd3ae4a81cc..9ddd4419dd16 100644 --- a/packages/CompanionDeviceManager/res/values-et/strings.xml +++ b/packages/CompanionDeviceManager/res/values-et/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Kaasseadme haldur"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Andke rakendusele <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> juurdepääs seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"käekell"</string> <string name="chooser_title" msgid="2262294130493605839">"Valige <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Seda rakendust on vaja teie seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> haldamiseks. Rakendusel <xliff:g id="APP_NAME">%2$s</xliff:g> lubatakse sünkroonida teavet, näiteks helistaja nime, kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide, kalendri, kõnelogide ja läheduses olevate seadmete lubadele."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hallata seadet <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"prillid"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Seda rakendust on vaja seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> haldamiseks. Rakendusel <xliff:g id="APP_NAME">%2$s</xliff:g> lubatakse kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide, mikrofoni ja läheduses olevate seadmete lubadele."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi voogesitada"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play teenused"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nimel luba pääseda juurde telefoni fotodele, meediale ja märguannetele"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Kas lubada seadmel <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> teha seda toimingut?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba voogesitada rakendusi ja muid süsteemi funktsioone läheduses olevatesse seadmetesse"</string> <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> vahel"</string> + <string name="summary_generic" msgid="1761976003668044801">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja valitud seadme vahel"</string> <string name="consent_yes" msgid="8344487259618762872">"Luba"</string> <string name="consent_no" msgid="2640796915611404382">"Ära luba"</string> <string name="consent_back" msgid="2560683030046918882">"Tagasi"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefoni rakenduste voogesitamine"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Rakenduste ja muude süsteemi funktsioonide voogesitamine teie telefonist"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tahvelarvuti"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml index 1185b2d6ac88..7b4e4f907769 100644 --- a/packages/CompanionDeviceManager/res/values-eu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gailu osagarriaren kudeatzailea"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> erabiltzeko baimena eman nahi diozu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari?"</string> <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string> <string name="chooser_title" msgid="2262294130493605839">"Aukeratu <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Aplikazioa <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kudeatzeko behar da. Informazioa sinkronizatzeko (esate baterako, deitzaileen izenak), jakinarazpenekin interakzioan aritzeko, eta telefonoa, SMSak, kontaktuak, egutegia, deien erregistroak eta inguruko gailuak erabiltzeko baimena izango du <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kudeatzeko baimena eman nahi diozu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"betaurrekoak"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailua kudeatzeko behar da aplikazioa. Jakinarazpenekin interakzioan aritzeko, eta telefonoa, SMSak, kontaktuak, mikrofonoa eta inguruko gailuak erabiltzeko baimena izango du <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu baterako baino gehiagotarako zerbitzuak"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Gailu batetik bestera aplikazioak igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Eman telefonoko informazio hau erabiltzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Telefonoko argazkiak, multimedia-edukia eta jakinarazpenak erabiltzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ekintza hau gauzatzeko baimena eman nahi diozu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> aplikazioari?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikazioak eta sistemaren beste eginbide batzuk inguruko gailuetara igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string> <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Telefonoaren eta <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuaren artean informazioa sinkronizatzeko gai izango da aplikazioa (esate baterako, deitzaileen izenak)"</string> + <string name="summary_generic" msgid="1761976003668044801">"Telefonoaren eta hautatutako gailuaren artean informazioa sinkronizatzeko gai izango da aplikazioa (esate baterako, deitzaileen izenak)"</string> <string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string> <string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string> <string name="consent_back" msgid="2560683030046918882">"Atzera"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Igorri zuzenean telefonoko aplikazioak"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Igorri aplikazioak eta sistemaren beste eginbide batzuk telefonotik"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"Telefonoa"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"Tableta"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml index d77c5c9cd5e2..bafeabc38d5e 100644 --- a/packages/CompanionDeviceManager/res/values-fa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"مدیر دستگاه مرتبط"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه داده شود به <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی پیدا کند؟"</string> <string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string> <string name="chooser_title" msgid="2262294130493605839">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما لازم است. به <xliff:g id="APP_NAME">%2$s</xliff:g> اجازه داده میشود اطلاعاتی مثل نام شخصی را که تماس میگیرد همگامسازی کند، با اعلانهای شما تعامل داشته باشد، و به اجازههای «تلفن»، «پیامک»، «مخاطبین»، «تقویم»، «گزارشهای تماس»، و «دستگاههای اطراف» دسترسی داشته باشد."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه داده شود <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> را مدیریت کند؟"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"عینک"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> لازم است. به <xliff:g id="APP_NAME">%2$s</xliff:g> اجازه داده میشود با اعلانهای شما تعامل داشته باشد و به اجازههای «تلفن»، «پیامک»، «مخاطبین»، «میکروفون»، و «دستگاههای اطراف» دسترسی داشته باشد."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"اجازه دادن به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> برای دسترسی به اطلاعات تلفن"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"سرویسهای بیندستگاهی"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> اجازه میخواهد ازطرف <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> برنامهها را بین دستگاههای شما جاریسازی کند"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه دسترسی به این اطلاعات در دستگاهتان داده شود"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"خدمات Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> اجازه میخواهد ازطرف <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> به عکسها، رسانهها، و اعلانهای تلفن شما دسترسی پیدا کند"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"به <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> اجازه داده شود این اقدام را انجام دهد؟"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه میخواهد تا برنامهها و دیگر ویژگیهای سیستم را در دستگاههای اطراف جاریسازی کند."</string> <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"این برنامه مجاز میشود اطلاعتی مثل نام شخصی را که تماس میگیرد بین تلفن شما و <xliff:g id="DEVICE_NAME">%1$s</xliff:g> همگامسازی کند"</string> + <string name="summary_generic" msgid="1761976003668044801">"این برنامه مجاز میشود اطلاعتی مثل نام شخصی را که تماس میگیرد بین تلفن شما و دستگاه انتخابشده همگامسازی کند"</string> <string name="consent_yes" msgid="8344487259618762872">"اجازه دادن"</string> <string name="consent_no" msgid="2640796915611404382">"اجازه ندادن"</string> <string name="consent_back" msgid="2560683030046918882">"برگشتن"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"جاریسازی برنامههای تلفن"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"برنامهها و دیگر ویژگیهای سیستم را از تلفن شما جاریسازی میکند"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"تلفن"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"رایانه لوحی"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml index c679f86b5fed..ff8d7a75278c 100644 --- a/packages/CompanionDeviceManager/res/values-fi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Sallitaanko, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa pääsyn laitteeseen: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"kello"</string> <string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> hallinnoi"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ylläpitoon (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) tarvitaan tätä sovellusta. <xliff:g id="APP_NAME">%2$s</xliff:g> saa luvan synkronoida tietoja (esimerkiksi soittajan nimen), hallinnoida ilmoituksiasi sekä pääsyn puhelimeen, tekstiviesteihin, yhteystietoihin, kalenteriin, puhelulokeihin ja lähellä olevat laitteet ‑lupiin."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa ylläpitää laitetta: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"lasit"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> edellyttää ylläpitoon tätä sovellusta. <xliff:g id="APP_NAME">%2$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeen, tekstiviesteihin, yhteystietoihin, mikrofoniin ja lähellä olevat laitteet ‑lupiin."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa pääsyn näihin puhelimesi tietoihin"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Laitteidenväliset palvelut"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia laitteidesi välillä"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Salli pääsy tähän tietoon puhelimellasi: <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Palvelut"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) puolesta lupaa päästä puhelimesi kuviin, mediaan ja ilmoituksiin"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Sallitko, että <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> voi suorittaa tämän toiminnon?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia ja muita järjestelmän ominaisuuksia lähellä oleviin laitteisiin."</string> <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Sovellus voi synkronoida tietoja (esimerkiksi soittajan nimen) puhelimesi ja laitteen (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) välillä"</string> + <string name="summary_generic" msgid="1761976003668044801">"Sovellus voi synkronoida tietoja (esimerkiksi soittajan nimen) puhelimesi ja valitun laitteen välillä"</string> <string name="consent_yes" msgid="8344487259618762872">"Salli"</string> <string name="consent_no" msgid="2640796915611404382">"Älä salli"</string> <string name="consent_back" msgid="2560683030046918882">"Takaisin"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Striimaa puhelimen sovelluksia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Striimaa sovelluksia ja muita järjestelmän ominaisuuksia puhelimesta"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"puhelin"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tabletti"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml index f88864d18af8..a58cd8263283 100644 --- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml @@ -17,28 +17,29 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareil compagnon"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"montre"</string> <string name="chooser_title" msgid="2262294130493605839">"Choisissez un(e) <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <!-- no translation found for summary_watch (898569637110705523) --> <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"lunettes"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Cette application est nécessaire pour gérer <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> sera autorisée à interagir avec vos notifications et à accéder à vos autorisations pour le téléphone, les messages texte, les contacts, le microphone et les appareils à proximité."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Autorisez <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations à partir de votre téléphone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour diffuser des applications entre vos appareils"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Autorisez <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations à partir de votre téléphone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour accéder aux photos, aux fichiers multimédias et aux notifications de votre téléphone"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à effectuer cette action?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation, au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g>, de diffuser des applications et d\'autres fonctionnalités du système sur des appareils à proximité"</string> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> @@ -75,8 +76,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Diffusez les applications de votre téléphone"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Diffusez des applications et d\'autres fonctionnalités du système à partir de votre téléphone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"téléphone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablette"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml index 94d00afa63f0..35f95be6e294 100644 --- a/packages/CompanionDeviceManager/res/values-fr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareils associés"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ?"</string> <string name="profile_name_watch" msgid="576290739483672360">"montre"</string> <string name="chooser_title" msgid="2262294130493605839">"Sélectionnez le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Cette appli est nécessaire pour gérer <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation de synchroniser des infos (comme le nom de l\'appelant), d\'interagir avec vos notifications et d\'accéder à votre téléphone, à votre agenda, ainsi qu\'à vos SMS, contacts, journaux d\'appels et appareils à proximité."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"lunettes"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Cette appli est nécessaire pour gérer <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations du téléphone, des SMS, des contacts, du micro et des appareils à proximité."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations depuis votre téléphone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour caster des applis d\'un appareil à l\'autre"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations depuis votre téléphone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour accéder aux photos, contenus multimédias et notifications de votre téléphone"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à effectuer cette action ?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de diffuser des applis et d\'autres fonctionnalités système en streaming sur des appareils à proximité"</string> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Cette appli pourra synchroniser des infos, comme le nom de l\'appelant, entre votre téléphone et <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Cette appli pourra synchroniser des infos, comme le nom de l\'appelant, entre votre téléphone et l\'appareil choisi"</string> <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string> <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string> <string name="consent_back" msgid="2560683030046918882">"Retour"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Diffuser en streaming les applis de votre téléphone"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Diffusez des applis et d\'autres fonctionnalités système en streaming depuis votre téléphone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"téléphone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablette"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml index f9b1475ad894..7e6aa921d303 100644 --- a/packages/CompanionDeviceManager/res/values-gl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml @@ -17,28 +17,29 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Xestor de dispositivos complementarios"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda ao dispositivo (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)?"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string> <string name="chooser_title" msgid="2262294130493605839">"Escolle un dispositivo (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <!-- no translation found for summary_watch (898569637110705523) --> <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> xestione o dispositivo (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"lentes"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Esta aplicación é necesaria para xestionar o dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das SMS, dos contactos, do micrófono e dos dispositivos próximos."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde o teu teléfono"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizos multidispositivo"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) para emitir contido de aplicacións entre os teus aparellos"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información do teu teléfono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Servizos de Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) para acceder ás fotos, ao contido multimedia e ás notificacións do teléfono"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Queres permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> leve a cabo esta acción?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para emitir o contido das aplicacións e doutras funcións do sistema en dispositivos próximos"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> @@ -75,8 +76,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Emite as aplicacións do teu teléfono"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Emite o contido das aplicacións e doutras funcións do sistema desde o teléfono"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"teléfono"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tableta"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml index dd32e5d845a1..5d1d0e3d2aaa 100644 --- a/packages/CompanionDeviceManager/res/values-gu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"કમ્પેનિયન ડિવાઇસ મેનેજર"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string> <string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"તમારા <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ને મેનેજ કરવા માટે આ ઍપ જરૂરી છે. <xliff:g id="APP_NAME">%2$s</xliff:g>ને કૉલ કરનાર વ્યક્તિનું નામ જેવી માહિતી સિંક કરવાની, તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની અને તમારો ફોન, SMS, સંપર્કો, Calendar, કૉલ લૉગ તથા નજીકના ડિવાઇસની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> મેનેજ કરવા માટે મંજૂરી આપીએ?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ચશ્માં"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ને મેનેજ કરવા માટે આ ઍપ જરૂરી છે. <xliff:g id="APP_NAME">%2$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની અને તમારો ફોન, SMS, સંપર્કો, માઇક્રોફોન તથા નજીકના ડિવાઇસની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને મંજૂરી આપો"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ક્રોસ-ડિવાઇસ સેવાઓ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> વતી તમારા ડિવાઇસ વચ્ચે ઍપ સ્ટ્રીમ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને મંજૂરી આપો"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play સેવાઓ"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> વતી તમારા ફોનના ફોટા, મીડિયા અને નોટિફિકેશન ઍક્સેસ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ને આ પગલું ભરવાની મંજૂરી આપીએ?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> નજીકના ડિવાઇસ પર ઍપ અને સિસ્ટમની અન્ય સુવિધાઓ સ્ટ્રીમ કરવા તમારા <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી પરવાનગીની વિનંતી કરી રહી છે"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"આ ઍપ તમારા ફોન અને <xliff:g id="DEVICE_NAME">%1$s</xliff:g> વચ્ચે, કૉલ કરનાર કોઈ વ્યક્તિનું નામ જેવી માહિતી સિંક કરી શકશે"</string> + <string name="summary_generic" msgid="1761976003668044801">"આ ઍપ તમારા ફોન અને પસંદ કરેલા ડિવાઇસ વચ્ચે, કૉલ કરનાર કોઈ વ્યક્તિનું નામ જેવી માહિતી સિંક કરી શકશે"</string> <string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string> <string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string> <string name="consent_back" msgid="2560683030046918882">"પાછળ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"તમારા ફોનની ઍપ સ્ટ્રીમ કરો"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"તમારા ફોન પરથી ઍપ અને સિસ્ટમની અન્ય સુવિધાઓ સ્ટ્રીમ કરો"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ફોન"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ટૅબ્લેટ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml index e5ee703e7ded..f0887aceabbe 100644 --- a/packages/CompanionDeviceManager/res/values-hi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"सहयोगी डिवाइस मैनेजर"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"क्या <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> को ऐक्सेस करने के लिए <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अनुमति देनी है?"</string> <string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string> <string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> की मदद से मैनेज किया जा सके"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"यह ऐप्लिकेशन, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> को मैनेज करने के लिए ज़रूरी है. <xliff:g id="APP_NAME">%2$s</xliff:g> को डिवाइस की जानकारी सिंक करने की अनुमति होगी. जैसे, कॉल करने वाले व्यक्ति का नाम. इसे आपकी सूचनाओं पर कार्रवाई करने के साथ-साथ आपके फ़ोन, एसएमएस, संपर्कों, कैलेंडर, कॉल लॉग, और आस-पास मौजूद डिवाइसों को ऐक्सेस करने की अनुमति भी होगी."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"क्या <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> मैनेज करने की अनुमति देनी है?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"चश्मा"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"यह ऐप्लिकेशन, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> को मैनेज करने के लिए ज़रूरी है. <xliff:g id="APP_NAME">%2$s</xliff:g> को डिवाइस की सूचनाओं पर कार्रवाई करने की अनुमति होगी. इसे आपके फ़ोन, मैसेज, संपर्कों, माइक्रोफ़ोन, और आस-पास मौजूद डिवाइसों को ऐक्सेस करने की अनुमति भी होगी."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, आपके डिवाइसों के बीच ऐप्लिकेशन को स्ट्रीम करने की अनुमति मांग रहा है"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, फ़ोन में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रहा है"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"क्या <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> को यह कार्रवाई करने की अनुमति देनी है?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से, ऐप्लिकेशन और दूसरे सिस्टम की सुविधाओं को आस-पास मौजूद डिवाइसों पर स्ट्रीम करने की अनुमति मांग रहा है"</string> <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"यह ऐप्लिकेशन, आपके फ़ोन और <xliff:g id="DEVICE_NAME">%1$s</xliff:g> के बीच जानकारी सिंक करेगा. जैसे, कॉल करने वाले व्यक्ति का नाम"</string> + <string name="summary_generic" msgid="1761976003668044801">"यह ऐप्लिकेशन, आपके फ़ोन और चुने हुए डिवाइस के बीच जानकारी सिंक करेगा. जैसे, कॉल करने वाले व्यक्ति का नाम"</string> <string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string> <string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string> <string name="consent_back" msgid="2560683030046918882">"वापस जाएं"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"अपने फ़ोन पर मौजूद ऐप्लिकेशन स्ट्रीम करें"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"अपने फ़ोन से ऐप्लिकेशन और दूसरे सिस्टम की सुविधाओं को स्ट्रीम करें"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"फ़ोन"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"टैबलेट"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml index 559dfd55d922..3c399b553b73 100644 --- a/packages/CompanionDeviceManager/res/values-hr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Želite li dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"satom"</string> <string name="chooser_title" msgid="2262294130493605839">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ta je aplikacija potrebna za upravljanje vašim uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će sinkronizirati podatke, primjerice ime pozivatelja, stupati u interakciju s vašim obavijestima i pristupati vašim dopuštenjima za telefon, SMS-ove, kontakte, kalendar, zapisnike poziva i uređaje u blizini."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"naočale"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ta je aplikacija potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati vašim dopuštenjima za telefon, SMS-ove, kontakte, mikrofon i uređaje u blizini."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Omogućite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa informacijama s vašeg telefona"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na različitim uređajima"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za emitiranje aplikacija između vaših uređaja"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Omogućite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa informacijama s vašeg telefona"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Usluge za Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za pristup fotografijama, medijskim sadržajima i obavijestima na telefonu"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Dopustiti <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> da izvede tu radnju?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za emitiranje aplikacija i drugih značajki sustava na uređajima u blizini"</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ta će aplikacija moći sinkronizirati podatke između vašeg telefona i uređaja <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, primjerice ime pozivatelja"</string> + <string name="summary_generic" msgid="1761976003668044801">"Ta će aplikacija moći sinkronizirati podatke između vašeg telefona i odabranog uređaja, primjerice ime pozivatelja"</string> <string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string> <string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string> <string name="consent_back" msgid="2560683030046918882">"Natrag"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streaming aplikacija vašeg telefona"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Emitiranje aplikacija i drugih značajki sustava s vašeg telefona"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefonu"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tabletu"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml index bc317ee4c33d..0fad7f1be614 100644 --- a/packages/CompanionDeviceManager/res/values-hu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Társeszközök kezelője"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Engedélyezi a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hozzáférését a következőhöz: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"óra"</string> <string name="chooser_title" msgid="2262294130493605839">"A(z) <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Szükség van erre az alkalmazásra a következő kezeléséhez: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A(z) <xliff:g id="APP_NAME">%2$s</xliff:g> képes lesz szinkronizálni információkat (például a hívó fél nevét), műveleteket végezhet majd az értesítésekkel, és hozzáférhet majd a Telefon, az SMS, a Névjegyek, a Naptár, a Hívásnaplók és a Közeli eszközök engedélyekhez."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Engedélyezi, hogy a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> kezelje a következő eszközt: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"szemüveg"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Erre az alkalmazásra szükség van a következő eszköz kezeléséhez: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A(z) <xliff:g id="APP_NAME">%2$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet majd a Telefon, az SMS, a Névjegyek, a Mikrofon és a Közeli eszközök engedélyekhez."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Többeszközös szolgáltatások"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nevében az alkalmazások eszközök közötti streameléséhez"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-szolgáltatások"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nevében a telefonon tárolt fotókhoz, médiatartalmakhoz és értesítésekhez való hozzáféréshez"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Engedélyezi a(z) <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> számára ennek a műveletnek a végrehajtását?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az alkalmazások és más rendszerfunkciók közeli eszközökre történő streamelésére"</string> <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ez az alkalmazás képes lesz szinkronizálni az olyan információkat a telefon és a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszköz között, mint például a hívó fél neve."</string> + <string name="summary_generic" msgid="1761976003668044801">"Ez az alkalmazás képes lesz szinkronizálni az olyan információkat a telefon és a kiválasztott eszköz között, mint például a hívó fél neve."</string> <string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string> <string name="consent_no" msgid="2640796915611404382">"Tiltás"</string> <string name="consent_back" msgid="2560683030046918882">"Vissza"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"A telefon alkalmazásainak streamelése"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Alkalmazások és más rendszerfunkciók streamelése a telefonról"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefonján"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"táblagépén"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml index bc7bfc7fec5c..7cc3f07736f1 100644 --- a/packages/CompanionDeviceManager/res/values-hy/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին կառավարել <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> սարքը"</string> <string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string> <string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> հավելվածի կողմից"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Այս հավելվածն անհրաժեշտ է ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g> պրոֆիլը կառավարելու համար։ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածը կկարողանա համաժամացնել տվյալները, օր․՝ զանգողի անունը, փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ», «Օրացույց», «Կանչերի ցուցակ» և «Մոտակա սարքեր» թույլտվությունները։"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին կառավարել <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> սարքը"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ակնոց"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Այս հավելվածն անհրաժեշտ է <xliff:g id="DEVICE_NAME">%1$s</xliff:g> սարքը կառավարելու համար։ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ», «Խոսափող» և «Մոտակա սարքեր» թույլտվությունները։"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Թույլատրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Միջսարքային ծառայություններ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Թույլատրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ծառայություններ"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր հեռախոսի լուսանկարները, մեդիաֆայլերն ու ծանուցումները տեսնելու համար"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Թույլատրե՞լ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> հավելվածին կատարել այս գործողությունը"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ մոտակա սարքերին հավելվածներ և համակարգի այլ գործառույթներ հեռարձակելու համար"</string> <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Այս հավելվածը կկարողանա համաժամացնել ձեր հեռախոսի և <xliff:g id="DEVICE_NAME">%1$s</xliff:g> սարքի տվյալները, օր․՝ զանգողի անունը"</string> + <string name="summary_generic" msgid="1761976003668044801">"Այս հավելվածը կկարողանա համաժամացնել ձեր հեռախոսի և ընտրված սարքի տվյալները, օր․՝ զանգողի անունը"</string> <string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string> <string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string> <string name="consent_back" msgid="2560683030046918882">"Հետ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Հեռարձակել հեռախոսի հավելվածները"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Հեռարձակել հավելվածներ և համակարգի այլ գործառույթներ հեռախոսում"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"հեռախոս"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"պլանշետ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml index 8ece9defea44..16906810e747 100644 --- a/packages/CompanionDeviceManager/res/values-in/strings.xml +++ b/packages/CompanionDeviceManager/res/values-in/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Pengelola Perangkat Pendamping"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string> <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Aplikasi ini diperlukan untuk mengelola <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan diizinkan menyinkronkan info, seperti nama penelepon, berinteraksi dengan notifikasi, dan mengakses izin Telepon, SMS, Kontak, Kalender, Log panggilan, dan Perangkat di sekitar."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengelola <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Aplikasi ini diperlukan untuk mengelola <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Ponsel, SMS, Kontak, Mikrofon, dan Perangkat di sekitar."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses informasi ini dari ponsel Anda"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> untuk menstreaming aplikasi di antara perangkat Anda"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses informasi ini dari ponsel Anda"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Layanan Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> untuk mengakses foto, media, dan notifikasi ponsel Anda"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Izinkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> melakukan tindakan ini?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menstreaming aplikasi dan fitur sistem lainnya ke perangkat di sekitar"</string> <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Aplikasi ini akan dapat menyinkronkan info, seperti nama penelepon, antara ponsel dan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Aplikasi ini akan dapat menyinkronkan info, seperti nama penelepon, antara ponsel dan perangkat yang dipilih"</string> <string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string> <string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string> <string name="consent_back" msgid="2560683030046918882">"Kembali"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streaming aplikasi ponsel"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Menstreaming aplikasi dan fitur sistem lainnya dari ponsel Anda"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ponsel"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml index 49b06f09d708..fabfe2e5dff0 100644 --- a/packages/CompanionDeviceManager/res/values-is/strings.xml +++ b/packages/CompanionDeviceManager/res/values-is/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Stjórnun fylgdartækja"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"úr"</string> <string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> á að stjórna"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Þetta forrit er nauðsynlegt til að stjórna <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> fær heimild til að samstilla upplýsingar, t.d. nafn þess sem hringir, og bregðast við tilkynningum og fær aðgang að heimildum fyrir síma, SMS, tengiliði, dagatal, símtalaskrár og nálæg tæki."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að stjórna <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"gleraugu"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Þetta forrit er nauðsynlegt til að stjórna <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> fær heimild til að bregðast við tilkynningum og fær aðgang að heimildum fyrir síma, SMS, tengiliði, hljóðnema og nálæg tæki."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að þessum upplýsingum úr símanum þínum"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Þjónustur á milli tækja"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> sendir beiðni um heimild til straumspilunar forrita á milli tækjanna þinna fyrir hönd <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að þessum upplýsingum úr símanum þínum"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Þjónusta Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> sendir beiðni um aðgang að myndum, margmiðlunarefni og tilkynningum símans þíns fyrir hönd <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Leyfa <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> að framkvæma þessa aðgerð?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að streyma forritum og öðrum kerfiseiginleikum í nálægum tækjum"</string> <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Þetta forrit mun geta samstillt upplýsingar, t.d. nafn þess sem hringir, á milli símans og <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Þetta forrit mun geta samstillt upplýsingar, t.d. nafn þess sem hringir, á milli símans og valins tækis"</string> <string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string> <string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string> <string name="consent_back" msgid="2560683030046918882">"Til baka"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streymdu forritum símans"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Streymdu forritum og öðrum kerfiseiginleikum úr símanum"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"símanum"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"spjaldtölvunni"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml index 0dc78baff7c2..a0cdce61f3f1 100644 --- a/packages/CompanionDeviceManager/res/values-it/strings.xml +++ b/packages/CompanionDeviceManager/res/values-it/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gestione dispositivi companion"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Vuoi consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"orologio"</string> <string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da gestire con <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Questa app è necessaria per gestire <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> potrà sincronizzare informazioni, ad esempio il nome di un chiamante, interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti, Calendario, Registri chiamate e Dispositivi nelle vicinanze."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vuoi consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di gestire <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"occhiali"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Questa app è necessaria per gestire <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti, Microfono e Dispositivi nelle vicinanze."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Consenti a <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a queste informazioni dal tuo telefono"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> l\'autorizzazione a trasmettere app in streaming tra i dispositivi"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Consenti a <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a questa informazione dal tuo telefono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> l\'autorizzazione ad accedere a foto, contenuti multimediali e notifiche del telefono"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vuoi consentire a <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> di compiere questa azione?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> l\'autorizzazione a trasmettere in streaming app e altre funzionalità di sistema ai dispositivi nelle vicinanze"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra il telefono e <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra il telefono e il dispositivo scelto"</string> <string name="consent_yes" msgid="8344487259618762872">"Consenti"</string> <string name="consent_no" msgid="2640796915611404382">"Non consentire"</string> <string name="consent_back" msgid="2560683030046918882">"Indietro"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Trasmetti in streaming le app del tuo telefono"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Consente di trasmettere in streaming app e altre funzionalità di sistema dal telefono"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefono"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml index 8ef04eb7fe60..33bfcfddebb8 100644 --- a/packages/CompanionDeviceManager/res/values-iw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"ניהול מכשיר מותאם"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"לאשר לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong&g; לגשת אל <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"שעון"</string> <string name="chooser_title" msgid="2262294130493605839">"בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"האפליקציה הזו נחוצה כדי לנהל את <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. האפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g> תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, לבצע פעולות בהתראות ולקבל הרשאות גישה לטלפון, ל-SMS, לאנשי הקשר, ליומן, ליומני השיחות ולמכשירים בקרבת מקום."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"מתן הרשאה לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong&g; לנהל את <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"משקפיים"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"האפליקציה הזו נחוצה כדי לנהל את <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. האפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר, למיקרופון ולמכשירים בקרבת מקום."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"מתן אישור לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לגשת למידע הזה מהטלפון שלך"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"שירותים למספר מכשירים"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור מכשיר <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> כדי לשדר אפליקציות בין המכשירים שלך"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"מתן אישור לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לגשת למידע הזה מהטלפון שלך"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור מכשיר <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> כדי לגשת לתמונות, למדיה ולהתראות בטלפון שלך"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"לתת הרשאה למכשיר <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> לבצע את הפעולה הזו?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור <xliff:g id="DEVICE_NAME">%2$s</xliff:g> כדי להעביר אפליקציות ותכונות מערכת אחרות בסטרימינג למכשירים בקרבת מקום"</string> <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, מהטלפון שלך למכשיר <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, מהטלפון שלך למכשיר שבחרת"</string> <string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string> <string name="consent_no" msgid="2640796915611404382">"אין אישור"</string> <string name="consent_back" msgid="2560683030046918882">"חזרה"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"שידור אפליקציות מהטלפון"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"העברה של אפליקציות ותכונות מערכת אחרות בסטרימינג מהטלפון"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"טלפון"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"טאבלט"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml index 862ec9416dc9..3420eb78af92 100644 --- a/packages/CompanionDeviceManager/res/values-ja/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"コンパニオン デバイス マネージャー"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> へのアクセスを許可しますか?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"このアプリは<xliff:g id="DEVICE_NAME">%1$s</xliff:g>の管理に必要です。<xliff:g id="APP_NAME">%2$s</xliff:g> は通話相手の名前などの情報を同期したり、デバイスの通知を使用したり、電話、SMS、連絡先、カレンダー、通話履歴、付近のデバイスの権限にアクセスしたりできるようになります。"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> の管理を許可しますか?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"眼鏡"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"このアプリは <xliff:g id="DEVICE_NAME">%1$s</xliff:g> の管理に必要です。<xliff:g id="APP_NAME">%2$s</xliff:g> はデバイスの通知を使用したり、電話、SMS、連絡先、マイク、付近のデバイスの権限にアクセスしたりできるようになります。"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"スマートフォンのこの情報へのアクセスを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"クロスデバイス サービス"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> に代わってデバイス間でアプリをストリーミングする権限をリクエストしています"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"スマートフォンのこの情報へのアクセスを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 開発者サービス"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> に代わってスマートフォンの写真、メディア、通知にアクセスする権限をリクエストしています"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> にこの操作の実行を許可しますか?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わって、アプリやその他のシステム機能を付近のデバイスにストリーミングする権限をリクエストしています"</string> <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"このアプリは、あなたのスマートフォンと <xliff:g id="DEVICE_NAME">%1$s</xliff:g> との間で、通話相手の名前などの情報を同期できるようになります"</string> + <string name="summary_generic" msgid="1761976003668044801">"このアプリは、あなたのスマートフォンと選択したデバイスとの間で、通話相手の名前などの情報を同期できるようになります"</string> <string name="consent_yes" msgid="8344487259618762872">"許可"</string> <string name="consent_no" msgid="2640796915611404382">"許可しない"</string> <string name="consent_back" msgid="2560683030046918882">"戻る"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"スマートフォンのアプリをストリーミングします"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"アプリやその他のシステム機能をスマートフォンからストリーミングする"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"スマートフォン"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"タブレット"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml index f80515bd7fbf..870f7ef8eb74 100644 --- a/packages/CompanionDeviceManager/res/values-ka/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"კომპანიონი მოწყობილობების მენეჯერი"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"მიანიჭებთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> მოწყობილობაზე წვდომას?"</string> <string name="profile_name_watch" msgid="576290739483672360">"საათი"</string> <string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-მა"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"ეს აპი საჭიროა თქვენი <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ს სამართავად. <xliff:g id="APP_NAME">%2$s</xliff:g>-ს ექნება ისეთი ინფორმაციის სინქრონიზაციის უფლება, როგორიც იმ ადამიანის სახელია, რომელიც გირეკავთ; ასევე, თქვენს შეტყობინებებთან ინტერაქციისა და თქვენს ტელეფონზე, SMS-ებზე, კონტაქტებზე, კალენდარზე, ზარების ჟურნალებსა და ახლომახლო მოწყობილობების ნებართვებზე წვდომის უფლება."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"ნება დართეთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g>-ს</strong> მართოს <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"სათვალე"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"ეს აპი საჭიროა თქვენი <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ის სამართავად. <xliff:g id="APP_NAME">%2$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენს ტელეფონზე, SMS-ებზე, კონტაქტებზე, მიკროფონსა და ახლომახლო მოწყობილობების ნებართვებზე წვდომას."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"ნება დართეთ, რომ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"მოწყობილობათშორისი სერვისები"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს უფლებას თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის სახელით, რომ მოწყობილობებს შორის აპების სტრიმინგი შეძლოს"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"ნება დართეთ, რომ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს უფლებას თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის სახელით, რომ წვდომა ჰქონდეს თქვენი ტელეფონის ფოტოებზე, მედიასა და შეტყობინებებზე"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"გსურთ ნება მისცეთ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ს</strong> ამ მოქმედების შესასრულებლად?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს თქვენი <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ის სახელით აპების და სისტემის სხვა ფუნქციების ახლომახლო მოწყობილობებზე სტრიმინგის ნებართვას"</string> <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"ეს აპი შეძლებს ინფორმაციის სინქრონიზებას თქვენს ტელეფონსა და თქვენ მიერ არჩეულ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ს შორის, მაგალითად, იმ ადამიანის სახელის, რომელიც გირეკავთ"</string> + <string name="summary_generic" msgid="1761976003668044801">"ეს აპი შეძლებს ინფორმაციის სინქრონიზებას თქვენს ტელეფონსა და თქვენ მიერ არჩეულ მოწყობილობას შორის, მაგალითად, იმ ადამიანის სახელის, რომელიც გირეკავთ"</string> <string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string> <string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string> <string name="consent_back" msgid="2560683030046918882">"უკან"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"თქვენი ტელეფონის აპების სტრიმინგი"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"აწარმოეთ აპების და სისტემის სხვა ფუნქციების სტრიმინგი თქვენი ტელეფონიდან"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ტელეფონი"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ტაბლეტი"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml index 67d1ab820d7b..9e5ea724c20b 100644 --- a/packages/CompanionDeviceManager/res/values-kk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> құрылғысын пайдалануға рұқсат беру керек пе?"</string> <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Бұл қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысын басқару үшін қажет. <xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасы қоңырау шалушының аты сияқты деректі синхрондау, хабарландыруларды оқу және телефон, SMS, контактілер, күнтізбе, қоңырау журналдары мен маңайдағы құрылғылар рұқсаттарын пайдалана алады."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> құрылғысын басқаруға рұқсат беру керек пе?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"көзілдірік"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Бұл қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысын басқару үшін қажет. <xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасына хабарландыруларды оқуға, телефонды, хабарларды, контактілерді, микрофон мен маңайдағы құрылғыларды пайдалануға рұқсат беріледі."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Аралық құрылғы қызметтері"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> атынан құрылғылар арасында қолданбалар трансляциялау үшін рұқсат сұрайды."</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play қызметтері"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> атынан телефондағы фотосуреттерді, медиафайлдар мен хабарландыруларды пайдалану үшін рұқсат сұрайды."</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> құрылғысына бұл әрекетті орындауға рұқсат беру керек пе?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан қолданбалар мен басқа да жүйе функцияларын маңайдағы құрылғыларға трансляциялау рұқсатын сұрап тұр."</string> <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Бұл қолданба телефон мен <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысы арасында деректі (мысалы, қоңырау шалушының атын) синхрондай алады."</string> + <string name="summary_generic" msgid="1761976003668044801">"Бұл қолданба телефон мен таңдалған құрылғы арасында деректі (мысалы, қоңырау шалушының атын) синхрондай алады."</string> <string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string> <string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string> <string name="consent_back" msgid="2560683030046918882">"Артқа"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Телефон қолданбаларын трансляциялайды."</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Қолданбалар мен басқа да жүйе функцияларын телефоннан трансляциялау"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"телефон"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"планшет"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml index 83cea128619c..445c89c7eb62 100644 --- a/packages/CompanionDeviceManager/res/values-km/strings.xml +++ b/packages/CompanionDeviceManager/res/values-km/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"កម្មវិធីគ្រប់គ្រងឧបករណ៍ដៃគូ"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលប្រើ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ឬ?"</string> <string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string> <string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោមការគ្រប់គ្រងរបស់ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="DEVICE_NAME">%1$s</xliff:g> របស់អ្នក។ <xliff:g id="APP_NAME">%2$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម ធ្វើអន្តរកម្មជាមួយការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតទូរសព្ទ, SMS, ទំនាក់ទំនង, ប្រតិទិន, កំណត់ហេតុហៅទូរសព្ទ និងឧបករណ៍នៅជិតរបស់អ្នក។"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> គ្រប់គ្រង <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ឬ?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"វ៉ែនតា"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="DEVICE_NAME">%1$s</xliff:g>។ <xliff:g id="APP_NAME">%2$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើអន្តរកម្មជាមួយការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតរបស់ទូរសព្ទ, SMS, ទំនាក់ទំនង, មីក្រូហ្វូន និងឧបករណ៍នៅជិតរបស់អ្នក។"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលប្រើព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"សេវាកម្មឆ្លងកាត់ឧបករណ៍"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក ដើម្បីបញ្ចាំងកម្មវិធីរវាងឧបករណ៍របស់អ្នក"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលមើលព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"សេវាកម្ម Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក ដើម្បីចូលប្រើរូបថត មេឌៀ និងការជូនដំណឹងរបស់ទូរសព្ទអ្នក"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"អនុញ្ញាតឱ្យ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ធ្វើសកម្មភាពនេះឬ?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> របស់អ្នក ដើម្បីចាក់ផ្សាយកម្មវិធី និងមុខងារប្រព័ន្ធផ្សេងទៀតទៅកាន់ឧបករណ៍នៅជិត"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"កម្មវិធីនេះនឹងអាចធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម រវាង <xliff:g id="DEVICE_NAME">%1$s</xliff:g> និងទូរសព្ទរបស់អ្នក"</string> + <string name="summary_generic" msgid="1761976003668044801">"កម្មវិធីនេះនឹងអាចធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម រវាងឧបករណ៍ដែលបានជ្រើសរើស និងទូរសព្ទរបស់អ្នក"</string> <string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string> <string name="consent_no" msgid="2640796915611404382">"មិនអនុញ្ញាត"</string> <string name="consent_back" msgid="2560683030046918882">"ថយក្រោយ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"ផ្សាយកម្មវិធីរបស់ទូរសព្ទអ្នក"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"ចាក់ផ្សាយកម្មវិធី និងមុខងារប្រព័ន្ធផ្សេងទៀតពីទូរសព្ទរបស់អ្នក"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ទូរសព្ទ"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ថេប្លេត"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml index 91131a709dcf..21b4cc0beae2 100644 --- a/packages/CompanionDeviceManager/res/values-kn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"ಕಂಪ್ಯಾನಿಯನ್ ಸಾಧನ ನಿರ್ವಾಹಕರು"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಅನ್ನು ಪ್ರವೇಶಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು ಈ ಆ್ಯಪ್ನ ಅಗತ್ಯವಿದೆ. ಕರೆ ಮಾಡುವವರ ಹೆಸರು, ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು, ಕ್ಯಾಲೆಂಡರ್, ಕರೆಯ ಲಾಗ್ಗಳು ಮತ್ತು ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳ ದೃಢೀಕರಣಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು <xliff:g id="APP_NAME">%2$s</xliff:g> ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? ನಿರ್ವಹಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ಗ್ಲಾಸ್ಗಳು"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು ಈ ಆ್ಯಪ್ನ ಅಗತ್ಯವಿದೆ. <xliff:g id="APP_NAME">%2$s</xliff:g> ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು, ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳ ಅನುಮತಿಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ಕ್ರಾಸ್-ಡಿವೈಸ್ ಸೇವೆಗಳು"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ಸೇವೆಗಳು"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"ನಿಮ್ಮ ಫೋನ್ನ ಫೋಟೋಗಳು, ಮೀಡಿಯಾ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"ಈ ಆ್ಯಕ್ಷನ್ ಅನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ಅನುಮತಿಸಬೇಕೇ?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳಿಗೆ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಇತರ ಸಿಸ್ಟಂ ಫೀಚರ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ರ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"ಮೊಬೈಲ್ ಫೋನ್ ಮತ್ತು <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಸಾಧನದ ನಡುವೆ, ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ"</string> + <string name="summary_generic" msgid="1761976003668044801">"ಮೊಬೈಲ್ ಫೋನ್ ಮತ್ತು ಆಯ್ಕೆಮಾಡಿದ ಸಾಧನದ ನಡುವೆ, ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ"</string> <string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string> <string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string> <string name="consent_back" msgid="2560683030046918882">"ಹಿಂದೆ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"ನಿಮ್ಮ ಫೋನ್ನ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಿ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"ನಿಮ್ಮ ಫೋನ್ನಿಂದ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಇತರ ಸಿಸ್ಟಂ ಫೀಚರ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಿ"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ಫೋನ್"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ಟ್ಯಾಬ್ಲೆಟ್"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml index 5b9c42981fea..be2c70d1be41 100644 --- a/packages/CompanionDeviceManager/res/values-ko/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"부속 기기 관리자"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 액세스하도록 허용하시겠습니까?"</string> <string name="profile_name_watch" msgid="576290739483672360">"시계"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 기기를 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 정보(예: 발신자 이름)를 동기화하고, 알림과 상호작용하고, 전화, SMS, 연락처, 캘린더, 통화 기록 및 근처 기기에 액세스할 수 있게 됩니다."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? 기기를 관리하도록 허용"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"안경"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 기기를 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 알림과 상호작용하고 내 전화, SMS, 연락처, 마이크, 근처 기기에 대한 권한을 갖게 됩니다."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>이 휴대전화의 이 정보에 액세스하도록 허용합니다."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 대신 기기 간에 앱을 스트리밍할 수 있는 권한을 요청하고 있습니다."</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 앱이 휴대전화에서 이 정보에 액세스하도록 허용"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 서비스"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 대신 휴대전화의 사진, 미디어, 알림에 액세스할 수 있는 권한을 요청하고 있습니다."</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> 기기가 이 작업을 수행하도록 허용하시겠습니까?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 근처 기기로 앱 및 기타 시스템 기능을 스트리밍할 권한을 요청하고 있습니다."</string> <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"이 앱에서 휴대전화와 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 간에 정보(예: 발신자 이름)를 동기화할 수 있게 됩니다."</string> + <string name="summary_generic" msgid="1761976003668044801">"이 앱에서 휴대전화와 선택한 기기 간에 정보(예: 발신자 이름)를 동기화할 수 있게 됩니다."</string> <string name="consent_yes" msgid="8344487259618762872">"허용"</string> <string name="consent_no" msgid="2640796915611404382">"허용 안함"</string> <string name="consent_back" msgid="2560683030046918882">"뒤로"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"휴대전화의 앱을 스트리밍합니다."</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"내 휴대전화의 앱 및 기타 시스템 기능 스트리밍"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"스마트폰"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"태블릿"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml index 2f9957741fba..47a1da52b2cb 100644 --- a/packages/CompanionDeviceManager/res/values-ky/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүнө кирүүгө уруксат бересизби?"</string> <string name="profile_name_watch" msgid="576290739483672360">"саат"</string> <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> тарабынан башкарылсын"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Бул колдонмо <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздү башкаруу үчүн керек. <xliff:g id="APP_NAME">%2$s</xliff:g> маалыматты шайкештирип, мисалы, билдирмелериңизди көрүп, телефонуңуз, SMS билдирүүлөр, байланыштар, жылнаама, чалуулар тизмеси жана жакын жердеги түзмөктөргө болгон уруксаттарды пайдалана алат."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүн тескөөгө уруксат бересизби?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"көз айнектер"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Бул колдонмо <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүн башкаруу үчүн керек. <xliff:g id="APP_NAME">%2$s</xliff:g> билдирмелериңизди көрүп, телефонуңуз, SMS билдирүүлөр, Байланыштар, Микрофон жана Жакын жердеги түзмөктөргө болгон уруксаттарды пайдалана алат."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрүңүздүн ортосунда колдонмолорду өткөрүүгө уруксат сурап жатат"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play кызматтары"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздүн атынан телефондогу сүрөттөрдү, медиа файлдарды жана билдирмелерди колдонууга уруксат сурап жатат"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> түзмөгүнө бул аракетти аткарууга уруксат бересизби?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан жакын жердеги түзмөктөрдө колдонмолорду жана тутумдун башка функцияларын алып ойнотууга уруксат сурап жатат"</string> <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Бул колдонмо маалыматты шайкештире алат, мисалы, чалып жаткан кишинин атын телефон жана <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгү менен шайкештирет"</string> + <string name="summary_generic" msgid="1761976003668044801">"Бул колдонмо маалыматты шайкештире алат, мисалы, чалып жаткан кишинин атын телефон жана тандалган түзмөк менен шайкештирет"</string> <string name="consent_yes" msgid="8344487259618762872">"Ооба"</string> <string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string> <string name="consent_back" msgid="2560683030046918882">"Артка"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Телефондогу колдонмолорду алып ойнотуу"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Телефонуңуздагы колдонмолорду жана тутумдун башка функцияларын алып ойнотуу"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"телефон"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"планшет"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml index 53995be29d43..3782d25f3e42 100644 --- a/packages/CompanionDeviceManager/res/values-lo/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"ຕົວຈັດການອຸປະກອນປະກອບ"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ໃຫ້ເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ບໍ?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string> <string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"ຕ້ອງໃຊ້ແອັບນີ້ເພື່ອຈັດການ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຂອງທ່ານ. <xliff:g id="APP_NAME">%2$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ, ການໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ສິດເຂົ້າເຖິງໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່, ປະຕິທິນ, ບັນທຶກການໂທ ແລະ ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງຂອງທ່ານ."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ຈັດການ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ບໍ?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ແວ່ນຕາ"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"ຕ້ອງໃຊ້ແອັບນີ້ເພື່ອຈັດການ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ການອະນຸຍາດສິດເຂົ້າເຖິງໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່, ໄມໂຄຣໂຟນ ແລະ ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງຂອງທ່ານ."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ບໍລິການຂ້າມອຸປະກອນ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ເພື່ອສະຕຣີມແອັບລະຫວ່າງອຸປະກອນຂອງທ່ານ"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"ບໍລິການ Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ເພື່ອເຂົ້າເຖິງຮູບພາບ, ມີເດຍ ແລະ ການແຈ້ງເຕືອນຂອງໂທລະສັບທ່ານ"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"ອະນຸຍາດ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ເພື່ອດຳເນີນຄຳສັ່ງນີ້ບໍ?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກໍາລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ຂອງທ່ານເພື່ອສະຕຣີມແອັບ ແລະ ຄຸນສົມບັດລະບົບອື່ນໆໄປຫາອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"ແອັບນີ້ຈະສາມາດຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ, ລະຫວ່າງໂທລະສັບຂອງທ່ານ ແລະ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ໄດ້"</string> + <string name="summary_generic" msgid="1761976003668044801">"ແອັບນີ້ຈະສາມາດຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ, ລະຫວ່າງໂທລະສັບຂອງທ່ານ ແລະ ອຸປະກອນທີ່ເລືອກໄວ້ໄດ້"</string> <string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string> <string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string> <string name="consent_back" msgid="2560683030046918882">"ກັບຄືນ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"ສະຕຣີມແອັບຂອງໂທລະສັບທ່ານ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"ສະຕຣີມແອັບ ແລະ ຄຸນສົມບັດລະບົບອື່ນໆຈາກໂທລະສັບຂອງທ່ານ"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ໂທລະສັບ"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ແທັບເລັດ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml index 56cfcb8e813f..8f8572b14f7c 100644 --- a/packages/CompanionDeviceManager/res/values-lt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string> <string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> (pasirinkite)"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ši programa reikalinga norint tvarkyti jūsų įrenginį „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“. Programai „<xliff:g id="APP_NAME">%2$s</xliff:g>“ bus leidžiama sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, sąveikauti su jūsų pranešimais ir pasiekti jūsų leidimus „Telefonas“, „SMS“, „Kontaktai“, „Kalendorius“, „Skambučių žurnalai“ ir „Įrenginiai netoliese."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> valdyti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"akiniai"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ši programa reikalinga norint tvarkyti įrenginį „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“. Programai „<xliff:g id="APP_NAME">%2$s</xliff:g>“ bus leidžiama sąveikauti su jūsų pranešimais ir pasiekti jūsų leidimus „Telefonas“, „SMS“, „Kontaktai“, „Mikrofonas“ ir „Įrenginiai netoliese“."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti šią informaciją iš jūsų telefono"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Pasl. keliuose įrenginiuose"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas iš vieno įrenginio į kitą"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti šią informaciją iš jūsų telefono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"„Google Play“ paslaugos"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>“ vardu, kad galėtų pasiekti telefono nuotraukas, mediją ir pranešimus"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Leisti <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> atlikti šį veiksmą?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas ir kitas sistemos funkcijas įrenginiams netoliese"</string> <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ši programa galės sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, su jūsų telefonu ir įrenginiu „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string> + <string name="summary_generic" msgid="1761976003668044801">"Ši programa galės sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, su jūsų telefonu ir pasirinktu įrenginiu"</string> <string name="consent_yes" msgid="8344487259618762872">"Leisti"</string> <string name="consent_no" msgid="2640796915611404382">"Neleisti"</string> <string name="consent_back" msgid="2560683030046918882">"Atgal"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefono programų perdavimas srautu"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Srautu perduokite programas ir kitas sistemos funkcijas iš telefono"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"planšetiniame kompiuteryje"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml index b6dcd2da8958..905df48c8933 100644 --- a/packages/CompanionDeviceManager/res/values-lv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Palīgierīču pārzinis"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Vai atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt ierīcei <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string> <string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Šī lietotne ir nepieciešama jūsu ierīces (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) pārvaldībai. <xliff:g id="APP_NAME">%2$s</xliff:g> drīkstēs sinhronizēt informāciju (piemēram, zvanītāja vārdu), mijiedarboties ar jūsu paziņojumiem un piekļūt atļaujām Tālrunis, Īsziņas, Kontaktpersonas, Kalendārs, Zvanu žurnāli un Tuvumā esošas ierīces."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vai atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt ierīcei <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"brilles"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Šī lietotne ir nepieciešama šādas ierīces pārvaldībai: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> drīkstēs mijiedarboties ar jūsu paziņojumiem un piekļūt atļaujām Tālrunis, Īsziņas, Kontaktpersonas, Mikrofons un Tuvumā esošas ierīces."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt šai informācijai no jūsu tālruņa"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Vairāku ierīču pakalpojumi"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju straumēt lietotnes starp jūsu ierīcēm šīs ierīces vārdā: <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt šai informācijai no jūsu tālruņa"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play pakalpojumi"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju piekļūt jūsu tālruņa fotoattēliem, multivides saturam un paziņojumiem šīs ierīces vārdā: <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vai atļaut ierīcei <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> veikt šo darbību?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju tuvumā esošās ierīcēs straumēt lietotnes un citas sistēmas funkcijas šīs ierīces vārdā: <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Šī lietotne varēs sinhronizēt informāciju (piemēram, zvanītāja vārdu) starp jūsu tālruni un šo ierīci: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Šī lietotne varēs sinhronizēt informāciju (piemēram, zvanītāja vārdu) starp jūsu tālruni un izvēlēto ierīci"</string> <string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string> <string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string> <string name="consent_back" msgid="2560683030046918882">"Atpakaļ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Straumēt jūsu tālruņa lietotnes"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"No sava tālruņa straumējiet lietotnes un citas sistēmas funkcijas"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"tālrunī"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"planšetdatorā"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml index 8b4c9e1c5072..414ecee88766 100644 --- a/packages/CompanionDeviceManager/res/values-mk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Ќе дозволите <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string> <string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Апликацијава е потребна за управување со вашиот <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ќе може да ги синхронизира податоците како што се имињата на јавувачите, да остварува интеракција со известувањата и да пристапува до дозволите за „Телефон“, SMS, „Контакти“, „Календар“, „Евиденција на повици“ и „Уреди во близина“."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Ќе дозволите <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управува со <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"очила"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Апликацијава е потребна за управување со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за „Телефон“, SMS, „Контакти“, „Микрофон“ и „Уреди во близина“."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Овозможете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до овие податоци на телефонот"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Повеќенаменски услуги"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за да стримува апликации помеѓу вашите уреди"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Дозволете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до овие податоци на телефонот"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Услуги на Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за да пристапува до фотографиите, аудиовизуелните содржини и известувањата на телефонот"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ќе дозволите <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> да го преземе ова дејство?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_NAME">%2$s</xliff:g> за да стримува апликации и други системски карактеристики на уредите во близина"</string> <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Оваа апликација ќе може да ги синхронизира податоците како што се имињата на јавувачите помеѓу вашиот телефон и <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Оваа апликација ќе може да ги синхронизира податоците како што се имињата на јавувачите помеѓу вашиот телефон и избраниот уред"</string> <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string> <string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string> <string name="consent_back" msgid="2560683030046918882">"Назад"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Стримувајте ги апликациите на телефонот"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Апликации за стриминг и други системски карактеристики од вашиот телефон"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"телефон"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"таблет"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml index f86897c472b5..9aab050d8f33 100644 --- a/packages/CompanionDeviceManager/res/values-ml/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"കമ്പാനിയൻ ഉപകരണ മാനേജർ"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കണോ?"</string> <string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ സമന്വയിപ്പിക്കുന്നതിനും നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, Contacts, Calendar, കോൾ ചരിത്രം, സമീപമുള്ള ഉപകരണങ്ങളുടെ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%2$s</xliff:g> ആപ്പിനെ അനുവദിക്കും."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? മാനേജ് ചെയ്യാൻ, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ഗ്ലാസുകൾ"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. നിങ്ങളുടെ അറിയിപ്പുകളുമായി ഇടപഴകാനും ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, മൈക്രോഫോൺ, സമീപമുള്ള ഉപകരണങ്ങളുടെ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ആപ്പിനെ അനുവദിക്കുക"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ക്രോസ്-ഉപകരണ സേവനങ്ങൾ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"നിങ്ങളുടെ ഉപകരണങ്ങളിൽ ഒന്നിൽ നിന്ന് അടുത്തതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ആപ്പിനെ അനുവദിക്കുക"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play സേവനങ്ങൾ"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"നിങ്ങളുടെ ഫോണിലെ ഫോട്ടോകൾ, മീഡിയ, അറിയിപ്പുകൾ എന്നിവ ആക്സസ് ചെയ്യാൻ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"ഈ പ്രവർത്തനം നടത്താൻ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കണോ?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"സമീപമുള്ള ഉപകരണങ്ങളിൽ ആപ്പുകളും മറ്റ് സിസ്റ്റം ഫീച്ചറുകളും സ്ട്രീം ചെയ്യാൻ നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്നതിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ നിങ്ങളുടെ ഫോണിനും <xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതിനും ഇടയിൽ സമന്വയിപ്പിക്കുന്നതിന് ഈ ആപ്പിന് കഴിയും"</string> + <string name="summary_generic" msgid="1761976003668044801">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ നിങ്ങളുടെ ഫോണിനും തിരഞ്ഞെടുത്ത ഉപകരണത്തിനും ഇടയിൽ സമന്വയിപ്പിക്കുന്നതിന് ഈ ആപ്പിന് കഴിയും"</string> <string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string> <string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string> <string name="consent_back" msgid="2560683030046918882">"മടങ്ങുക"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"നിങ്ങളുടെ ഫോണിലെ ആപ്പുകൾ സ്ട്രീം ചെയ്യുക"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ആപ്പുകളും മറ്റ് സിസ്റ്റം ഫീച്ചറുകളും സ്ട്രീം ചെയ്യാം"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ഫോൺ"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ടാബ്ലെറ്റ്"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml index 1d29cdef2c28..6be7212683fb 100644 --- a/packages/CompanionDeviceManager/res/values-mn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-д <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д хандахыг зөвшөөрөх үү?"</string> <string name="profile_name_watch" msgid="576290739483672360">"цаг"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Энэ апп таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="APP_NAME">%2$s</xliff:g>-д залгаж буй хүний нэр зэрэг мэдээллийг синк хийх, таны мэдэгдэлтэй харилцан үйлдэл хийх, Утас, SMS, Харилцагчид, Календарь, Дуудлагын жагсаалт болон Ойролцоох төхөөрөмжүүдийн зөвшөөрөлд хандахыг зөвшөөрнө."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г удирдахыг зөвшөөрөх үү?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"нүдний шил"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Энэ апп <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="APP_NAME">%2$s</xliff:g>-д таны мэдэгдэлтэй харилцан үйлдэл хийх, Утас, SMS, Харилцагчид, Микрофон болон Ойролцоох төхөөрөмжүүдийн зөвшөөрөлд хандахыг зөвшөөрнө."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Таны төхөөрөмжүүд хооронд апп дамжуулахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н өмнөөс зөвшөөрөл хүсэж байна"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play үйлчилгээ"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Таны утасны зураг, медиа болон мэдэгдэлд хандахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н өмнөөс зөвшөөрөл хүсэж байна"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>-д энэ үйлдлийг хийхийг зөвшөөрөх үү?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-н өмнөөс аппууд болон системийн бусад онцлогийг ойролцоох төхөөрөмжүүд рүү дамжуулах зөвшөөрөл хүсэж байна"</string> <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Энэ апп залгаж буй хүний нэр зэрэг мэдээллийг таны утас болон <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-н хооронд синк хийх боломжтой болно"</string> + <string name="summary_generic" msgid="1761976003668044801">"Энэ апп залгаж буй хүний нэр зэрэг мэдээллийг таны утас болон сонгосон төхөөрөмжийн хооронд синк хийх боломжтой болно"</string> <string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string> <string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string> <string name="consent_back" msgid="2560683030046918882">"Буцах"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Утасныхаа аппуудыг дамжуулаарай"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Утаснаасаа аппууд болон системийн бусад онцлогийг дамжуулаарай"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"утас"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"таблет"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml index 9c082a46584b..c66d6fff1f67 100644 --- a/packages/CompanionDeviceManager/res/values-mr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> अॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string> <string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"तुमचे <xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करण्याची, तुमच्या सूचनांसोबत संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क, कॅलेंडर, कॉल लॉग व जवळपासच्या डिव्हाइसच्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> व्यवस्थापित करण्याची अनुमती द्यायची आहे?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"Glasses"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला तुमच्या सूचनांसोबत संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क, मायक्रोफोन व जवळपासच्या डिव्हाइसच्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला ही माहिती तुमच्या फोनवरून अॅक्सेस करण्यासाठी अनुमती द्या"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिव्हाइस सेवा"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"तुमच्या डिव्हाइसदरम्यान ॲप्स स्ट्रीम करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला ही माहिती तुमच्या फोनवरून अॅक्सेस करण्यासाठी अनुमती द्या"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवा"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"तुमच्या फोनमधील फोटो, मीडिया आणि सूचना ॲक्सेस करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ला ही कृती करण्याची अनुमती द्यायची आहे का?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे जवळपासच्या डिव्हाइसवर अॅप्स आणि इतर सिस्टीम वैशिष्ट्ये स्ट्रीम करण्यासाठी तुमच्या <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करा"</string> <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"हे ॲप तुमचा फोन आणि <xliff:g id="DEVICE_NAME">%1$s</xliff:g> दरम्यान कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करू शकेल"</string> + <string name="summary_generic" msgid="1761976003668044801">"हे ॲप तुमचा फोन आणि निवडलेल्या डिव्हाइसदरम्यान कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करू शकेल"</string> <string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string> <string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string> <string name="consent_back" msgid="2560683030046918882">"मागे जा"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"तुमच्या फोनवरील ॲप्स स्ट्रीम करा"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"तुमच्या फोनवरून अॅप्स आणि इतर सिस्टीम वैशिष्ट्ये स्ट्रीम करा"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"फोन"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"टॅबलेट"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml index 69f3c85de963..b554f5af63e5 100644 --- a/packages/CompanionDeviceManager/res/values-ms/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Pengurus Peranti Rakan"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string> <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Apl ini diperlukan untuk mengurus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda. <xliff:g id="APP_NAME">%2$s</xliff:g> akan dibenarkan untuk menyegerakkan maklumat seperti nama individu yang memanggil, berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan, Kalendar, Log panggilan dan Peranti berdekatan anda."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengurus <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"cermin mata"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Apl ini diperlukan untuk mengurus <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan dibenarkan untuk berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan, Mikrofon dan Peranti berdekatan anda."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses maklumat ini daripada telefon anda"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda untuk menstrim apl antara peranti anda"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses maklumat ini daripada telefon anda"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Perkhidmatan Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda untuk mengakses foto, media dan pemberitahuan telefon anda"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Benarkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> mengambil tindakan ini?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> anda untuk menstrim apl dan ciri sistem yang lain pada peranti berdekatan"</string> <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Apl ini akan dapat menyegerakkan maklumat seperti nama individu yang memanggil, antara telefon anda dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Apl ini akan dapat menyegerakkan maklumat seperti nama individu yang memanggil, antara telefon anda dengan peranti yang dipilih"</string> <string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string> <string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string> <string name="consent_back" msgid="2560683030046918882">"Kembali"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Strim apl telefon anda"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Strim apl dan ciri sistem yang lain daripada telefon anda"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml index ebd63574d95e..32230fffdff7 100644 --- a/packages/CompanionDeviceManager/res/values-my/strings.xml +++ b/packages/CompanionDeviceManager/res/values-my/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"တွဲဖက်ကိရိယာ မန်နေဂျာ"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အား <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>? သုံးခွင့်ပြုခြင်း"</string> <string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"သင်၏ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်လိုအပ်သည်။ ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်ရန်၊ သင်၏ဖုန်း၊ SMS စာတိုစနစ်၊ အဆက်အသွယ်များ၊ ပြက္ခဒိန်၊ ခေါ်ဆိုမှတ်တမ်းနှင့် အနီးတစ်ဝိုက်ရှိ စက်များဆိုင်ရာ ခွင့်ပြုချက်များသုံးရန်၊ အကြောင်းကြားချက်များနှင့် ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> ကို ခွင့်ပြုမည်။"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကို <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အား စီမံခွင့်ပြုမလား။"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"မျက်မှန်"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်လိုအပ်သည်။ သင်၏ဖုန်း၊ SMS စာတိုစနစ်၊ အဆက်အသွယ်များ၊ မိုက်ခရိုဖုန်းနှင့် အနီးတစ်ဝိုက်ရှိ စက်များဆိုင်ရာ ခွင့်ပြုချက်များသုံးရန်၊ အကြောင်းကြားချက်များနှင့် ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> ကို ခွင့်ပြုမည်။"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"စက်များကြားသုံး ဝန်ဆောင်မှုများ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင်၏စက်များအကြား အက်ပ်များတိုက်ရိုက်လွှင့်ရန် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အား သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုခြင်း"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ဝန်ဆောင်မှုများ"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့်ဖုန်း၏ ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များသုံးရန် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ကို ဤသို့လုပ်ဆောင်ခွင့်ပြုမလား။"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် အနီးတစ်ဝိုက်ရှိ အက်ပ်များနှင့် အခြားစနစ်အင်္ဂါရပ်များကို တိုက်ရိုက်ဖွင့်ရန် သင့် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string> <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"ဤအက်ပ်သည် သင့်ဖုန်းနှင့် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> အကြား ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်နိုင်ပါမည်"</string> + <string name="summary_generic" msgid="1761976003668044801">"ဤအက်ပ်သည် သင့်ဖုန်းနှင့် ရွေးထားသောစက်အကြား ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်နိုင်ပါမည်"</string> <string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string> <string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string> <string name="consent_back" msgid="2560683030046918882">"နောက်သို့"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"သင့်ဖုန်းရှိအက်ပ်များကို တိုက်ရိုက်ဖွင့်နိုင်သည်"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"သင့်ဖုန်းမှ အက်ပ်များနှင့် အခြားစနစ်အင်္ဂါရပ်များကို တိုက်ရိုက်ဖွင့်သည်"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ဖုန်း"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"တက်ဘလက်"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml index 4801c8ce8a62..5cffcbd44d8c 100644 --- a/packages/CompanionDeviceManager/res/values-nb/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"klokke"</string> <string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Denne appen kreves for å administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillatelse til å synkronisere informasjon som navnet til noen som ringer, og samhandle med varslene dine, og får tilgang til tillatelsene for telefon, SMS, kontakter, kalender, samtalelogger og enheter i nærheten."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du la <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administrere <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"briller"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Denne appen kreves for å administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilgang til varslene dine og får tillatelsene for telefon, SMS, kontakter, mikrofon og enheter i nærheten."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester på flere enheter"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme apper mellom enhetene dine, på vegne av <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å få tilgang til bilder, medier og varsler på telefonen din, på vegne av <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vil du la <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> gjøre dette?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til å strømme apper og andre systemfunksjoner til enheter i nærheten"</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Denne appen kan synkronisere informasjon som navnet til noen som ringer, mellom telefonen og <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Denne appen kan synkronisere informasjon som navnet til noen som ringer, mellom telefonen og den valgte enheten"</string> <string name="consent_yes" msgid="8344487259618762872">"Tillat"</string> <string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string> <string name="consent_back" msgid="2560683030046918882">"Tilbake"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Strøm appene på telefonen"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Strøm apper og andre systemfunksjoner fra telefonen"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"nettbrett"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml index 71b7695ab4b9..b17503a9364b 100644 --- a/packages/CompanionDeviceManager/res/values-ne/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"सहयोगी डिभाइसको प्रबन्धक"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> प्रयोग गर्ने अनुमति दिने हो?"</string> <string name="profile_name_watch" msgid="576290739483672360">"घडी"</string> <string name="chooser_title" msgid="2262294130493605839">"आफूले <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"तपाईंको <xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापन गर्न यो एप चाहिन्छ। <xliff:g id="APP_NAME">%2$s</xliff:g> लाई कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्ने, तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट, पात्रो, कल लग तथा नजिकैका डिभाइससम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> व्यवस्थापन गर्ने अनुमति दिने हो?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"चस्मा"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापन गर्न यो एप चाहिन्छ। <xliff:g id="APP_NAME">%2$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट, माइक्रोफोन तथा नजिकैका डिभाइससम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रस-डिभाइस सेवाहरू"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> को तर्फबाट तपाईंका कुनै एउटा डिभाइसबाट अर्को डिभाइसमा एप स्ट्रिम गर्ने अनुमति माग्दै छ"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> को तर्फबाट तपाईंको फोनमा भएका फोटो, मिडिया र सूचनाहरू हेर्ने तथा प्रयोग गर्ने अनुमति माग्दै छ"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> लाई यो कार्य गर्ने अनुमति दिने हो?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट नजिकैका डिभाइसहरूमा एप र सिस्टमका अन्य सुविधाहरू स्ट्रिम गर्ने अनुमति माग्दै छ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"यो एपले तपाईंको फोन र तपाईंले छनौट गर्ने <xliff:g id="DEVICE_NAME">%1$s</xliff:g> का बिचमा कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्न सक्ने छ।"</string> + <string name="summary_generic" msgid="1761976003668044801">"यो एपले तपाईंको फोन र तपाईंले छनौट गर्ने डिभाइसका बिचमा कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्न सक्ने छ।"</string> <string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string> <string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string> <string name="consent_back" msgid="2560683030046918882">"पछाडि"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"आफ्नो फोनका एपहरू प्रयोग गर्नुहोस्"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"आफ्नो फोनबाट एप र सिस्टमका अन्य सुविधाहरू स्ट्रिम गर्नुहोस्"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"फोन"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ट्याब्लेट"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml index d953a951f288..add068406984 100644 --- a/packages/CompanionDeviceManager/res/values-nl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string> <string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Deze app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> mag informatie (zoals de naam van iemand die belt) synchroniseren, mag interactie hebben met je meldingen en krijgt toegang tot de rechten Telefoon, Sms, Contacten, Agenda, Gesprekslijsten en Apparaten in de buurt."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toestaan <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> te beheren?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"brillen"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Deze app is nodig om <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> mag interactie hebben met je meldingen en krijgt toegang tot de rechten Telefoon, Sms, Contacten, Microfoon en Apparaten in de buurt."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot deze informatie op je telefoon"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device-services"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toestemming om apps te streamen tussen je apparaten"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot deze informatie op je telefoon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toegang tot de foto\'s, media en meldingen van je telefoon"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Toestaan dat <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> deze actie uitvoert?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens je <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps en andere systeemfuncties naar apparaten in de buurt te streamen"</string> <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Deze app kan informatie, zoals de naam van iemand die belt, synchroniseren tussen je telefoon en <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Deze app kan informatie, zoals de naam van iemand die belt, synchroniseren tussen je telefoon en het gekozen apparaat"</string> <string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string> <string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string> <string name="consent_back" msgid="2560683030046918882">"Terug"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream de apps van je telefoon"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Apps en andere systeemfuncties streamen vanaf je telefoon"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefoon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml index f9a5c304227a..12c8e6c4e71f 100644 --- a/packages/CompanionDeviceManager/res/values-or/strings.xml +++ b/packages/CompanionDeviceManager/res/values-or/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"ସହଯୋଗୀ ଡିଭାଇସ୍ ପରିଚାଳକ"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଏହି ଆପ ଆବଶ୍ୟକ। କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବା, ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କର ଫୋନ, SMS, କଣ୍ଟାକ୍ଟ, କେଲେଣ୍ଡର, କଲ ଲଗ ଓ ଆଖପାଖର ଡିଭାଇସ ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%2$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ଚଷମା"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଏହି ଆପ ଆବଶ୍ୟକ। ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କର ଫୋନ, SMS, କଣ୍ଟାକ୍ଟ, ମାଇକ୍ରୋଫୋନ ଓ ଆଖପାଖର ଡିଭାଇସ ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%2$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"କ୍ରସ-ଡିଭାଇସ ସେବାଗୁଡ଼ିକ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କର <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ସେବାଗୁଡ଼ିକ"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"ଆପଣଙ୍କ ଫୋନର ଫଟୋ, ମିଡିଆ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କର <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"ଏହି ପଦକ୍ଷେପ ନେବା ପାଇଁ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"ଆଖପାଖର ଡିଭାଇସଗୁଡ଼ିକରେ ଆପ୍ସ ଏବଂ ଅନ୍ୟ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"ଆପଣଙ୍କ ଫୋନ ଏବଂ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ମଧ୍ୟରେ, କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏହି ଆପ ସକ୍ଷମ ହେବ"</string> + <string name="summary_generic" msgid="1761976003668044801">"ଆପଣଙ୍କ ଫୋନ ଏବଂ ବଛାଯାଇଥିବା ଡିଭାଇସ ମଧ୍ୟରେ, କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏହି ଆପ ସକ୍ଷମ ହେବ"</string> <string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string> <string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string> <string name="consent_back" msgid="2560683030046918882">"ପଛକୁ ଫେରନ୍ତୁ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"ଆପଣଙ୍କ ଫୋନର ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରନ୍ତୁ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"ଆପଣଙ୍କ ଫୋନରୁ ଆପ୍ସ ଏବଂ ଅନ୍ୟ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକୁ ଷ୍ଟ୍ରିମ କରନ୍ତୁ"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ଫୋନ"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ଟାବଲେଟ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml index b6b8b290f584..a99d764c260a 100644 --- a/packages/CompanionDeviceManager/res/values-pa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"ਸੰਬੰਧੀ ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਕ"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"ਇਹ ਐਪ ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="APP_NAME">%2$s</xliff:g> ਨੂੰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰਨ, ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕਾਂ, ਕੈਲੰਡਰ, ਕਾਲ ਲੌਗਾਂ ਅਤੇ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ।"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ਐਨਕਾਂ"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"ਇਹ ਐਪ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="APP_NAME">%2$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕਾਂ, ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ।"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ਕ੍ਰਾਸ-ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ਸੇਵਾਵਾਂ"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੀਆਂ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"ਕੀ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ਨੂੰ ਇਹ ਕਾਰਵਾਈ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ \'ਤੇ ਐਪਾਂ ਅਤੇ ਹੋਰ ਸਿਸਟਮ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ ਅਤੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਵਿਚਕਾਰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰ ਸਕੇਗੀ"</string> + <string name="summary_generic" msgid="1761976003668044801">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ ਅਤੇ ਚੁਣੇ ਗਏ ਡੀਵਾਈਸ ਵਿਚਕਾਰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰ ਸਕੇਗੀ"</string> <string name="consent_yes" msgid="8344487259618762872">"ਆਗਿਆ ਦਿਓ"</string> <string name="consent_no" msgid="2640796915611404382">"ਆਗਿਆ ਨਾ ਦਿਓ"</string> <string name="consent_back" msgid="2560683030046918882">"ਪਿੱਛੇ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"ਆਪਣੇ ਫ਼ੋਨ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰੋ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"ਆਪਣੇ ਫ਼ੋਨ ਤੋਂ ਐਪਾਂ ਅਤੇ ਹੋਰ ਸਿਸਟਮ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰੋ"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ਫ਼ੋਨ"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ਟੈਬਲੈੱਟ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml index dafdb631b5a3..a00e5bfc04ef 100644 --- a/packages/CompanionDeviceManager/res/values-pl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Menedżer urządzeń towarzyszących"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Zezwolić na dostęp aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> do tego urządzenia (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)?"</string> <string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string> <string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ta aplikacja jest niezbędna do zarządzania urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła synchronizować informacje takie jak nazwa osoby dzwoniącej, korzystać z powiadomień oraz uprawnień dotyczących telefonu, SMS-ów, kontaktów, kalendarza, rejestrów połączeń i Urządzeń w pobliżu."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Zezwolić na dostęp aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> do urządzenia <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"Okulary"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ta aplikacja jest niezbędna do zarządzania urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła wchodzić w interakcję z powiadomieniami i korzystać z uprawnień dotyczących telefonu, SMS-ów, kontaktów, mikrofonu oraz urządzeń w pobliżu."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól urządzeniu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do tych informacji na Twoim telefonie"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> o uprawnienia dotyczące strumieniowego odtwarzania treści z aplikacji na innym urządzeniu"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Zezwól aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do tych informacji na Twoim telefonie"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Usługi Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> o uprawnienia dotyczące dostępu do zdjęć, multimediów i powiadomień na telefonie"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Zezwolić urządzeniu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> na wykonanie tego działania?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o uprawnienia do strumieniowego odtwarzania treści i innych funkcji systemowych na urządzeniach w pobliżu"</string> <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ta aplikacja może synchronizować informacje takie jak nazwa osoby dzwoniącej między Twoim telefonem i urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Ta aplikacja może synchronizować informacje takie jak nazwa osoby dzwoniącej między Twoim telefonem i wybranym urządzeniem"</string> <string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string> <string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string> <string name="consent_back" msgid="2560683030046918882">"Wstecz"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Odtwarzaj strumieniowo aplikacje z telefonu"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Aplikacje do odtwarzania strumieniowego i inne funkcje systemowe na Twoim telefonie"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml index 221456704814..f482146975e7 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"O app <xliff:g id="APP_NAME">%2$s</xliff:g> é necessário para gerenciar o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Ele poderá sincronizar informações, como o nome de quem está ligando, interagir com suas notificações e acessar as permissões do Telefone, SMS, contatos, agenda, registro de chamadas e dispositivos por perto."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gerencie o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"óculos"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"O app <xliff:g id="APP_NAME">%2$s</xliff:g> é necessário para gerenciar o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Ele poderá interagir com suas notificações e acessar suas permissões de telefone, SMS, contatos, microfone e dispositivos por perto."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone."</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize essa ação?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e de outros recursos do sistema para dispositivos por perto"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string> <string name="consent_back" msgid="2560683030046918882">"Voltar"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Fazer transmissão dos apps no seu smartphone"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Faça streaming de apps e outros recursos do sistema pelo smartphone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"smartphone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml index 738fe4addeb6..1f375f53629e 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos associados"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Esta app é necessária para gerir o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A app <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder sincronizar informações, como o nome do autor de uma chamada, interagir com as suas notificações e aceder às autorizações do Telemóvel, SMS, Contactos, Calendário, Registos de chamadas e Dispositivos próximos."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça a gestão do dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"óculos"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Esta app é necessária para gerir o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A app <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com as suas notificações e aceder às autorizações do Telemóvel, SMS, Contactos, Microfone e Dispositivos próximos."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer stream de apps entre os seus dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permita que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Serviços do Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para aceder às fotos, ao conteúdo multimédia e às notificações do seu telemóvel"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize esta ação?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de apps e outras funcionalidades do sistema para dispositivos próximos"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, entre o telemóvel e o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, entre o telemóvel e o dispositivo escolhido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string> <string name="consent_back" msgid="2560683030046918882">"Voltar"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Faça stream das apps do telemóvel"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Faça stream de apps e outras funcionalidades do sistema a partir do telemóvel"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telemóvel"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml index 221456704814..f482146975e7 100644 --- a/packages/CompanionDeviceManager/res/values-pt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"O app <xliff:g id="APP_NAME">%2$s</xliff:g> é necessário para gerenciar o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Ele poderá sincronizar informações, como o nome de quem está ligando, interagir com suas notificações e acessar as permissões do Telefone, SMS, contatos, agenda, registro de chamadas e dispositivos por perto."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gerencie o dispositivo <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"óculos"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"O app <xliff:g id="APP_NAME">%2$s</xliff:g> é necessário para gerenciar o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Ele poderá interagir com suas notificações e acessar suas permissões de telefone, SMS, contatos, microfone e dispositivos por perto."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone."</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize essa ação?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e de outros recursos do sistema para dispositivos por perto"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string> <string name="consent_back" msgid="2560683030046918882">"Voltar"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Fazer transmissão dos apps no seu smartphone"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Faça streaming de apps e outros recursos do sistema pelo smartphone"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"smartphone"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml index cf4275379897..67b53e49dd1a 100644 --- a/packages/CompanionDeviceManager/res/values-ro/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Manager de dispozitiv Companion"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Permiți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze dispozitivul <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string> <string name="chooser_title" msgid="2262294130493605839">"Alege un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să sincronizeze informații, cum ar fi numele unui apelant, să interacționeze cu notificările tale și să îți acceseze permisiunile pentru Telefon, SMS, Agendă, Calendar, Jurnale de apeluri și Dispozitive din apropiere."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Permiți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să gestioneze <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"ochelari"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu notificările tale și să-ți acceseze permisiunile pentru Telefon, SMS, Agendă, Microfon și Dispozitive din apropiere."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Permite ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze aceste informații de pe telefon"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a reda în stream aplicații între dispozitivele tale"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permite ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze aceste informații de pe telefon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Servicii Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a accesa fotografiile, conținutul media și notificările de pe telefon"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permiți ca <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> să realizeze această acțiune?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a reda în stream conținut din aplicații și alte funcții de sistem pe dispozitivele din apropiere"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, între telefonul tău și <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, între telefonul tău și dispozitivul ales"</string> <string name="consent_yes" msgid="8344487259618762872">"Permite"</string> <string name="consent_no" msgid="2640796915611404382">"Nu permite"</string> <string name="consent_back" msgid="2560683030046918882">"Înapoi"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Să redea în stream aplicațiile telefonului"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Redă în stream conținut din aplicații și alte funcții de sistem de pe telefon"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tabletă"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml index 6b1172df5f01..6486d2444e04 100644 --- a/packages/CompanionDeviceManager/res/values-ru/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Управление подключенными устройствами"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Предоставить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ к устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"часы"</string> <string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Это приложение необходимо для управления устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Приложение \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" сможет синхронизировать данные, например из журнала звонков, а также получит доступ к уведомлениям и разрешениям \"Телефон\", \"Контакты\", \"Календарь\", \"Список вызовов\", \"Устройства поблизости\" и SMS."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> управлять устройством <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"Очки"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Это приложение необходимо для управления устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Приложение \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" сможет взаимодействовать с уведомлениями, а также получит разрешения \"Телефон\", SMS, \"Контакты\", \"Микрофон\" и \"Устройства поблизости\"."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> получать эту информацию с вашего телефона"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы стриминга приложений"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, чтобы транслировать приложения между вашими устройствами."</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> получать эту информацию с вашего телефона"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Сервисы Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, чтобы получить доступ к фотографиям, медиаконтенту и уведомлениям на телефоне."</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Разрешить приложению <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> выполнять это действие?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать приложения и системные функции на устройства поблизости."</string> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Приложение сможет синхронизировать информацию между телефоном и устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\", например данные из журнала звонков."</string> + <string name="summary_generic" msgid="1761976003668044801">"Приложение сможет синхронизировать информацию между телефоном и выбранным устройством, например данные из журнала звонков."</string> <string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string> <string name="consent_no" msgid="2640796915611404382">"Запретить"</string> <string name="consent_back" msgid="2560683030046918882">"Назад"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Трансляция приложений с телефона."</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Трансляция приложений и системных функций с телефона"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"телефоне"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"планшете"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml index b86b0c438b1a..8207122c5109 100644 --- a/packages/CompanionDeviceManager/res/values-si/strings.xml +++ b/packages/CompanionDeviceManager/res/values-si/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"සහායක උපාංග කළමනාකරු"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> වෙත ප්රවේශ වීමට ඉඩ දෙන්න ද?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"මෙම යෙදුමට ඔබේ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> කළමනාකරණය කිරීමට අවශ්යයි. <xliff:g id="APP_NAME">%2$s</xliff:g> හට අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට, ඔබේ දැනුම්දීම් සමග අන්තර්ක්රියා කිරීමට සහ ඔබේ දුරකථනය, SMS, සම්බන්ධතා, දින දර්ශනය, ඇමතුම් ලොග සහ අවට උපාංග අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ඇත."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> කළමනා කිරීමට ඉඩ දෙන්න ද?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"කණ්ණාඩි"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> කළමනා කිරීමට මෙම යෙදුම අවශ්යයි. <xliff:g id="APP_NAME">%2$s</xliff:g> හට ඔබේ දැනුම්දීම් සමග අන්තර්ක්රියා කිරීමට සහ ඔබේ දුරකථනය, කෙටි පණිවුඩය, සම්බන්ධතා, මයික්රොෆෝනය සහ අවට උපාංග අවසර වෙත ප්රවේශ වීමට ඉඩ දෙයි."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්රවේශ වීමට ඉඩ දෙන්න"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"හරස්-උපාංග සේවා"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> වෙනුවෙන් ඔබගේ උපාංග අතර යෙදුම් ප්රවාහ කිරීමට අවසරය ඉල්ලමින් සිටියි"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්රවේශ වීමට ඉඩ දෙන්න"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play සේවා"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> වෙනුවෙන් ඔබගේ දුරකථනයෙහි ඡායාරූප, මාධ්ය සහ දැනුම්දීම් වෙත ප්රවේශ වීමට අවසරය ඉල්ලමින් සිටියි"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"මෙම ක්රියාව කිරීමට <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> හට ඉඩ දෙන්න ද?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබේ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් යෙදුම් සහ අනෙකුත් පද්ධති විශේෂාංග අවට උපාංග වෙත ප්රවාහ කිරීමට අවසර ඉල්ලයි"</string> <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"මෙම යෙදුමට ඔබේ දුරකථනය සහ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> අතර, අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට හැකි වනු ඇත"</string> + <string name="summary_generic" msgid="1761976003668044801">"මෙම යෙදුමට ඔබේ දුරකථනය සහ තෝරා ගත් උපාංගය අතර, අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට හැකි වනු ඇත"</string> <string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string> <string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string> <string name="consent_back" msgid="2560683030046918882">"ආපසු"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"ඔබේ දුරකථනයේ යෙදුම් ප්රවාහ කරන්න"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"ඔබේ දුරකථනයෙන් යෙදුම් සහ අනෙකුත් පද්ධති විශේෂාංග ප්රවාහ කරන්න"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"දුරකථනය"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ටැබ්ලටය"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml index 77cfe8d3951c..088e38303689 100644 --- a/packages/CompanionDeviceManager/res/values-sk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Správca sprievodných zariadení"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k zariadeniu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string> <string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Táto aplikácia sa vyžaduje na správu zariadenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude môcť synchronizovať informácie, napríklad meno volajúceho, interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov, kalendára, zoznamu hovorov a zariadení v okolí."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> spravovať zariadenie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"okuliare"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Táto aplikácia sa vyžaduje na správu zariadenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získa prístup k povoleniam pre telefón, SMS, kontakty, mikrofón a zariadenia v okolí."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje povolenie na streamovanie aplikácií medzi vašimi zariadeniami v mene tohto zariadenia (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje povolenie na prístup k fotkám, médiám a upozorneniam vášho telefónu v mene tohto zariadenia (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Chcete povoliť zariadeniu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> vykonať túto akciu?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovať aplikácie a ďalšie systémové funkcie do zariadení v okolí"</string> <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, medzi telefónom a zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, medzi telefónom a vybraným zariadením"</string> <string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string> <string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string> <string name="consent_back" msgid="2560683030046918882">"Späť"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streamovať aplikácie telefónu"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Steaming aplikácii a ďalších systémov funkcií zo zariadenia"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefón"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml index 976289a4164c..bc7843c7e585 100644 --- a/packages/CompanionDeviceManager/res/values-sl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Upravitelj spremljevalnih naprav"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Želite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoliti dostop do naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ura"</string> <string name="chooser_title" msgid="2262294130493605839">"Izbira naprave »<xliff:g id="PROFILE_NAME">%1$s</xliff:g>«, ki jo bo upravljala aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ta aplikacija je potrebna za upravljanje naprave »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> bodo omogočene sinhronizacija podatkov, na primer imena klicatelja, interakcija z obvestili in uporaba dovoljenj Telefon, SMS, Stiki, Koledar, Dnevniki klicev in Naprave v bližini."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoliti upravljanje naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"očala"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ta aplikacija je potrebna za upravljanje naprave »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> bosta omogočeni interakcija z obvestili in uporaba dovoljenj Telefon, SMS, Stiki, Mikrofon in Naprave v bližini."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje aplikacij v vaših napravah."</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Storitve Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« zahteva dovoljenje za dostop do fotografij, predstavnosti in obvestil v telefonu."</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ali napravi <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> dovolite izvedbo tega dejanja?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_NAME">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje aplikacij in drugih sistemskih funkcij v napravah v bližini."</string> <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, v telefonu in napravi »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«."</string> + <string name="summary_generic" msgid="1761976003668044801">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, v telefonu in izbrani napravi."</string> <string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string> <string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string> <string name="consent_back" msgid="2560683030046918882">"Nazaj"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Pretočno predvajanje aplikacij telefona"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Pretočno predvajanje aplikacij in drugih sistemskih funkcij iz telefona"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablični računalnik"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml index 97fdcbb0ca99..d5999f3befac 100644 --- a/packages/CompanionDeviceManager/res/values-sq/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Menaxheri i pajisjes shoqëruese"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"T\'i lejohet <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> qasja te <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string> <string name="chooser_title" msgid="2262294130493605839">"Zgjidh \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\" që do të menaxhohet nga <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ky aplikacion nevojitet për të menaxhuar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> do të lejohet të sinkronizojë informacione, si p.sh. emrin e dikujt që po telefonon, të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\", \"Kalendarit\", \"Evidencave të telefonatave\" dhe \"Pajisjeve në afërsi\"."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Të lejohet që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të menaxhojë <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"syzet"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ky aplikacion nevojitet për të menaxhuar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\", \"Mikrofonit\" dhe të \"Pajisjeve në afërsi\"."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> për të transmetuar aplikacione ndërmjet pajisjeve të tua"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Shërbimet e Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet e telefonit tënd"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Të lejohet që <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> të ndërmarrë këtë veprim?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) tënde për të transmetuar aplikacione dhe veçori të tjera të sistemit te pajisjet në afërsi"</string> <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin i dikujt që po telefonon, mes telefonit tënd dhe <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="summary_generic" msgid="1761976003668044801">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin e dikujt që po telefonon, mes telefonit tënd dhe pajisjes së zgjedhur."</string> <string name="consent_yes" msgid="8344487259618762872">"Lejo"</string> <string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string> <string name="consent_back" msgid="2560683030046918882">"Pas"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Transmeto aplikacionet e telefonit tënd"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Transmeto aplikacionet dhe veçoritë e tjera të sistemit nga telefoni yt"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml index b205061c431d..93c939c773b7 100644 --- a/packages/CompanionDeviceManager/res/values-sr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Менаџер придруженог уређаја"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа уређају <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_watch" msgid="576290739483672360">"сат"</string> <string name="chooser_title" msgid="2262294130493605839">"Одаберите <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Ова апликација је потребна за управљање уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ће добити дозволу за синхронизовање информација, попут особе која упућује позив, за интеракцију са обавештењима и приступ дозволама за телефон, SMS, контакте, календар, евиденције позива и уређаје у близини."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Желите ли да дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> управља уређајем <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"наочаре"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Ова апликација је потребна за управљање уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS, контакте, микрофон и уређаје у близини."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа овим информацијама са телефона"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за стримовање апликација између уређаја"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа овим информацијама са телефона"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play услуге"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за приступ сликама, медијском садржају и обавештењима са телефона"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Желите ли да дозволите да <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> обави ову радњу?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да стримује апликације и друге системске функције на уређаје у близини"</string> <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ова апликација ће моћи да синхронизује податке, попут имена особе која упућује позив, између телефона и уређаја <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Ова апликација ће моћи да синхронизује податке, попут имена особе која упућује позив, између телефона и одабраног уређаја"</string> <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string> <string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string> <string name="consent_back" msgid="2560683030046918882">"Назад"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Стримујте апликације на телефону"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Стримујте апликације и друге системске функције са телефона"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"телефону"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"таблету"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml index 45089f096334..dfe795e66bef 100644 --- a/packages/CompanionDeviceManager/res/values-sv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Vill du tillåta att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> får åtkomst till <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"klocka"</string> <string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Appen behövs för att hantera <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillåtelse att synkronisera information, till exempel namnet på någon som ringer, interagera med dina aviseringar och får åtkomst till behörigheterna Telefon, Sms, Kontakter, Kalender, Samtalsloggar och Enheter i närheten."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Tillåt att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hanterar <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"glasögon"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Appen behövs för att hantera <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillåtelse att interagera med dina aviseringar och får åtkomst till behörigheterna Telefon, Sms, Kontakter, Mikrofon och Enheter i närheten."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Ge <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> åtkomstbehörighet till denna information på telefonen"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjänster för flera enheter"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att låta <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> streama appar mellan enheter"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Ge <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> åtkomstbehörighet till denna information på telefonen"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjänster"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att ge <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> åtkomst till foton, mediefiler och aviseringar på telefonen"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vill du tillåta att <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> utför denna åtgärd?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att streama appar och andra systemfunktioner till enheter i närheten för din <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Den här appen kommer att kunna synkronisera information mellan telefonen och <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, till exempel namnet på någon som ringer"</string> + <string name="summary_generic" msgid="1761976003668044801">"Den här appen kommer att kunna synkronisera information mellan telefonen och den valda enheten, till exempel namnet på någon som ringer"</string> <string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string> <string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string> <string name="consent_back" msgid="2560683030046918882">"Tillbaka"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streama telefonens appar"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Streama appar och andra systemfunktioner från din telefon"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"surfplatta"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml index a12f3c21bb7a..982c1d9dc6eb 100644 --- a/packages/CompanionDeviceManager/res/values-sw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Kidhibiti cha Vifaa Visaidizi"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"saa"</string> <string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Programu hii inahitajika ili udhibiti <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako. <xliff:g id="APP_NAME">%2$s</xliff:g> itaruhusiwa kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kutumia arifa zako na ruhusa zako za Simu, SMS, Anwani, Maikrofoni na vifaa vilivyo Karibu."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> idhibiti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"miwani"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Programu hii inahitajika ili udhibiti <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> itaruhusiwa kutumia arifa zako na kufikia ruhusa zako za Simu, SMS, Anwani, Maikrofoni na Vifaa vilivyo Karibu."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie maelezo haya kutoka kwenye simu yako"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Huduma za kifaa kilichounganishwa kwingine"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako ili itiririshe programu kati ya vifaa vyako"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie maelezo haya kutoka kwenye simu yako"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Huduma za Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako ili ifikie picha, maudhui na arifa za simu yako"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ungependa kuruhusu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> itekeleze kitendo hiki?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> chako ili itiririshe programu na vipengele vingine vya mfumo kwenye vifaa vilivyo karibu"</string> <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Programu hii itaweza kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kati ya simu na <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako"</string> + <string name="summary_generic" msgid="1761976003668044801">"Programu hii itaweza kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kati ya simu yako na kifaa ulichochagua"</string> <string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string> <string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string> <string name="consent_back" msgid="2560683030046918882">"Nyuma"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Tiririsha programu za simu yako"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Kutiririsha programu na vipengele vya mfumo kwenye simu yako"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"simu"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"kompyuta kibao"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml index 98981b2c7f28..34da557b9365 100644 --- a/packages/CompanionDeviceManager/res/values-ta/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml @@ -17,28 +17,29 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"கம்பேனியன் சாதன நிர்வாகி"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்தை அணுக <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string> <string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> தேர்ந்தெடுக்கப்பட வேண்டும்"</string> <!-- no translation found for summary_watch (898569637110705523) --> <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong&gt சாதனத்தை நிர்வகிக்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"கிளாஸஸ்"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்தை நிர்வகிக்க இந்த ஆப்ஸ் தேவை. உங்கள் மொபைல், மெசேஜ், தொடர்புகள், மைக்ரோஃபோன், அருகிலுள்ள சாதனங்கள் ஆகியவற்றுக்கான அணுகலையும் உங்கள் அறிவிப்புகளைப் பார்ப்பதற்கான அனுமதியையும் <xliff:g id="APP_NAME">%2$s</xliff:g> பெறும்."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"மொபைலில் உள்ள இந்தத் தகவல்களை அணுக, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவும்"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"பன்முக சாதன சேவைகள்"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"உங்கள் சாதனங்களுக்கு இடையே ஆப்ஸை ஸ்ட்ரீம் செய்ய உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் அனுமதியைக் கோருகிறது"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"உங்கள் மொபைலிலிருந்து இந்தத் தகவலை அணுக <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதியுங்கள்"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play சேவைகள்"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"உங்கள் மொபைலில் உள்ள படங்கள், மீடியா, அறிவிப்புகள் ஆகியவற்றை அணுக உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் அனுமதியைக் கோருகிறது"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"இந்தச் செயலைச் செய்ய <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong&gt சாதனத்தை அனுமதிக்கவா?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"அருகிலுள்ள சாதனங்களுக்கு ஆப்ஸையும் பிற சிஸ்டம் அம்சங்களையும் ஸ்ட்ரீம் செய்ய உங்கள் <xliff:g id="DEVICE_NAME">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கோருகிறது"</string> <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string> @@ -75,8 +76,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"உங்கள் மொபைல் ஆப்ஸை ஸ்ட்ரீம் செய்யலாம்"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"உங்கள் மொபைலில் இருந்து ஆப்ஸையும் பிற சிஸ்டம் அம்சங்களையும் ஸ்ட்ரீம் செய்யலாம்"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"மொபைல்"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"டேப்லெட்"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml index d7ffce7d5782..9155ed206953 100644 --- a/packages/CompanionDeviceManager/res/values-te/strings.xml +++ b/packages/CompanionDeviceManager/res/values-te/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"సహచర పరికర మేనేజర్"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ను యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string> <string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"మీ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని సింక్ చేయడానికి, మీ నోటిఫికేషన్లతో ఇంటరాక్ట్ అవ్వడానికి, అలాగే మీ ఫోన్, SMS, కాంటాక్ట్లు, క్యాలెండర్, కాల్ లాగ్లు, సమీపంలోని పరికరాల అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%2$s</xliff:g> అనుమతించబడుతుంది."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ను మేనేజ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"గ్లాసెస్"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. మీ నోటిఫికేషన్లతో ఇంటరాక్ట్ అవ్వడానికి, అలాగే మీ ఫోన్, SMS, కాంటాక్ట్లు, మైక్రోఫోన్, సమీపంలోని పరికరాల అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%2$s</xliff:g> అనుమతించబడుతుంది."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యాప్ను అనుమతించండి"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"మీ పరికరాల మధ్య యాప్లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యాప్ను అనుమతించండి"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play సర్వీసులు"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> మీ ఫోన్లోని ఫోటోలను, మీడియాను, ఇంకా నోటిఫికేషన్లను యాక్సెస్ చేయడానికి మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"ఈ చర్యను అమలు చేయడానికి <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"సమీపంలోని పరికరాలకు యాప్లను, ఇతర సిస్టమ్ ఫీచర్లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string> <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని ఈ యాప్ మీ ఫోన్కి, <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కి మధ్య సింక్ చేయగలుగుతుంది"</string> + <string name="summary_generic" msgid="1761976003668044801">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని ఈ యాప్ మీ ఫోన్ కు, ఎంచుకున్న పరికరానికీ మధ్య సింక్ చేయగలుగుతుంది"</string> <string name="consent_yes" msgid="8344487259618762872">"అనుమతించండి"</string> <string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string> <string name="consent_back" msgid="2560683030046918882">"వెనుకకు"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"మీ ఫోన్లోని యాప్లను స్ట్రీమ్ చేయండి"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"మీ ఫోన్ నుండి యాప్లను, ఇతర సిస్టమ్ ఫీచర్లను స్ట్రీమ్ చేస్తుంది"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ఫోన్"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"టాబ్లెట్"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml index ff17b6920724..950078e05b52 100644 --- a/packages/CompanionDeviceManager/res/values-th/strings.xml +++ b/packages/CompanionDeviceManager/res/values-th/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึง <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string> <string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g> จะได้รับอนุญาตให้ซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา โต้ตอบกับการแจ้งเตือน รวมถึงมีสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ, ปฏิทิน, บันทึกการโทร และอุปกรณ์ที่อยู่ใกล้เคียง"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> จัดการ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ไหม"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"แว่นตา"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและมีสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ, ไมโครโฟน และอุปกรณ์ที่อยู่ใกล้เคียง"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> เพื่อสตรีมแอประหว่างอุปกรณ์ต่างๆ ของคุณ"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"บริการ Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> เพื่อเข้าถึงรูปภาพ สื่อ และการแจ้งเตือนในโทรศัพท์ของคุณ"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"อนุญาตให้ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ทำงานนี้ไหม"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อสตรีมแอปและฟีเจอร์อื่นๆ ของระบบไปยังอุปกรณ์ที่อยู่ใกล้เคียง"</string> <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"แอปนี้จะสามารถซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา ระหว่างโทรศัพท์ของคุณและ<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ได้"</string> + <string name="summary_generic" msgid="1761976003668044801">"แอปนี้จะสามารถซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา ระหว่างโทรศัพท์ของคุณและอุปกรณ์ที่เลือกไว้ได้"</string> <string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string> <string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string> <string name="consent_back" msgid="2560683030046918882">"กลับ"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"สตรีมแอปของโทรศัพท์คุณ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"สตรีมแอปและฟีเจอร์อื่นๆ ของระบบจากโทรศัพท์"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"โทรศัพท์"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"แท็บเล็ต"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml index afb6adb30a69..b177dda22957 100644 --- a/packages/CompanionDeviceManager/res/values-tl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Kasamang Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"relo"</string> <string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Kailangan ang app na ito para mapamahalaan ang iyong <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Papayagan ang <xliff:g id="APP_NAME">%2$s</xliff:g> na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, makipag-ugnayan sa mga notification mo, at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, Kalendaryo, Mga log ng tawag, at Mga kalapit na device."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na pamahalaan ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"salamin"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Kailangan ang app na ito para mapamahalaan ang <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Papayagan ang <xliff:g id="APP_NAME">%2$s</xliff:g> na makipag-ugnayan sa mga notification mo at i-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, Mikropono, at Mga kalapit na device."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang impormasyong ito sa iyong telepono"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Mga cross-device na serbisyo"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para mag-stream ng mga app sa pagitan ng mga device mo"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang impormasyon sa iyong telepono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Mga serbisyo ng Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para i-access ang mga larawan, media, at notification ng telepono mo"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Payagan ang <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> na gawin ang pagkilos na ito?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Humihiling ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para mag-stream ng mga app at iba pang feature ng system sa mga kalapit na device"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Magagawa ng app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, sa pagitan ng iyong telepono at ng <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Magagawa ng app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, sa pagitan ng iyong telepono at ng napiling device"</string> <string name="consent_yes" msgid="8344487259618762872">"Payagan"</string> <string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string> <string name="consent_back" msgid="2560683030046918882">"Bumalik"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"I-stream ang mga app ng iyong telepono"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Mag-stream ng mga app at iba pang feature ng system mula sa iyong telepono"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telepono"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml index 69d08b77ba10..7df524bb661c 100644 --- a/packages/CompanionDeviceManager/res/values-tr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazına erişmesi için <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasına izin verin"</string> <string name="profile_name_watch" msgid="576290739483672360">"saat"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Bu uygulama, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızın yönetilmesi için gereklidir. <xliff:g id="APP_NAME">%2$s</xliff:g> adlı uygulamanın arayan kişinin adı gibi bilgileri senkronize etmesine, bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler, Takvim, Arama kayıtları ve Yakındaki cihazlar izinlerine erişmesine izin verilir."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasına <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazını yönetmesi için izin verilsin mi?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"glasses"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Bu uygulama, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazının yönetilmesi için gereklidir. <xliff:g id="APP_NAME">%2$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler, Mikrofon ve Yakındaki cihazlar izinlerine erişmesine izin verilir."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulama akışı gerçekleştirmek için <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınız adına izin istiyor"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play hizmetleri"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g>, telefonunuzdaki fotoğraf, medya ve bildirimlere erişmek için <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınız adına izin istiyor"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> cihazının bu işlem yapmasına izin verilsin mi?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması <xliff:g id="DEVICE_NAME">%2$s</xliff:g> cihazınız adına uygulamaları ve diğer sistem özelliklerini yakındaki cihazlara aktarmak için izin istiyor"</string> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Bu uygulama, arayan kişinin adı gibi bilgileri telefonunuz ve <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaz arasında senkronize edebilir"</string> + <string name="summary_generic" msgid="1761976003668044801">"Bu uygulama, arayan kişinin adı gibi bilgileri telefonunuz ve seçili cihaz arasında senkronize edebilir"</string> <string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string> <string name="consent_no" msgid="2640796915611404382">"İzin verme"</string> <string name="consent_back" msgid="2560683030046918882">"Geri"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefonunuzun uygulamalarını yayınlama"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Telefonunuzdan uygulamaları ve diğer sistem özelliklerini yayınlayın"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"tablet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml index 0733997f5202..22a2afd08bbc 100644 --- a/packages/CompanionDeviceManager/res/values-uk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Диспетчер супутніх пристроїв"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Надати додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до інформації на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"годинник"</string> <string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Цей додаток потрібен, щоб керувати пристроєм \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Додаток <xliff:g id="APP_NAME">%2$s</xliff:g> зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає), взаємодіяти з вашими сповіщеннями й отримає дозволи \"Телефон\", \"SMS\", \"Контакти\", \"Календар\", \"Журнали викликів\" і \"Пристрої поблизу\"."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Дозволити додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> керувати пристроєм <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"окуляри"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Цей додаток потрібен, щоб керувати пристроєм \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Додаток <xliff:g id="APP_NAME">%2$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями й отримає дозволи \"Телефон\", \"SMS\", \"Контакти\", \"Мікрофон\" і \"Пристрої поблизу\"."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Надайте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до цієї інформації з телефона"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервіси для кількох пристроїв"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> запитує дозвіл на трансляцію додатків між вашими пристроями"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Надайте пристрою <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до цієї інформації з телефона"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Сервіси Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> запитує дозвіл на доступ до фотографій, медіафайлів і сповіщень вашого телефона"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Дозволити додатку <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> виконувати цю дію?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) запитує дозвіл на трансляцію додатків та інших системних функцій на пристрої поблизу"</string> <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) між телефоном і пристроєм \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\""</string> + <string name="summary_generic" msgid="1761976003668044801">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) між телефоном і вибраним пристроєм"</string> <string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string> <string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string> <string name="consent_back" msgid="2560683030046918882">"Назад"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Транслювати додатки телефона"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Транслюйте додатки й інші системні функції зі свого телефона"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"телефоні"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"планшеті"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml index fee4da20ed49..82b160568f8b 100644 --- a/packages/CompanionDeviceManager/res/values-ur/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"ساتھی آلہ مینیجر"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> تک رسائی کی اجازت دیں؟"</string> <string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کا نظم کرنے کے لیے اس ایپ کی ضرورت ہے۔ <xliff:g id="APP_NAME">%2$s</xliff:g> کو کسی کال کرنے والے کے نام جیسی معلومات کی مطابقت پذیری کرنے، آپ کی اطلاعات کے ساتھ تعامل کرنے، آپ کے فون، SMS، رابطے، کیلنڈر، کال لاگز اور قریبی آلات کی اجازتوں تک رسائی حاصل کرنے کی اجازت ہوگی۔"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کا نظم کرنے کی اجازت دیں؟"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"گلاسز"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> کا نظم کرنے کے لیے، اس ایپ کی ضرورت ہے۔ <xliff:g id="APP_NAME">%2$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں، مائیکروفون اور قریبی آلات کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"اپنے فون سے ان معلومات تک رسائی حاصل کرنے کی <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو اجازت دیں"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس ڈیوائس سروسز"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان ایپس کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"اپنے فون سے اس معلومات تک رسائی حاصل کرنے کی <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو اجازت دیں"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play سروسز"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی جانب سے آپ کے فون کی تصاویر، میڈیا اور اطلاعات تک رسائی کی اجازت طلب کر رہی ہے"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> کو یہ کارروائی انجام دینے کی اجازت دیں؟"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> آپ کے <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے ایپس اور سسٹم کی دیگر خصوصیات کی سلسلہ بندی قریبی آلات پر کرنے کی اجازت طلب کر رہی ہے"</string> <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"یہ ایپ آپ کے فون اور <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کے درمیان معلومات، جیسے کسی کال کرنے والے کے نام، کی مطابقت پذیری کر سکے گی"</string> + <string name="summary_generic" msgid="1761976003668044801">"یہ ایپ آپ کے فون اور منتخب کردہ آلے کے درمیان معلومات، جیسے کسی کال کرنے والے کے نام، کی مطابقت پذیری کر سکے گی"</string> <string name="consent_yes" msgid="8344487259618762872">"اجازت دیں"</string> <string name="consent_no" msgid="2640796915611404382">"اجازت نہ دیں"</string> <string name="consent_back" msgid="2560683030046918882">"پیچھے"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"اپنے فون کی ایپس کی سلسلہ بندی کریں"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"اپنے فون سے ایپس اور سسٹم کی دیگر خصوصیات کی سلسلہ بندی کریں"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"فون"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ٹیبلیٹ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml index 27f60541ea5f..99bf67edf646 100644 --- a/packages/CompanionDeviceManager/res/values-uz/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qurilmasidan foydalanishga ruxsat berilsinmi?"</string> <string name="profile_name_watch" msgid="576290739483672360">"soat"</string> <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Bu ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> profilini boshqarish uchun kerak. <xliff:g id="APP_NAME">%2$s</xliff:g> ilovasiga chaqiruvchining ismi, bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar, taqvim, chaqiruvlar jurnali va yaqin-atrofdagi qurilmalarni aniqlash kabi maʼlumotlarni sinxronlashga ruxsat beriladi."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qurilmasini boshqarish uchun ruxsat berilsinmi?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"koʻzoynak"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Bu ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasini boshqarish uchun kerak. <xliff:g id="APP_NAME">%2$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar, mikrofon va yaqin-atrofdagi qurilmalarga kirishga ruxsat beriladi."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Qurilmalararo xizmatlar"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"Qurilamalararo ilovalar strimingi uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xizmatlari"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Telefoningizdagi rasm, media va bildirishnomalarga kirish uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ilovasiga bu amalni bajarish uchun ruxsat berilsinmi?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_NAME">%2$s</xliff:g> qurilmangizdan nomidan atrofdagi qurilmalarga ilova va boshqa tizim funksiyalarini uzatish uchun ruxsat olmoqchi"</string> <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Bu ilova telefoningiz va <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasida chaqiruvchining ismi kabi maʼlumotlarni sinxronlay oladi"</string> + <string name="summary_generic" msgid="1761976003668044801">"Bu ilova telefoningiz va tanlangan qurilmada chaqiruvchining ismi kabi maʼlumotlarni sinxronlay oladi"</string> <string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string> <string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string> <string name="consent_back" msgid="2560683030046918882">"Orqaga"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefondagi ilovalarni translatsiya qilish"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Telefoningizdan ilovalar va tizim funksiyalarini translatsiya qilish"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"planshet"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml index fb18b0084bfd..4b3e1ecc9147 100644 --- a/packages/CompanionDeviceManager/res/values-vi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Trình quản lý thiết bị đồng hành"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string> <string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> quản lý"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Cần ứng dụng này để quản lý <xliff:g id="DEVICE_NAME">%1$s</xliff:g> của bạn. <xliff:g id="APP_NAME">%2$s</xliff:g> được phép đồng bộ hoá thông tin (ví dụ: tên người gọi), tương tác với thông báo cũng như có các quyền truy cập Điện thoại, Tin nhắn SMS, Danh bạ, Lịch, Nhật ký cuộc gọi và Thiết bị ở gần."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> quản lý <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"kính"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Bạn cần có ứng dụng này để quản lý <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> sẽ được phép tương tác với thông báo của bạn, cũng như sử dụng các quyền đối với Điện thoại, SMS, Danh bạ, Micrô và Thiết bị ở gần."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào thông tin này trên điện thoại của bạn"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Dịch vụ trên nhiều thiết bị"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> để truyền trực tuyến ứng dụng giữa các thiết bị của bạn"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào thông tin này trên điện thoại của bạn"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Dịch vụ Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> để truy cập vào ảnh, nội dung nghe nhìn và thông báo trên điện thoại của bạn."</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Cho phép <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> thực hiện hành động này?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang thay <xliff:g id="DEVICE_NAME">%2$s</xliff:g> yêu cầu quyền truyền trực tuyến ứng dụng và các tính năng khác của hệ thống đến các thiết bị ở gần"</string> <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Ứng dụng này sẽ đồng bộ hoá thông tin (ví dụ: tên người gọi) giữa điện thoại của bạn và <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Ứng dụng này sẽ đồng bộ hoá thông tin (ví dụ: tên người gọi) giữa điện thoại của bạn và thiết bị bạn chọn"</string> <string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string> <string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string> <string name="consent_back" msgid="2560683030046918882">"Quay lại"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Truyền các ứng dụng trên điện thoại của bạn"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Truyền trực tuyến ứng dụng và các tính năng khác của hệ thống từ điện thoại của bạn"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"điện thoại"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"máy tính bảng"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml index 25df72787503..8ae797422b48 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"配套设备管理器"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>访问<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"手表"</string> <string name="chooser_title" msgid="2262294130493605839">"选择要由<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"需要使用此应用才能管理您的设备“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”。<xliff:g id="APP_NAME">%2$s</xliff:g>将能同步信息(例如来电者的姓名)、与通知交互,并能获得对电话、短信、通讯录、日历、通话记录和附近设备的访问权限。"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>管理<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"眼镜"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"需要使用此应用才能管理<xliff:g id="DEVICE_NAME">%1$s</xliff:g>。“<xliff:g id="APP_NAME">%2$s</xliff:g>”将能与通知交互,并可获得电话、短信、通讯录、麦克风和附近设备的访问权限。"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”<strong></strong>访问您手机中的这项信息"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨设备服务"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>请求在您的设备之间流式传输应用内容"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 访问您手机中的这项信息"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服务"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>请求访问您手机上的照片、媒体内容和通知"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"允许<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>进行此操作?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_NAME">%2$s</xliff:g>请求将应用和其他系统功能流式传输到附近的设备"</string> <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"此应用将能在您的手机和“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”之间同步信息,例如来电者的姓名"</string> + <string name="summary_generic" msgid="1761976003668044801">"此应用将能在您的手机和所选设备之间同步信息,例如来电者的姓名"</string> <string name="consent_yes" msgid="8344487259618762872">"允许"</string> <string name="consent_no" msgid="2640796915611404382">"不允许"</string> <string name="consent_back" msgid="2560683030046918882">"返回"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"流式传输手机上的应用"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"从您的手机流式传输应用和其他系统功能"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"手机"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"平板电脑"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml index fe58ddd69013..66c6be27a564 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string> <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string> <string name="chooser_title" msgid="2262294130493605839">"選擇由 <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"必須使用此應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可同步資訊 (例如來電者的名稱)、透過通知與你互動,並存取電話、短訊、通訊錄、日曆、通話記錄和附近的裝置權限。"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"眼鏡"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"必須使用此應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可透過通知與您互動,並存取電話、短訊、通訊錄、麥克風和附近的裝置權限。"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取您手機中的這項資料"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在為 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 要求權限,以在裝置之間串流應用程式內容"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取您手機中的這項資料"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 要求權限,以便存取手機上的相片、媒體和通知"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"要允許「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」<strong></strong>執行此操作嗎?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求權限,才能在附近的裝置上串流播放應用程式和其他系統功能"</string> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"此應用程式將可同步手機和「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」的資訊,例如來電者的名稱"</string> + <string name="summary_generic" msgid="1761976003668044801">"此應用程式將可同步手機和所選裝置的資訊,例如來電者的名稱"</string> <string name="consent_yes" msgid="8344487259618762872">"允許"</string> <string name="consent_no" msgid="2640796915611404382">"不允許"</string> <string name="consent_back" msgid="2560683030046918882">"返回"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"串流播放手機應用程式內容"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"串流播放手機中的應用程式和其他系統功能"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"手機"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"平板電腦"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml index 33c1f2ab679f..fdb78a5d4a7d 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string> <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string> <string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」<strong></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"你必須使用這個應用程式,才能管理<xliff:g id="DEVICE_NAME">%1$s</xliff:g>。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可同步資訊 (例如來電者名稱)、存取通知及在通知上執行操作,並取得電話、簡訊、聯絡人、日曆、通話記錄、麥克風和鄰近裝置權限。"</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>嗎?"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"眼鏡"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"你必須使用這個應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可存取通知及在通知上執行操作,並取得電話、簡訊、聯絡人、麥克風和鄰近裝置權限。"</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取手機中的這項資訊"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表你的「<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>」要求必要權限,以便在裝置之間串流傳輸應用程式內容"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取你手機中的這項資訊"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表你的「<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>」要求必要權限,以便存取手機上的相片、媒體和通知"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"要允許「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」<strong></strong>執行這項操作嗎?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求必要權限,才能在鄰近裝置上串流播放應用程式和其他系統功能"</string> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"這個應用程式將可在手機和「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」之間同步資訊,例如來電者名稱"</string> + <string name="summary_generic" msgid="1761976003668044801">"這個應用程式將可在手機和指定裝置間同步資訊,例如來電者名稱"</string> <string name="consent_yes" msgid="8344487259618762872">"允許"</string> <string name="consent_no" msgid="2640796915611404382">"不允許"</string> <string name="consent_back" msgid="2560683030046918882">"返回"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"串流傳輸手機應用程式內容"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"串流播放手機中的應用程式和其他系統功能"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"手機"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"平板電腦"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml index 5a3de1c7a10d..9656fefb37dd 100644 --- a/packages/CompanionDeviceManager/res/values-zu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml @@ -17,35 +17,33 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Isiphathi sedivayisi esihambisanayo"</string> - <!-- no translation found for confirmation_title (4593465730772390351) --> - <skip /> + <string name="confirmation_title" msgid="4593465730772390351">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukufinyelela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_watch" msgid="576290739483672360">"buka"</string> <string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> - <!-- no translation found for summary_watch (898569637110705523) --> - <skip /> - <!-- no translation found for summary_watch_single_device (3001383718181475756) --> + <string name="summary_watch" msgid="898569637110705523">"Le app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho. I-<xliff:g id="APP_NAME">%2$s</xliff:g> izovunyelwa ukuvumelanisa ulwazi, njengegama lomuntu othile ofonayo, ukusebenzisana nezaziso zakho futhi ufinyelele Ifoni yakho, i-SMS, Oxhumana Nabo, Ikhalenda, Amarekhodi Amakholi nezimvume zamadivayisi aseduze."</string> + <!-- no translation found for summary_watch_single_device (3173948915947011333) --> <skip /> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukuthi ifinyelele i-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_glasses" msgid="8488394059007275998">"Izingilazi"</string> <string name="summary_glasses_multi_device" msgid="615259525961937348">"Le app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>. I-<xliff:g id="APP_NAME">%2$s</xliff:g> izovunyelwa ukuthi ihlanganyele nezaziso zakho futhi ifinyelele kufoni yakho, i-SMS, Oxhumana nabo, Imakrofoni Nezimvume zamadivayisi aseduze."</string> - <!-- no translation found for summary_glasses_single_device (403955999347676820) --> + <!-- no translation found for summary_glasses_single_device (3000909894067413398) --> <skip /> <string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifinyelele lolu lwazi kusukela efonini yakho"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string> - <string name="helper_summary_app_streaming" msgid="5977509499890099">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho ukuze isakaze-bukhoma ama-app phakathi kwamadivayisi akho"</string> + <!-- no translation found for helper_summary_app_streaming (2396773196949578425) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukufinyelela lolu lwazi kusuka efonini yakho"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Amasevisi we-Google Play"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho ukuze ifinyelele izithombe zefoni yakho, imidiya nezaziso"</string> + <!-- no translation found for helper_summary_computer (8774832742608187072) --> + <skip /> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Vumela i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ukwenza lesi senzo?"</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ukusakaza ama-app nezinye izakhi zesistimu kumadivayisi aseduze"</string> <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string> - <!-- no translation found for summary_generic_single_device (4181180669689590417) --> - <skip /> - <!-- no translation found for summary_generic (1761976003668044801) --> - <skip /> + <string name="summary_generic_single_device" msgid="4181180669689590417">"Le app izokwazi ukuvumelanisa ulwazi, njengegama lomuntu othile ofonayo, phakathi kwefoni yakho ne-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> + <string name="summary_generic" msgid="1761976003668044801">"Le app izokwazi ukuvumelanisa ulwazi, njengegama lomuntu othile ofonayo, phakathi kwefoni yakho nedivayisi ekhethiwe"</string> <string name="consent_yes" msgid="8344487259618762872">"Vumela"</string> <string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string> <string name="consent_back" msgid="2560683030046918882">"Emuva"</string> @@ -75,8 +73,6 @@ <string name="permission_app_streaming_summary" msgid="606923325679670624">"Sakaza ama-app wefoni yakho"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Sakaza ama-app nezinye izakhi zesistimu kusuka kufoni yakho"</string> - <!-- no translation found for device_type (8268703872070046263) --> - <skip /> - <!-- no translation found for device_type (5038791954983067774) --> - <skip /> + <string name="device_type" product="default" msgid="8268703872070046263">"ifoni"</string> + <string name="device_type" product="tablet" msgid="5038791954983067774">"ithebulethi"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml index d87abb98ebde..ebfb86d4d6ba 100644 --- a/packages/CompanionDeviceManager/res/values/strings.xml +++ b/packages/CompanionDeviceManager/res/values/strings.xml @@ -34,7 +34,7 @@ <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">This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="device_name" example="phone">%1$s</xliff:g></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 on your <xliff:g id="device_type" example="phone">%1$s</xliff:g></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 <xliff:g id="device_name" example="phone">%1$s</xliff:g></string> + <string name="summary_glasses_single_device">This app will be allowed to access these permissions on your <xliff:g id="device_type" example="phone">%1$s</xliff:g></string> <!-- ================= DEVICE_PROFILE_APP_STREAMING ================= --> @@ -59,7 +59,7 @@ <string name="helper_title_app_streaming">Cross-device services</string> <!-- Description of the helper dialog for APP_STREAMING profile. [CHAR LIMIT=NONE] --> - <string name="helper_summary_app_streaming"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to stream apps between your devices</string> + <string name="helper_summary_app_streaming"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="display_name" example="Chromebook">%2$s</xliff:g> to stream apps between your devices</string> <!-- ================= DEVICE_PROFILE_AUTOMOTIVE_PROJECTION ================= --> @@ -81,7 +81,7 @@ <string name="helper_title_computer">Google Play services</string> <!-- Description of the helper dialog for COMPUTER profile. [CHAR LIMIT=NONE] --> - <string name="helper_summary_computer"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to access your phone\u2019s photos, media, and notifications</string> + <string name="helper_summary_computer"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="display_name" example="Chromebook">%2$s</xliff:g> to access your phone\u2019s photos, media, and notifications</string> <!-- ================= DEVICE_PROFILE_NEARBY_DEVICE_STREAMING ================= --> diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml index 9def248b1fd7..0c205c3cdbec 100644 --- a/packages/CredentialManager/res/values-af/strings.xml +++ b/packages/CredentialManager/res/values-af/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Kies ’n opsie vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Gebruik hierdie inligting op <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Aanmeldopsies"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Vir <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Geslote wagwoordbestuurders"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tik om te ontsluit"</string> diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml index ca7584f27151..6837617eaadf 100644 --- a/packages/CredentialManager/res/values-am/strings.xml +++ b/packages/CredentialManager/res/values-am/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"ለ<xliff:g id="APP_NAME">%1$s</xliff:g> አማራጭ ይመረጥ?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"ይህን መረጃ በ<xliff:g id="APP_NAME">%1$s</xliff:g> ላይ ይጠቀማሉ?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"የመግቢያ አማራጮች"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"ለ<xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"የተቆለፉ የሚስጥር ቁልፍ አስተዳዳሪዎች"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ለመክፈት መታ ያድርጉ"</string> diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml index ef8c6f049361..8e23ca08cc61 100644 --- a/packages/CredentialManager/res/values-ar/strings.xml +++ b/packages/CredentialManager/res/values-ar/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"هل تريد اختيار بيانات الاعتماد لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"هل تريد استخدام بيانات الاعتماد هذه في \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"خيارات تسجيل الدخول"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"معلومات تسجيل دخول \"<xliff:g id="USERNAME">%1$s</xliff:g>\""</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"خدمات إدارة كلمات المرور المقفولة"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"انقر لفتح القفل."</string> diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml index 0a6d5d072d29..ac0969ce34d6 100644 --- a/packages/CredentialManager/res/values-as/strings.xml +++ b/packages/CredentialManager/res/values-as/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে এটা বিকল্প বাছনি কৰিবনে?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g>ত এই তথ্য ব্যৱহাৰ কৰিবনে?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ছাইন ইনৰ বিকল্প"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>ৰ বাবে"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"লক হৈ থকা পাছৱৰ্ড পৰিচালক"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"আনলক কৰিবলৈ টিপক"</string> diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml index 97ffd43916ad..904c2a4aa74f 100644 --- a/packages/CredentialManager/res/values-az/strings.xml +++ b/packages/CredentialManager/res/values-az/strings.xml @@ -26,13 +26,13 @@ <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün giriş açarı yaradılsın?"</string> <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün parol yadda saxlanılsın?"</string> <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün giriş məlumatları yadda saxlansın?"</string> - <string name="passkey" msgid="632353688396759522">"giriş açarı"</string> + <string name="passkey" msgid="632353688396759522">"açar"</string> <string name="password" msgid="6738570945182936667">"parol"</string> <string name="passkeys" msgid="5733880786866559847">"giriş açarları"</string> <string name="passwords" msgid="5419394230391253816">"parollar"</string> <string name="sign_ins" msgid="4710739369149469208">"girişlər"</string> <string name="sign_in_info" msgid="2627704710674232328">"Giriş məlumatları"</string> - <string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> burada yadda saxlansın:"</string> + <string name="save_credential_to_title" msgid="3172811692275634301">"<xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> harada saxlanılsın?"</string> <string name="create_passkey_in_other_device_title" msgid="9195411122362461390">"Başqa cihazda giriş açarı yaradılsın?"</string> <string name="use_provider_for_all_title" msgid="4201020195058980757">"Bütün girişlər üçün <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> istifadə edilsin?"</string> <string name="use_provider_for_all_description" msgid="1998772715863958997">"<xliff:g id="USERNAME">%1$s</xliff:g> üçün bu parol meneceri asanlıqla daxil olmağınız məqsədilə parol və giriş açarlarını saxlayacaq"</string> @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün seçim edilsin?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Məlumat <xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqində istifadə edilsin?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Giriş seçimləri"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> üçün"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Kilidli parol menecerləri"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Kiliddən çıxarmaq üçün toxunun"</string> diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml index fb23ee125644..55b118924ff2 100644 --- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Želite da odaberete opciju za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Želite da koristite te podatke u aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcije za prijavljivanje"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Za: <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Menadžeri zaključanih lozinki"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Dodirnite da biste otključali"</string> diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml index 12b90ee27008..f73fb4e1c27e 100644 --- a/packages/CredentialManager/res/values-be/strings.xml +++ b/packages/CredentialManager/res/values-be/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Выберыце ўліковыя даныя для ўваходу ў праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Выкарыстоўваць гэтую інфармацыю на прыладзе <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Спосабы ўваходу"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Для карыстальніка <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблакіраваныя спосабы ўваходу"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Націсніце, каб разблакіраваць"</string> diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml index f22c83e08107..d2e8e55b20f1 100644 --- a/packages/CredentialManager/res/values-bg/strings.xml +++ b/packages/CredentialManager/res/values-bg/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Искате ли да изберете опция за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Да се използва ли тази информация за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Опции за влизане в профила"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"За <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заключени мениджъри на пароли"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Докоснете, за да отключите"</string> diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml index c1a74fc316f7..1d2afb6f74e9 100644 --- a/packages/CredentialManager/res/values-bn/strings.xml +++ b/packages/CredentialManager/res/values-bn/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য বিকল্প বেছে নেবেন?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ সাইন-ইন করতে এই তথ্য ব্যবহার করবেন?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"সাইন-ইন করার বিকল্প"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>-এর জন্য"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"লক করা Password Manager"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"আনলক করতে ট্যাপ করুন"</string> diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml index 7884e9fda4db..2bbd80fa3e2a 100644 --- a/packages/CredentialManager/res/values-bs/strings.xml +++ b/packages/CredentialManager/res/values-bs/strings.xml @@ -52,13 +52,14 @@ <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> - <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Želite li odabrati opciju za <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Odabrati opciju za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Koristiti ove informacije u aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcije prijave"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Za osobu <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zaključani upravitelji lozinki"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Dodirnite da otključate"</string> diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml index 5e956a0fbc7a..c745ba50e533 100644 --- a/packages/CredentialManager/res/values-ca/strings.xml +++ b/packages/CredentialManager/res/values-ca/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Vols triar una opció per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Vols utilitzar aquesta informació a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcions d\'inici de sessió"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Per a <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestors de contrasenyes bloquejats"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Toca per desbloquejar"</string> diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml index 4a7b64342967..0bedef0d76d0 100644 --- a/packages/CredentialManager/res/values-cs/strings.xml +++ b/packages/CredentialManager/res/values-cs/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Vybrat možnost pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Použít tyto informace na <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Možnosti přihlašování"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pro uživatele <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Uzamčení správci hesel"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Klepnutím odemknete"</string> diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml index fe728dd12ad5..faae20b8d737 100644 --- a/packages/CredentialManager/res/values-da/strings.xml +++ b/packages/CredentialManager/res/values-da/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Vil du vælge en mulighed for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Vil du bruge disse oplysninger i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Valgmuligheder for login"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låste adgangskodeadministratorer"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tryk for at låse op"</string> diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml index d48b548c84eb..4e7682667e5a 100644 --- a/packages/CredentialManager/res/values-de/strings.xml +++ b/packages/CredentialManager/res/values-de/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Option für <xliff:g id="APP_NAME">%1$s</xliff:g> auswählen?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Diese Infos für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Anmeldeoptionen"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Für <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gesperrte Passwortmanager"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Zum Entsperren tippen"</string> diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml index a163954fb89b..4364d0f0ff45 100644 --- a/packages/CredentialManager/res/values-el/strings.xml +++ b/packages/CredentialManager/res/values-el/strings.xml @@ -52,13 +52,14 @@ <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_title_choose_option_for" msgid="4976380044745029107">"Επιλογή ενέργειας για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string> <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Να χρησιμοποιηθούν αυτές οι πληροφορίες στην εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Επιλογές σύνδεσης"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Κλειδωμένοι διαχειριστές κωδικών πρόσβασης"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Πατήστε για ξεκλείδωμα"</string> diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml index 44193666298f..34b3e94b6437 100644 --- a/packages/CredentialManager/res/values-en-rAU/strings.xml +++ b/packages/CredentialManager/res/values-en-rAU/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <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_title_use_info_on" msgid="8863708099535435146">"Use this info 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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tap to unlock"</string> diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml index b08425c9d79b..6b226bc82184 100644 --- a/packages/CredentialManager/res/values-en-rCA/strings.xml +++ b/packages/CredentialManager/res/values-en-rCA/strings.xml @@ -58,6 +58,7 @@ <string name="snackbar_action" msgid="37373514216505085">"View options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string> + <string name="button_label_view_more" msgid="3429098227286495651">"View more"</string> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tap to unlock"</string> diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml index 44193666298f..34b3e94b6437 100644 --- a/packages/CredentialManager/res/values-en-rGB/strings.xml +++ b/packages/CredentialManager/res/values-en-rGB/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <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_title_use_info_on" msgid="8863708099535435146">"Use this info 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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tap to unlock"</string> diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml index 44193666298f..34b3e94b6437 100644 --- a/packages/CredentialManager/res/values-en-rIN/strings.xml +++ b/packages/CredentialManager/res/values-en-rIN/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <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_title_use_info_on" msgid="8863708099535435146">"Use this info 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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tap to unlock"</string> diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml index e2f2dc3b3ffe..18d298bb0fb0 100644 --- a/packages/CredentialManager/res/values-en-rXC/strings.xml +++ b/packages/CredentialManager/res/values-en-rXC/strings.xml @@ -58,6 +58,7 @@ <string name="snackbar_action" msgid="37373514216505085">"View options"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string> + <string name="button_label_view_more" msgid="3429098227286495651">"View more"</string> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tap to unlock"</string> diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml index d8dd5ed46c7f..17d2e82c6d41 100644 --- a/packages/CredentialManager/res/values-es-rUS/strings.xml +++ b/packages/CredentialManager/res/values-es-rUS/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"¿Quieres una opción para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"¿Quieres usar esta información en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opciones de acceso"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Administradores de contraseñas bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Presiona para desbloquear"</string> diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml index 73c3b0d22e2d..533581d86740 100644 --- a/packages/CredentialManager/res/values-es/strings.xml +++ b/packages/CredentialManager/res/values-es/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"¿Elegir una opción para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"¿Usar esta información en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opciones de inicio de sesión"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestores de contraseñas bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tocar para desbloquear"</string> diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml index 6f7094153356..077ccdfbd9d3 100644 --- a/packages/CredentialManager/res/values-et/strings.xml +++ b/packages/CredentialManager/res/values-et/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Kas teha valik rakendusele <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Kas soovite kasutada seda teavet rakenduses <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sisselogimise valikud"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Kasutajale <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Lukustatud paroolihaldurid"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Avamiseks puudutage"</string> diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml index 3f08b61ad830..4cd4a61da3ac 100644 --- a/packages/CredentialManager/res/values-eu/strings.xml +++ b/packages/CredentialManager/res/values-eu/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako aukera bat hautatu nahi duzu?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan erabili nahi duzu informazio hori?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Saioa hasteko aukerak"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> erabiltzailearenak"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Blokeatutako pasahitz-kudeatzaileak"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Desblokeatzeko, sakatu hau"</string> diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml index a1d24460946b..2ef052fbc450 100644 --- a/packages/CredentialManager/res/values-fa/strings.xml +++ b/packages/CredentialManager/res/values-fa/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"گزینهای را برای <xliff:g id="APP_NAME">%1$s</xliff:g> انتخاب کنید؟"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"از این اطلاعات در <xliff:g id="APP_NAME">%1$s</xliff:g> استفاده شود؟"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"گزینههای ورود به سیستم"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"برای <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"مدیران گذرواژه قفلشده"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"برای باز کردن قفل ضربه بزنید"</string> diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml index 562741ed2a04..f034046425af 100644 --- a/packages/CredentialManager/res/values-fi/strings.xml +++ b/packages/CredentialManager/res/values-fi/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Valitaanko vaihtoehto, jota <xliff:g id="APP_NAME">%1$s</xliff:g> käyttää?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Saako <xliff:g id="APP_NAME">%1$s</xliff:g> käyttää näitä tietoja?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Kirjautumisvaihtoehdot"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Käyttäjä: <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Lukitut salasanojen ylläpitotyökalut"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Avaa napauttamalla"</string> diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml index af6076538c18..7b8f2a5d8a1d 100644 --- a/packages/CredentialManager/res/values-fr-rCA/strings.xml +++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Choisir une option pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Utiliser ces renseignements dans <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Options de connexion"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pour <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestionnaires de mots de passe verrouillés"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Touchez pour déverrouiller"</string> diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml index 293738d18738..ce487a91b0a4 100644 --- a/packages/CredentialManager/res/values-fr/strings.xml +++ b/packages/CredentialManager/res/values-fr/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Choisir une option pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Utiliser ces informations dans <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Options de connexion"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pour <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestionnaires de mots de passe verrouillés"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Appuyer pour déverrouiller"</string> diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml index f5d5a54c54bb..24e29d54d75e 100644 --- a/packages/CredentialManager/res/values-gl/strings.xml +++ b/packages/CredentialManager/res/values-gl/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Queres escoller unha opción para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Queres usar esta información en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcións de inicio de sesión"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Xestores de contrasinais bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Toca para desbloquear"</string> diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml index ea7809756d41..1ae3df2de523 100644 --- a/packages/CredentialManager/res/values-gu/strings.xml +++ b/packages/CredentialManager/res/values-gu/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g>નો વિકલ્પ પસંદ કરીએ?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> પર આ માહિતીનો ઉપયોગ કરીએ?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"સાઇન-ઇનના વિકલ્પો"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> માટે"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"લૉક કરેલા પાસવર્ડ મેનેજર"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"અનલૉક કરવા માટે ટૅપ કરો"</string> diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml index 5b07bdae4586..5dc1f0d5e6ff 100644 --- a/packages/CredentialManager/res/values-hi/strings.xml +++ b/packages/CredentialManager/res/values-hi/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> में साइन इन करने के लिए सेव किए गए विकल्पों में से किसी को चुनना है?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए, क्या इस जानकारी का इस्तेमाल करना है?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन इन करने के विकल्प"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> के लिए"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लॉक किए गए पासवर्ड मैनेजर"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"अनलॉक करने के लिए टैप करें"</string> diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml index d9ac2491ee0a..f1be424a9e31 100644 --- a/packages/CredentialManager/res/values-hr/strings.xml +++ b/packages/CredentialManager/res/values-hr/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Želite li odabrati opciju za <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Želite li koristiti te podatke u aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcije prijave"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Upravitelji zaključanih zaporki"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Dodirnite za otključavanje"</string> diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml index 92fa38869aff..4e851c9c09de 100644 --- a/packages/CredentialManager/res/values-hu/strings.xml +++ b/packages/CredentialManager/res/values-hu/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Kiválaszt egy lehetőséget a következőbe való bejelentkezéshez: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Használni szeretná ezt az információt a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásban?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Bejelentkezési beállítások"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zárolt jelszókezelők"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Koppintson a feloldáshoz"</string> diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml index 80947cc98844..f36ea9e0bad7 100644 --- a/packages/CredentialManager/res/values-hy/strings.xml +++ b/packages/CredentialManager/res/values-hy/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Ընտրե՞լ տարբերակ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Օգտագործե՞լ այս տեղեկությունները <xliff:g id="APP_NAME">%1$s</xliff:g> մտնելու համար"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Մուտքի տարբերակներ"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>-ի համար"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Գաղտնաբառերի կողպված կառավարիչներ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Հպեք ապակողպելու համար"</string> diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml index f72c36d383c6..f9a6176ffb1c 100644 --- a/packages/CredentialManager/res/values-in/strings.xml +++ b/packages/CredentialManager/res/values-in/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Pilih opsi untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Gunakan info ini di <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opsi login"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Untuk <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Pengelola sandi terkunci"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Ketuk untuk membuka kunci"</string> diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml index fa2d0b5b576b..e2aa5c02636e 100644 --- a/packages/CredentialManager/res/values-is/strings.xml +++ b/packages/CredentialManager/res/values-is/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Velja valkost fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Nota þessar upplýsingar í <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Innskráningarkostir"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Fyrir: <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Læst aðgangsorðastjórnun"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Ýttu til að opna"</string> diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml index a45f39a35941..8a0b48410dc6 100644 --- a/packages/CredentialManager/res/values-it/strings.xml +++ b/packages/CredentialManager/res/values-it/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Vuoi scegliere un\'opzione per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Vuoi usare questi dati su <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opzioni di accesso"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Per <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestori delle password bloccati"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tocca per sbloccare"</string> diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml index b18753339c67..47af8a727b7d 100644 --- a/packages/CredentialManager/res/values-iw/strings.xml +++ b/packages/CredentialManager/res/values-iw/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"רוצה לבחור אפשרות עבור <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"להשתמש במידע הזה בשביל <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"אפשרויות כניסה לחשבון"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"עבור <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"מנהלי סיסמאות נעולים"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"יש להקיש כדי לבטל את הנעילה"</string> diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml index f930d2a3afae..166aa73820a6 100644 --- a/packages/CredentialManager/res/values-ja/strings.xml +++ b/packages/CredentialManager/res/values-ja/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> のオプションを選択しますか?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> でこの情報を使用しますか?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ログイン オプション"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> 用"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"パスワード マネージャー ロック中"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"タップしてロック解除"</string> diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml index a53bb502da42..fbd70e48371a 100644 --- a/packages/CredentialManager/res/values-ka/strings.xml +++ b/packages/CredentialManager/res/values-ka/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"გსურთ აირჩიოთ ვარიანტი <xliff:g id="APP_NAME">%1$s</xliff:g>-ისთვის?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"გსურთ ამ ინფორმაციის გამოყენება <xliff:g id="APP_NAME">%1$s</xliff:g>-ში?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"სისტემაში შესვლის ვარიანტები"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>-ისთვის"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ჩაკეტილი პაროლის მმართველები"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"შეეხეთ განსაბლოკად"</string> diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml index 9635d8a3ebea..18ac0ebbe432 100644 --- a/packages/CredentialManager/res/values-kk/strings.xml +++ b/packages/CredentialManager/res/values-kk/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін опция таңдайсыз ба?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Бұл ақпарат <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында сақталсын ба?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Кіру опциялары"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> үшін"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Құлыпталған құпия сөз менеджерлері"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Құлыпты ашу үшін түртіңіз."</string> diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml index b1c3f5e17ac8..b402e8cd2d11 100644 --- a/packages/CredentialManager/res/values-km/strings.xml +++ b/packages/CredentialManager/res/values-km/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"ជ្រើសរើសជម្រើសសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"ប្រើព័ត៌មាននេះនៅលើ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ជម្រើសចូលគណនី"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"សម្រាប់ <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់ដែលបានចាក់សោ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ចុចដើម្បីដោះសោ"</string> diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml index 327535f2af74..99b4f45286cd 100644 --- a/packages/CredentialManager/res/values-kn/strings.xml +++ b/packages/CredentialManager/res/values-kn/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಆಯ್ಕೆಯನ್ನು ಆರಿಸಬೇಕೆ?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"ಈ ಮಾಹಿತಿಯನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ನಲ್ಲಿ ಬಳಸಬೇಕೆ?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ಸೈನ್ ಇನ್ ಆಯ್ಕೆಗಳು"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> ಗಾಗಿ"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ಪಾಸ್ವರ್ಡ್ ನಿರ್ವಾಹಕರನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml index 3ce02453227e..929944c8441d 100644 --- a/packages/CredentialManager/res/values-ko/strings.xml +++ b/packages/CredentialManager/res/values-ko/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱의 옵션을 선택하시겠습니까?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 이 정보를 사용하시나요?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"로그인 옵션"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>님의 로그인 정보"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"잠긴 비밀번호 관리자"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"탭하여 잠금 해제"</string> diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml index 7d828998aa86..f402c6c820ba 100644 --- a/packages/CredentialManager/res/values-ky/strings.xml +++ b/packages/CredentialManager/res/values-ky/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн параметр тандайсызбы?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Бул маалыматты <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда пайдаланасызбы?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Аккаунтка кирүү параметрлери"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> үчүн"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Кулпуланган сырсөздөрдү башкаргычтар"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Кулпусун ачуу үчүн таптаңыз"</string> diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml index 75726ea86fb4..be282d6fe671 100644 --- a/packages/CredentialManager/res/values-lo/strings.xml +++ b/packages/CredentialManager/res/values-lo/strings.xml @@ -58,6 +58,8 @@ <string name="snackbar_action" msgid="37373514216505085">"ເບິ່ງຕົວເລືອກ"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ສືບຕໍ່"</string> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ຕົວເລືອກການເຂົ້າສູ່ລະບົບ"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"ສຳລັບ <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ຕົວຈັດການລະຫັດຜ່ານທີ່ລັອກໄວ້"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ແຕະເພື່ອປົດລັອກ"</string> diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml index ed2db46ba45e..d9ae3a06b8d5 100644 --- a/packages/CredentialManager/res/values-lt/strings.xml +++ b/packages/CredentialManager/res/values-lt/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Pasirinkti parinktį programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Naudoti šią informaciją programoje „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Prisijungimo parinktys"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Skirta <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Užrakintos slaptažodžių tvarkyklės"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Palieskite, kad atrakintumėte"</string> diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml index c1ae23092fbc..16c0c41ef0e5 100644 --- a/packages/CredentialManager/res/values-lv/strings.xml +++ b/packages/CredentialManager/res/values-lv/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Vai izvēlēties opciju lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Vai izmantot šo informāciju lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Pierakstīšanās opcijas"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Lietotājam <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Paroļu pārvaldnieki, kuros nepieciešams autentificēties"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Pieskarieties, lai atbloķētu"</string> diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml index 969912b139d1..c449b90dd3ab 100644 --- a/packages/CredentialManager/res/values-mk/strings.xml +++ b/packages/CredentialManager/res/values-mk/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Избери опција за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Да се користат овие информации на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Опции за најавување"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"За <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заклучени управници со лозинки"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Допрете за да отклучите"</string> diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml index 498c9b0e3a9c..8cdf818b49c3 100644 --- a/packages/CredentialManager/res/values-ml/strings.xml +++ b/packages/CredentialManager/res/values-ml/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്ന ആപ്പിനായി ഒരു ഓപ്ഷൻ തിരഞ്ഞെടുക്കണോ?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിൽ ഈ വിവരങ്ങൾ ഉപയോഗിക്കണോ?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"സൈൻ ഇൻ ഓപ്ഷനുകൾ"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> എന്നയാൾക്ക്"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ലോക്ക് ചെയ്ത പാസ്വേഡ് സൈൻ ഇൻ മാനേജർമാർ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"അൺലോക്ക് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string> diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml index f8bd3586449b..00289b6f0377 100644 --- a/packages/CredentialManager/res/values-mn/strings.xml +++ b/packages/CredentialManager/res/values-mn/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д сонголт хийх үү?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Энэ мэдээллийг <xliff:g id="APP_NAME">%1$s</xliff:g>-д ашиглах уу?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Нэвтрэх сонголт"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>-д"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Түгжээтэй нууц үгний менежерүүд"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Түгжээг тайлахын тулд товшино уу"</string> diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml index 4e3c46e27e57..11973ba79c2e 100644 --- a/packages/CredentialManager/res/values-mr/strings.xml +++ b/packages/CredentialManager/res/values-mr/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी पर्याय निवडा?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"ही माहिती <xliff:g id="APP_NAME">%1$s</xliff:g> वर वापरायची का?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन इन पर्याय"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> साठी"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लॉक केलेले पासवर्ड व्यवस्थापक"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"अनलॉक करण्यासाठी टॅप करा"</string> diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml index f7cd421133df..cf9b13aea2d8 100644 --- a/packages/CredentialManager/res/values-ms/strings.xml +++ b/packages/CredentialManager/res/values-ms/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Pilih satu pilihan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Gunakan maklumat ini pada <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Pilihan log masuk"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Untuk <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Password Manager dikunci"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Ketik untuk membuka kunci"</string> diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml index 85ce79e9699f..8d556a402234 100644 --- a/packages/CredentialManager/res/values-my/strings.xml +++ b/packages/CredentialManager/res/values-my/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် တစ်ခုကိုရွေးမလား။"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> တွင် ဤအချက်အလက်ကို သုံးမလား။"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"လက်မှတ်ထိုးဝင်ရန် နည်းလမ်းများ"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> အတွက်"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"လော့ခ်ချထားသည့် စကားဝှက်မန်နေဂျာများ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ဖွင့်ရန် တို့ပါ"</string> diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml index b7f4aa5cd552..0dc750ebc419 100644 --- a/packages/CredentialManager/res/values-nb/strings.xml +++ b/packages/CredentialManager/res/values-nb/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Vil du velge et alternativ for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Vil du bruke denne informasjonen i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Påloggingsalternativer"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låste løsninger for passordlagring"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Trykk for å låse opp"</string> diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml index d181aa37aa07..a77082161c1e 100644 --- a/packages/CredentialManager/res/values-ne/strings.xml +++ b/packages/CredentialManager/res/values-ne/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन गर्न प्रयोग गरिने क्रिडेन्सियल छनौट गर्ने हो?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन गर्न गर्नका निम्ति यो जानकारी प्रयोग गर्ने हो?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन इनसम्बन्धी विकल्पहरू"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> का लागि"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लक गरिएका पासवर्ड म्यानेजरहरू"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"अनलक गर्न ट्याप गर्नुहोस्"</string> diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml index c26a8e51e183..b3497ee38c2f 100644 --- a/packages/CredentialManager/res/values-nl/strings.xml +++ b/packages/CredentialManager/res/values-nl/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Een optie kiezen voor <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Deze informatie gebruiken in <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opties voor inloggen"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Voor <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Vergrendelde wachtwoordmanagers"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tik om te ontgrendelen"</string> diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml index 75cc974a168b..bbe2aa6158ed 100644 --- a/packages/CredentialManager/res/values-or/strings.xml +++ b/packages/CredentialManager/res/values-or/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ଏକ ବିକଳ୍ପ ବାଛିବେ?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g>ରେ ଏହି ସୂଚନାକୁ ବ୍ୟବହାର କରିବେ?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ସାଇନ ଇନ ବିକଳ୍ପଗୁଡ଼ିକ"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>ରେ"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ଲକ ଥିବା Password Manager"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ଅନଲକ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string> diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml index b7797dae73be..da247682b400 100644 --- a/packages/CredentialManager/res/values-pa/strings.xml +++ b/packages/CredentialManager/res/values-pa/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਕਿਸੇ ਵਿਕਲਪ ਦੀ ਚੋਣ ਕਰਨੀ ਹੈ?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> \'ਤੇ ਇਸ ਜਾਣਕਾਰੀ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ਸਾਈਨ-ਇਨ ਕਰਨ ਦੇ ਵਿਕਲਪ"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ਲਾਕ ਕੀਤੇ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml index 03a547fe94fa..f5fffb3d2e0f 100644 --- a/packages/CredentialManager/res/values-pl/strings.xml +++ b/packages/CredentialManager/res/values-pl/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Wybrać opcję dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Użyć tych informacji w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcje logowania"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zablokowane menedżery haseł"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Kliknij, aby odblokować"</string> diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml index a7f1de13ea3a..5d23fed5dac8 100644 --- a/packages/CredentialManager/res/values-pt-rBR/strings.xml +++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Escolher uma opção para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Usar estas informações no app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opções de login"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gerenciadores de senha bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Toque para desbloquear"</string> diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml index 8ca0baf188c6..34a9d145db2a 100644 --- a/packages/CredentialManager/res/values-pt-rPT/strings.xml +++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml @@ -58,6 +58,8 @@ <string name="snackbar_action" msgid="37373514216505085">"Ver opções"</string> <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opções de início de sessão"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestores de palavras-passe bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tocar para desbloquear"</string> diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml index a7f1de13ea3a..5d23fed5dac8 100644 --- a/packages/CredentialManager/res/values-pt/strings.xml +++ b/packages/CredentialManager/res/values-pt/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Escolher uma opção para o app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Usar estas informações no app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opções de login"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gerenciadores de senha bloqueados"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Toque para desbloquear"</string> diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml index a9e76dea707b..9461e3cb19c2 100644 --- a/packages/CredentialManager/res/values-ro/strings.xml +++ b/packages/CredentialManager/res/values-ro/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Alegi o opțiune pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Folosești aceste informații în <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opțiuni de conectare"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pentru <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Manageri de parole blocate"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Atinge pentru a debloca"</string> diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml index 2694fa556200..8b9e23c0f092 100644 --- a/packages/CredentialManager/res/values-ru/strings.xml +++ b/packages/CredentialManager/res/values-ru/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Выберите данные для входа в приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Использовать эту информацию для входа в приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Варианты входа"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Для пользователя <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблокированные менеджеры паролей"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Нажмите для разблокировки"</string> diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml index fc0391efd5dd..63992de43a30 100644 --- a/packages/CredentialManager/res/values-si/strings.xml +++ b/packages/CredentialManager/res/values-si/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා විකල්පයක් තෝරන්නද?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> මත මෙම තතු භාවිතා කරන්න ද?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"පුරනය වීමේ විකල්ප"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> සඳහා"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"අගුළු දැමූ මුරපද කළමනාකරුවන්"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"අගුළු හැරීමට තට්ටු කරන්න"</string> diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml index fd20696b74cf..e89b6c324bd9 100644 --- a/packages/CredentialManager/res/values-sk/strings.xml +++ b/packages/CredentialManager/res/values-sk/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Chcete pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> vybrať možnosť?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Chcete použiť tieto informácie v aplikácii <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Možnosti prihlásenia"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pre používateľa <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Správcovia uzamknutých hesiel"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Odomknúť klepnutím"</string> diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml index 36dbf6e6aa1b..1a95c1499337 100644 --- a/packages/CredentialManager/res/values-sl/strings.xml +++ b/packages/CredentialManager/res/values-sl/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Izberite možnost za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Želite te podatke uporabiti v aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Možnosti prijave"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Za uporabnika <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zaklenjeni upravitelji gesel"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Dotaknite se, da odklenete"</string> diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml index a3b29eed96e5..adaf35eaf8e5 100644 --- a/packages/CredentialManager/res/values-sq/strings.xml +++ b/packages/CredentialManager/res/values-sq/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Të zgjidhet një opsion për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Të përdoren këto informacione në <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opsionet e identifikimit"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Për <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Menaxherët e fjalëkalimeve të kyçura"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Trokit për të shkyçur"</string> diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml index 698b3675273a..89c1a40b06af 100644 --- a/packages/CredentialManager/res/values-sr/strings.xml +++ b/packages/CredentialManager/res/values-sr/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Желите да одаберете опцију за апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Желите да користите те податке у апликацији <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Опције за пријављивање"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"За: <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Менаџери закључаних лозинки"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Додирните да бисте откључали"</string> diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml index 55127013d50e..c159600835ea 100644 --- a/packages/CredentialManager/res/values-sv/strings.xml +++ b/packages/CredentialManager/res/values-sv/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Vill du välja ett alternativ för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Vill du använda den här informationen på <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Inloggningsalternativ"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"För <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låsta lösenordshanterare"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Tryck för att låsa upp"</string> diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml index 065765d02a43..982b1ba4f6d2 100644 --- a/packages/CredentialManager/res/values-sw/strings.xml +++ b/packages/CredentialManager/res/values-sw/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Ungependa kuteua chaguo la <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Ungependa kutumia maelezo haya kwenye <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Chaguo za kuingia katika akaunti"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Kwa ajili ya <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Vidhibiti vya manenosiri vilivyofungwa"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Gusa ili ufungue"</string> diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml index 9c99f483f035..eabae9da442d 100644 --- a/packages/CredentialManager/res/values-ta/strings.xml +++ b/packages/CredentialManager/res/values-ta/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கான விருப்பத்தைத் தேர்வுசெய்யவா?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸில் இந்தத் தகவல்களைப் பயன்படுத்தவா?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"உள்நுழைவு விருப்பங்கள்"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>க்கு"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"பூட்டப்பட்ட கடவுச்சொல் நிர்வாகிகள்"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"அன்லாக் செய்ய தட்டவும்"</string> diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml index 9a9eafd5ff28..aa05e947c47a 100644 --- a/packages/CredentialManager/res/values-te/strings.xml +++ b/packages/CredentialManager/res/values-te/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం ఏదైనా ఆప్షన్ను ఎంచుకోవాలనుకుంటున్నారా?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"ఈ సమాచారాన్ని <xliff:g id="APP_NAME">%1$s</xliff:g>లో ఉపయోగించాలా?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"సైన్ ఇన్ ఆప్షన్లు"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> కోసం"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"లాక్ చేయబడిన పాస్వర్డ్ మేనేజర్లు"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"అన్లాక్ చేయడానికి ట్యాప్ చేయండి"</string> diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml index 0f6ab5a11cc9..e10016ca975d 100644 --- a/packages/CredentialManager/res/values-th/strings.xml +++ b/packages/CredentialManager/res/values-th/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"ต้องการเลือกตัวเลือกสำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"ใช้ข้อมูลนี้กับ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ตัวเลือกการลงชื่อเข้าใช้"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"สำหรับ <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"เครื่องมือจัดการรหัสผ่านที่ล็อกไว้"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"แตะเพื่อปลดล็อก"</string> diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml index 269d479f5977..c0ba96ff392f 100644 --- a/packages/CredentialManager/res/values-tl/strings.xml +++ b/packages/CredentialManager/res/values-tl/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Pumili ng opsyon para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Gamitin ang impormasyong ito sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Mga opsyon sa pag-sign in"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para kay <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Mga naka-lock na password manager"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"I-tap para i-unlock"</string> diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml index 857516c8432c..7d1d6970bce4 100644 --- a/packages/CredentialManager/res/values-tr/strings.xml +++ b/packages/CredentialManager/res/values-tr/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> için bir seçim yapmak ister misiniz?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Bu bilgiler <xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında kullanılsın mı?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Oturum açma seçenekleri"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> için"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Kilitli şifre yöneticileri"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Kilidi açmak için dokunun"</string> diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml index 6684c436fce2..a5ae72bc92ed 100644 --- a/packages/CredentialManager/res/values-uk/strings.xml +++ b/packages/CredentialManager/res/values-uk/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Вибрати варіант для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Використовувати ці дані в додатку <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Опції входу"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Для користувача <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблоковані менеджери паролів"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Торкніться, щоб розблокувати"</string> diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml index 0600a8d5f036..daadda8bca1e 100644 --- a/packages/CredentialManager/res/values-ur/strings.xml +++ b/packages/CredentialManager/res/values-ur/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے ایک اختیار منتخب کریں؟"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> پر اس معلومات کا استعمال کریں؟"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"سائن ان کے اختیارات"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> کے لیے"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"مقفل کردہ پاس ورڈ مینیجرز"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"غیر مقفل کرنے کیلئے تھپتھپائیں"</string> diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml index 4a77350ad083..a52095dd33f2 100644 --- a/packages/CredentialManager/res/values-uz/strings.xml +++ b/packages/CredentialManager/res/values-uz/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga kirish uchun maʼlumotlar tanlansinmi?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Bu axborotdan <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga kirish uchun foydalanilsinmi?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Kirish parametrlari"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> uchun"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Qulfli parol menejerlari"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Qulfni ochish uchun bosing"</string> diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml index da3ce4cf1414..0f8fb66568f7 100644 --- a/packages/CredentialManager/res/values-vi/strings.xml +++ b/packages/CredentialManager/res/values-vi/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Chọn một lựa chọn cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Sử dụng thông tin này trên <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Tuỳ chọn đăng nhập"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Cho <xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Trình quản lý mật khẩu đã khoá"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Nhấn để mở khoá"</string> diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml index b6338dc1fed2..4fded4b60b7d 100644 --- a/packages/CredentialManager/res/values-zh-rCN/strings.xml +++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml @@ -52,14 +52,14 @@ <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 /> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"要为“<xliff:g id="APP_NAME">%1$s</xliff:g>”选择一个选项吗?"</string> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"要将此信息用于“<xliff:g id="APP_NAME">%1$s</xliff:g>”吗?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"登录选项"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"用户:<xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已锁定的密码管理工具"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"点按即可解锁"</string> diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml index b4ae8f39f1d2..8486efebf26f 100644 --- a/packages/CredentialManager/res/values-zh-rHK/strings.xml +++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"要選擇適用於「<xliff:g id="APP_NAME">%1$s</xliff:g>」的項目嗎?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"要在「<xliff:g id="APP_NAME">%1$s</xliff:g>」上使用這些資料嗎?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"登入選項"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> 專用"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已鎖定的密碼管理工具"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"輕按即可解鎖"</string> diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml index a79f7cfd8cb1..0414538bf840 100644 --- a/packages/CredentialManager/res/values-zh-rTW/strings.xml +++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"要選擇適用於「<xliff:g id="APP_NAME">%1$s</xliff:g>」的項目嗎?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"要在「<xliff:g id="APP_NAME">%1$s</xliff:g>」上使用這項資訊嗎?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"登入選項"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> 專用"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已鎖定的密碼管理工具"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"輕觸即可解鎖"</string> diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml index 2a419829dce9..8aaf8692ebe0 100644 --- a/packages/CredentialManager/res/values-zu/strings.xml +++ b/packages/CredentialManager/res/values-zu/strings.xml @@ -53,12 +53,13 @@ <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> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Khetha ongakhetha kukho kwe-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> - <!-- no translation found for get_dialog_title_use_info_on (8863708099535435146) --> - <skip /> + <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Sebenzisa lolu lwazi ku-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <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> <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Okungakhethwa kukho kokungena ngemvume"</string> + <!-- no translation found for button_label_view_more (3429098227286495651) --> + <skip /> <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Okuka-<xliff:g id="USERNAME">%1$s</xliff:g>"</string> <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Abaphathi bephasiwedi abakhiyiwe"</string> <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Thepha ukuze uvule"</string> diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml index e9b2e1041c22..3e652517270d 100644 --- a/packages/CredentialManager/res/values/strings.xml +++ b/packages/CredentialManager/res/values/strings.xml @@ -117,6 +117,8 @@ <string name="get_dialog_sign_in_type_username_separator" translatable="false">" • "</string> <!-- This text is followed by a list of one or more options. [CHAR LIMIT=80] --> <string name="get_dialog_title_sign_in_options">Sign-in options</string> + <!-- Button label for viewing the full information about an account. [CHAR LIMIT=80] --> + <string name="button_label_view_more">View more</string> <!-- Column heading for displaying sign-ins for a specific username. [CHAR LIMIT=80] --> <string name="get_dialog_heading_for_username">For <xliff:g id="username" example="becket@gmail.com">%1$s</xliff:g></string> <!-- Column heading for displaying locked (that is, the user needs to first authenticate via pin, fingerprint, faceId, etc.) sign-ins. [CHAR LIMIT=80] --> diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index dd4419bc6540..a9bee039264e 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -65,8 +65,8 @@ class CredentialManagerRepo( ) val originName: String? = when (requestInfo?.type) { - RequestInfo.TYPE_CREATE -> requestInfo?.createCredentialRequest?.origin - RequestInfo.TYPE_GET -> requestInfo?.getCredentialRequest?.origin + RequestInfo.TYPE_CREATE -> requestInfo.createCredentialRequest?.origin + RequestInfo.TYPE_GET -> requestInfo.getCredentialRequest?.origin else -> null } @@ -107,7 +107,7 @@ class CredentialManagerRepo( initialUiState = when (requestInfo?.type) { RequestInfo.TYPE_CREATE -> { - val defaultProviderId = userConfigRepo.getDefaultProviderId() + val defaultProviderIdSetByUser = userConfigRepo.getDefaultProviderId() val isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse() val providerEnableListUiState = getCreateProviderEnableListInitialUiState() val providerDisableListUiState = getCreateProviderDisableListInitialUiState() @@ -115,12 +115,14 @@ class CredentialManagerRepo( getCreateRequestDisplayInfoInitialUiState(originName)!! UiState( createCredentialUiState = CreateFlowUtils.toCreateCredentialUiState( - providerEnableListUiState, - providerDisableListUiState, - defaultProviderId, - requestDisplayInfoUiState, + enabledProviders = providerEnableListUiState, + disabledProviders = providerDisableListUiState, + defaultProviderIdPreferredByApp = + requestDisplayInfoUiState.appPreferredDefaultProviderId, + defaultProviderIdSetByUser = defaultProviderIdSetByUser, + requestDisplayInfo = requestDisplayInfoUiState, isOnPasskeyIntroStateAlready = false, - isPasskeyFirstUse + isPasskeyFirstUse = isPasskeyFirstUse, )!!, getCredentialUiState = null, cancelRequestState = cancelUiRequestState diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt index 24f92c00c772..7581b5c0aa91 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt @@ -19,9 +19,9 @@ package com.android.credentialmanager import android.content.Intent import android.credentials.ui.BaseDialogResult import android.credentials.ui.RequestInfo +import android.net.Uri import android.os.Bundle import android.os.ResultReceiver -import android.provider.Settings import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.rememberLauncherForActivityResult @@ -192,7 +192,9 @@ class CredentialSelectorActivity : ComponentActivity() { this@CredentialSelectorActivity.finish() } else if (dialogState == DialogState.CANCELED_FOR_SETTINGS) { Log.d(Constants.LOG_TAG, "Received signal to finish the activity and launch settings.") - this@CredentialSelectorActivity.startActivity(Intent(Settings.ACTION_SYNC_SETTINGS)) + val settingsIntent = Intent(ACTION_CREDENTIAL_PROVIDER) + settingsIntent.data = Uri.parse("package:" + this.getPackageName()) + this@CredentialSelectorActivity.startActivity(settingsIntent) this@CredentialSelectorActivity.finish() } } @@ -222,4 +224,8 @@ class CredentialSelectorActivity : ComponentActivity() { dismissOnTimeout = true, ) } + + companion object { + const val ACTION_CREDENTIAL_PROVIDER = "android.settings.CREDENTIAL_PROVIDER" + } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt index 29ec970966d6..4d2bb4c6016a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt @@ -250,9 +250,15 @@ class CredentialSelectorViewModel( return } val newUiState = CreateFlowUtils.toCreateCredentialUiState( - prevUiState.enabledProviders, prevUiState.disabledProviders, - userConfigRepo.getDefaultProviderId(), prevUiState.requestDisplayInfo, true, - userConfigRepo.getIsPasskeyFirstUse()) + enabledProviders = prevUiState.enabledProviders, + disabledProviders = prevUiState.disabledProviders, + defaultProviderIdPreferredByApp = + prevUiState.requestDisplayInfo.appPreferredDefaultProviderId, + defaultProviderIdSetByUser = userConfigRepo.getDefaultProviderId(), + requestDisplayInfo = prevUiState.requestDisplayInfo, + isOnPasskeyIntroStateAlready = true, + isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse() + ) if (newUiState == null) { Log.d(Constants.LOG_TAG, "Unable to update create ui state") onInternalError() diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index 725401fb85bb..f08bbf430440 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -46,6 +46,7 @@ import com.android.credentialmanager.getflow.AuthenticationEntryInfo import com.android.credentialmanager.getflow.CredentialEntryInfo import com.android.credentialmanager.getflow.ProviderInfo import com.android.credentialmanager.getflow.RemoteEntryInfo +import com.android.credentialmanager.getflow.TopBrandingContent import androidx.credentials.CreateCredentialRequest import androidx.credentials.CreateCustomCredentialRequest import androidx.credentials.CreatePasswordRequest @@ -198,7 +199,8 @@ class GetFlowUtils { it.type, it.credentialRetrievalData, it.credentialRetrievalData, - it.isSystemProviderRequired + it.isSystemProviderRequired, + it.allowedProviders, ) if (credentialOptionJetpack is GetPublicKeyCredentialOption) { credentialOptionJetpack.preferImmediatelyAvailableCredentials @@ -206,11 +208,33 @@ class GetFlowUtils { false } } + val preferUiBrandingComponentName = + getCredentialRequest.data.getParcelable( + "androidx.credentials.BUNDLE_KEY_PREFER_UI_BRANDING_COMPONENT_NAME", + ComponentName::class.java + ) + val preferTopBrandingContent: TopBrandingContent? = + if (preferUiBrandingComponentName == null) null + else { + val (displayName, icon) = getServiceLabelAndIcon( + context.packageManager, preferUiBrandingComponentName.flattenToString()) + ?: Pair(null, null) + if (displayName != null && icon != null) { + TopBrandingContent(icon, displayName) + } else { + null + } + } return com.android.credentialmanager.getflow.RequestDisplayInfo( appName = originName ?: getAppLabel(context.packageManager, requestInfo.appPackageName) ?: return null, - preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials + preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials, + preferIdentityDocUi = getCredentialRequest.data.getBoolean( + // TODO(b/276777444): replace with direct library constant reference once + // exposed. + "androidx.credentials.BUNDLE_KEY_PREFER_IDENTITY_DOC_UI"), + preferTopBrandingContent = preferTopBrandingContent, ) } @@ -241,20 +265,13 @@ class GetFlowUtils { userName = credentialEntry.username.toString(), displayName = credentialEntry.displayName?.toString(), icon = credentialEntry.icon.loadDrawable(context), - shouldTintIcon = credentialEntry.isDefaultIcon ?: false, + shouldTintIcon = credentialEntry.isDefaultIcon, lastUsedTimeMillis = credentialEntry.lastUsedTime, isAutoSelectable = credentialEntry.isAutoSelectAllowed && credentialEntry.autoSelectAllowedFromOption, )) } is PublicKeyCredentialEntry -> { - val passkeyUsername = credentialEntry.username.toString() - val passkeyDisplayName = credentialEntry.displayName?.toString() ?: "" - val (username, displayName) = userAndDisplayNameForPasskey( - passkeyUsername = passkeyUsername, - passkeyDisplayName = passkeyDisplayName, - ) - result.add(CredentialEntryInfo( providerId = providerId, providerDisplayName = providerLabel, @@ -264,8 +281,8 @@ class GetFlowUtils { fillInIntent = it.frameworkExtrasIntent, credentialType = CredentialType.PASSKEY, credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(), - userName = username, - displayName = displayName, + userName = credentialEntry.username.toString(), + displayName = credentialEntry.displayName?.toString(), icon = credentialEntry.icon.loadDrawable(context), shouldTintIcon = credentialEntry.isDefaultIcon, lastUsedTimeMillis = credentialEntry.lastUsedTime, @@ -465,8 +482,12 @@ class CreateFlowUtils { createCredentialRequest.type, createCredentialRequest.credentialData, createCredentialRequest.candidateQueryData, - createCredentialRequest.isSystemProviderRequired + createCredentialRequest.isSystemProviderRequired, + createCredentialRequest.origin, ) + val appPreferredDefaultProviderId: String? = + if (!requestInfo.hasPermissionToOverrideDefault()) null + else createCredentialRequestJetpack?.displayInfo?.preferDefaultProvider return when (createCredentialRequestJetpack) { is CreatePasswordRequest -> RequestDisplayInfo( createCredentialRequestJetpack.id, @@ -475,6 +496,7 @@ class CreateFlowUtils { appLabel, context.getDrawable(R.drawable.ic_password_24) ?: return null, preferImmediatelyAvailableCredentials = false, + appPreferredDefaultProviderId = appPreferredDefaultProviderId, ) is CreatePublicKeyCredentialRequest -> { newRequestDisplayInfoFromPasskeyJson( @@ -483,6 +505,7 @@ class CreateFlowUtils { context = context, preferImmediatelyAvailableCredentials = createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, + appPreferredDefaultProviderId = appPreferredDefaultProviderId, ) } is CreateCustomCredentialRequest -> { @@ -498,6 +521,7 @@ class CreateFlowUtils { typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context) ?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null, preferImmediatelyAvailableCredentials = false, + appPreferredDefaultProviderId = appPreferredDefaultProviderId, ) } else -> null @@ -507,20 +531,27 @@ class CreateFlowUtils { fun toCreateCredentialUiState( enabledProviders: List<EnabledProviderInfo>, disabledProviders: List<DisabledProviderInfo>?, - defaultProviderId: String?, + defaultProviderIdPreferredByApp: String?, + defaultProviderIdSetByUser: String?, requestDisplayInfo: RequestDisplayInfo, isOnPasskeyIntroStateAlready: Boolean, isPasskeyFirstUse: Boolean, ): CreateCredentialUiState? { var lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo? = null var remoteEntry: RemoteInfo? = null - var defaultProvider: EnabledProviderInfo? = null + var defaultProviderPreferredByApp: EnabledProviderInfo? = null + var defaultProviderSetByUser: EnabledProviderInfo? = null var createOptionsPairs: MutableList<Pair<CreateOptionInfo, EnabledProviderInfo>> = mutableListOf() enabledProviders.forEach { enabledProvider -> - if (defaultProviderId != null) { - if (enabledProvider.id == defaultProviderId) { - defaultProvider = enabledProvider + if (defaultProviderIdPreferredByApp != null) { + if (enabledProvider.id == defaultProviderIdPreferredByApp) { + defaultProviderPreferredByApp = enabledProvider + } + } + if (defaultProviderIdSetByUser != null) { + if (enabledProvider.id == defaultProviderIdSetByUser) { + defaultProviderSetByUser = enabledProvider } } if (enabledProvider.createOptions.isNotEmpty()) { @@ -539,12 +570,14 @@ class CreateFlowUtils { remoteEntry = currRemoteEntry } } + val defaultProvider = defaultProviderPreferredByApp ?: defaultProviderSetByUser val initialScreenState = toCreateScreenState( - /*createOptionSize=*/createOptionsPairs.size, - /*isOnPasskeyIntroStateAlready=*/isOnPasskeyIntroStateAlready, - /*requestDisplayInfo=*/requestDisplayInfo, - /*defaultProvider=*/defaultProvider, /*remoteEntry=*/remoteEntry, - /*isPasskeyFirstUse=*/isPasskeyFirstUse + createOptionSize = createOptionsPairs.size, + isOnPasskeyIntroStateAlready = isOnPasskeyIntroStateAlready, + requestDisplayInfo = requestDisplayInfo, + defaultProvider = defaultProvider, + remoteEntry = remoteEntry, + isPasskeyFirstUse = isPasskeyFirstUse ) ?: return null return CreateCredentialUiState( enabledProviders = enabledProviders, @@ -670,6 +703,7 @@ class CreateFlowUtils { appLabel: String, context: Context, preferImmediatelyAvailableCredentials: Boolean, + appPreferredDefaultProviderId: String?, ): RequestDisplayInfo? { val json = JSONObject(requestJson) var passkeyUsername = "" @@ -690,6 +724,7 @@ class CreateFlowUtils { appLabel, context.getDrawable(R.drawable.ic_passkey_24) ?: return null, preferImmediatelyAvailableCredentials, + appPreferredDefaultProviderId, ) } } @@ -703,7 +738,7 @@ class CreateFlowUtils { * 2) username on top if display-name is not available. * 3) don't show username on second line if username == display-name */ -private fun userAndDisplayNameForPasskey( +fun userAndDisplayNameForPasskey( passkeyUsername: String, passkeyDisplayName: String, ): Pair<String, String> { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt index 307d95313ec8..10a75d436a5b 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt @@ -316,7 +316,7 @@ fun ModalBottomSheetLayout( rememberModalBottomSheetState(Hidden), sheetShape: Shape = MaterialTheme.shapes.large, sheetElevation: Dp = ModalBottomSheetDefaults.Elevation, - sheetBackgroundColor: Color = MaterialTheme.colorScheme.surface, + sheetBackgroundColor: Color, sheetContentColor: Color = contentColorFor(sheetBackgroundColor), content: @Composable () -> Unit ) { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt index 7a720b1e858b..2dba2ab6777c 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt @@ -32,7 +32,6 @@ import androidx.compose.material.icons.outlined.Lock import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SuggestionChip import androidx.compose.material3.SuggestionChipDefaults import androidx.compose.material3.TopAppBar @@ -52,6 +51,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.LayoutDirection @@ -80,6 +80,7 @@ fun Entry( /** If true, draws a trailing lock icon. */ isLockedAuthEntry: Boolean = false, enforceOneLine: Boolean = false, + onTextLayout: (TextLayoutResult) -> Unit = {}, ) { val iconPadding = Modifier.wrapContentSize().padding( // Horizontal padding should be 16dp, but the suggestion chip itself @@ -104,7 +105,11 @@ fun Entry( ) { // Apply weight so that the trailing icon can always show. Column(modifier = Modifier.wrapContentHeight().fillMaxWidth().weight(1f)) { - SmallTitleText(text = entryHeadlineText, enforceOneLine = enforceOneLine) + SmallTitleText( + text = entryHeadlineText, + enforceOneLine = enforceOneLine, + onTextLayout = onTextLayout, + ) if (passwordValue != null) { Row( modifier = Modifier.fillMaxWidth().padding(top = 4.dp), @@ -142,10 +147,18 @@ fun Entry( ) } } else if (entrySecondLineText != null) { - BodySmallText(text = entrySecondLineText, enforceOneLine = enforceOneLine) + BodySmallText( + text = entrySecondLineText, + enforceOneLine = enforceOneLine, + onTextLayout = onTextLayout, + ) } if (entryThirdLineText != null) { - BodySmallText(text = entryThirdLineText, enforceOneLine = enforceOneLine) + BodySmallText( + text = entryThirdLineText, + enforceOneLine = enforceOneLine, + onTextLayout = onTextLayout, + ) } } if (isLockedAuthEntry) { @@ -155,7 +168,7 @@ fun Entry( // Decorative purpose only. contentDescription = null, modifier = Modifier.size(24.dp), - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = LocalAndroidColorScheme.current.colorOnSurfaceVariant, ) } } @@ -169,7 +182,7 @@ fun Entry( Icon( modifier = iconSize, bitmap = iconImageBitmap, - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = LocalAndroidColorScheme.current.colorOnSurfaceVariant, // Decorative purpose only. contentDescription = null, ) @@ -193,7 +206,7 @@ fun Entry( Icon( modifier = iconSize, imageVector = iconImageVector, - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = LocalAndroidColorScheme.current.colorOnSurfaceVariant, // Decorative purpose only. contentDescription = null, ) @@ -205,7 +218,7 @@ fun Entry( Icon( modifier = iconSize, painter = iconPainter, - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = LocalAndroidColorScheme.current.colorOnSurfaceVariant, // Decorative purpose only. contentDescription = null, ) @@ -217,9 +230,8 @@ fun Entry( border = null, colors = SuggestionChipDefaults.suggestionChipColors( containerColor = LocalAndroidColorScheme.current.colorSurfaceContainerHigh, - // TODO: remove? - labelColor = MaterialTheme.colorScheme.onSurfaceVariant, - iconContentColor = MaterialTheme.colorScheme.onSurfaceVariant, + labelColor = LocalAndroidColorScheme.current.colorOnSurfaceVariant, + iconContentColor = LocalAndroidColorScheme.current.colorOnSurfaceVariant, ), ) } @@ -282,7 +294,7 @@ fun PasskeyBenefitRow( Icon( modifier = Modifier.size(24.dp), painter = leadingIconPainter, - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = LocalAndroidColorScheme.current.colorOnSurfaceVariant, // Decorative purpose only. contentDescription = null, ) @@ -341,7 +353,7 @@ fun MoreOptionTopAppBar( R.string.accessibility_back_arrow_button ), modifier = Modifier.size(24.dp).autoMirrored(), - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = LocalAndroidColorScheme.current.colorOnSurfaceVariant, ) } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SectionHeader.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SectionHeader.kt index 358122809985..2df0c7a9b1e8 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SectionHeader.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SectionHeader.kt @@ -20,25 +20,31 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme @Composable -fun CredentialListSectionHeader(text: String) { - InternalSectionHeader(text, MaterialTheme.colorScheme.onSurfaceVariant) +fun CredentialListSectionHeader(text: String, isFirstSection: Boolean) { + InternalSectionHeader( + text = text, + color = LocalAndroidColorScheme.current.colorOnSurfaceVariant, + applyTopPadding = !isFirstSection + ) } @Composable fun MoreAboutPasskeySectionHeader(text: String) { - InternalSectionHeader(text, MaterialTheme.colorScheme.onSurface) + InternalSectionHeader(text, LocalAndroidColorScheme.current.colorOnSurface) } @Composable -private fun InternalSectionHeader(text: String, color: Color) { - Row(modifier = Modifier.fillMaxWidth().wrapContentHeight().padding(top = 8.dp)) { +private fun InternalSectionHeader(text: String, color: Color, applyTopPadding: Boolean = false) { + Row(modifier = Modifier.fillMaxWidth().wrapContentHeight().padding( + top = if (applyTopPadding) 8.dp else 0.dp + )) { SectionHeaderText( text, modifier = Modifier.padding(top = 20.dp, bottom = 8.dp), diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt index 22871bcbe767..6b46636964e4 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt @@ -22,8 +22,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow +import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme /** * The headline for a screen. E.g. "Create a passkey for X", "Choose a saved sign-in for X". @@ -35,7 +37,7 @@ fun HeadlineText(text: String, modifier: Modifier = Modifier) { Text( modifier = modifier.wrapContentSize(), text = text, - color = MaterialTheme.colorScheme.onSurface, + color = LocalAndroidColorScheme.current.colorOnSurface, textAlign = TextAlign.Center, style = MaterialTheme.typography.headlineSmall, ) @@ -49,7 +51,7 @@ fun BodyMediumText(text: String, modifier: Modifier = Modifier) { Text( modifier = modifier.wrapContentSize(), text = text, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = LocalAndroidColorScheme.current.colorOnSurfaceVariant, style = MaterialTheme.typography.bodyMedium, ) } @@ -58,14 +60,20 @@ fun BodyMediumText(text: String, modifier: Modifier = Modifier) { * Body-small typography; on-surface-variant color. */ @Composable -fun BodySmallText(text: String, modifier: Modifier = Modifier, enforceOneLine: Boolean = false) { +fun BodySmallText( + text: String, + modifier: Modifier = Modifier, + enforceOneLine: Boolean = false, + onTextLayout: (TextLayoutResult) -> Unit = {}, +) { Text( modifier = modifier.wrapContentSize(), text = text, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = LocalAndroidColorScheme.current.colorOnSurfaceVariant, style = MaterialTheme.typography.bodySmall, overflow = TextOverflow.Ellipsis, - maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE + maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE, + onTextLayout = onTextLayout, ) } @@ -77,7 +85,7 @@ fun LargeTitleText(text: String, modifier: Modifier = Modifier) { Text( modifier = modifier.wrapContentSize(), text = text, - color = MaterialTheme.colorScheme.onSurface, + color = LocalAndroidColorScheme.current.colorOnSurface, style = MaterialTheme.typography.titleLarge, ) } @@ -86,14 +94,20 @@ fun LargeTitleText(text: String, modifier: Modifier = Modifier) { * Title-small typography; on-surface color. */ @Composable -fun SmallTitleText(text: String, modifier: Modifier = Modifier, enforceOneLine: Boolean = false) { +fun SmallTitleText( + text: String, + modifier: Modifier = Modifier, + enforceOneLine: Boolean = false, + onTextLayout: (TextLayoutResult) -> Unit = {}, +) { Text( modifier = modifier.wrapContentSize(), text = text, - color = MaterialTheme.colorScheme.onSurface, + color = LocalAndroidColorScheme.current.colorOnSurface, style = MaterialTheme.typography.titleSmall, overflow = TextOverflow.Ellipsis, - maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE + maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE, + onTextLayout = onTextLayout, ) } @@ -145,7 +159,7 @@ fun LargeLabelTextOnSurfaceVariant(text: String, modifier: Modifier = Modifier) modifier = modifier.wrapContentSize(), text = text, textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = LocalAndroidColorScheme.current.colorOnSurfaceVariant, style = MaterialTheme.typography.labelLarge, ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt index 648d83268541..96010cc66821 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt @@ -30,7 +30,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.Divider -import androidx.compose.material3.MaterialTheme import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.NewReleases import androidx.compose.material.icons.filled.Add @@ -67,6 +66,7 @@ import com.android.credentialmanager.common.ui.SheetContainerCard import com.android.credentialmanager.common.ui.PasskeyBenefitRow import com.android.credentialmanager.common.ui.HeadlineText import com.android.credentialmanager.logging.CreateCredentialEvent +import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme import com.android.internal.logging.UiEventLogger.UiEventEnum @Composable @@ -435,7 +435,7 @@ fun MoreOptionsRowIntroCard( } SheetContainerCard { item { HeadlineIcon(imageVector = Icons.Outlined.NewReleases) } - item { Divider(thickness = 24.dp, color = Color.Transparent) } + item { Divider(thickness = 16.dp, color = Color.Transparent) } item { HeadlineText( text = stringResource( @@ -559,7 +559,7 @@ fun CreationSelectionCard( item { Divider( thickness = 1.dp, - color = MaterialTheme.colorScheme.outlineVariant, + color = LocalAndroidColorScheme.current.colorOutlineVariant, modifier = Modifier.padding(vertical = 16.dp) ) } @@ -633,6 +633,7 @@ fun MoreAboutPasskeysIntroCard( } } item { + Divider(thickness = 8.dp, color = Color.Transparent) MoreAboutPasskeySectionHeader( text = stringResource(R.string.public_key_cryptography_title) ) @@ -641,6 +642,7 @@ fun MoreAboutPasskeysIntroCard( } } item { + Divider(thickness = 8.dp, color = Color.Transparent) MoreAboutPasskeySectionHeader( text = stringResource(R.string.improved_account_security_title) ) @@ -649,6 +651,7 @@ fun MoreAboutPasskeysIntroCard( } } item { + Divider(thickness = 8.dp, color = Color.Transparent) MoreAboutPasskeySectionHeader( text = stringResource(R.string.seamless_transition_title) ) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt index 4332fb34ce79..12bb6298b282 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt @@ -107,6 +107,7 @@ data class RequestDisplayInfo( val appName: String, val typeIcon: Drawable, val preferImmediatelyAvailableCredentials: Boolean, + val appPreferredDefaultProviderId: String?, ) /** diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt index 6d7ecd70eb0b..516c1a3bb1e3 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt @@ -16,6 +16,7 @@ package com.android.credentialmanager.getflow +import android.graphics.drawable.Drawable import android.text.TextUtils import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.result.ActivityResult @@ -34,11 +35,14 @@ import androidx.compose.material3.Divider import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.unit.dp import androidx.core.graphics.drawable.toBitmap import com.android.credentialmanager.CredentialSelectorViewModel @@ -62,6 +66,7 @@ import com.android.credentialmanager.common.ui.HeadlineIcon import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant import com.android.credentialmanager.common.ui.Snackbar import com.android.credentialmanager.logging.GetCredentialEvent +import com.android.credentialmanager.userAndDisplayNameForPasskey import com.android.internal.logging.UiEventLogger.UiEventEnum @Composable @@ -158,30 +163,35 @@ fun PrimarySelectionCard( onMoreOptionSelected: () -> Unit, onLog: @Composable (UiEventEnum) -> Unit, ) { + val showMoreForTruncatedEntry = remember { mutableStateOf(false) } val sortedUserNameToCredentialEntryList = providerDisplayInfo.sortedUserNameToCredentialEntryList val authenticationEntryList = providerDisplayInfo.authenticationEntryList SheetContainerCard { - // When only one provider (not counting the remote-only provider) exists, display that - // provider's icon + name up top. - if (providerInfoList.size <= 2) { // It's only possible to be the single provider case - // if we are started with no more than 2 providers. - val nonRemoteProviderList = providerInfoList.filter( - { it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty() } - ) - if (nonRemoteProviderList.size == 1) { - val providerInfo = nonRemoteProviderList.firstOrNull() // First should always work - // but just to be safe. + val preferTopBrandingContent = requestDisplayInfo.preferTopBrandingContent + if (preferTopBrandingContent != null) { + item { + HeadlineProviderIconAndName( + preferTopBrandingContent.icon, + preferTopBrandingContent.displayName + ) + } + } else { + // When only one provider (not counting the remote-only provider) exists, display that + // provider's icon + name up top. + val providersWithActualEntries = providerInfoList.filter { + it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty() + } + if (providersWithActualEntries.size == 1) { + // First should always work but just to be safe. + val providerInfo = providersWithActualEntries.firstOrNull() if (providerInfo != null) { item { - HeadlineIcon( - bitmap = providerInfo.icon.toBitmap().asImageBitmap(), - tint = Color.Unspecified, + HeadlineProviderIconAndName( + providerInfo.icon, + providerInfo.displayName ) } - item { Divider(thickness = 4.dp, color = Color.Transparent) } - item { LargeLabelTextOnSurfaceVariant(text = providerInfo.displayName) } - item { Divider(thickness = 16.dp, color = Color.Transparent) } } } } @@ -209,6 +219,8 @@ fun PrimarySelectionCard( Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { val usernameForCredentialSize = sortedUserNameToCredentialEntryList.size val authenticationEntrySize = authenticationEntryList.size + // If true, render a view more button for the single truncated entry on the + // front page. // Show max 4 entries in this primary page if (usernameForCredentialSize + authenticationEntrySize <= 4) { sortedUserNameToCredentialEntryList.forEach { @@ -216,6 +228,9 @@ fun PrimarySelectionCard( credentialEntryInfo = it.sortedCredentialEntryList.first(), onEntrySelected = onEntrySelected, enforceOneLine = true, + onTextLayout = { + showMoreForTruncatedEntry.value = it.hasVisualOverflow + } ) } authenticationEntryList.forEach { @@ -269,6 +284,13 @@ fun PrimarySelectionCard( onMoreOptionSelected ) } + } else if (showMoreForTruncatedEntry.value) { + { + ActionButton( + stringResource(R.string.button_label_view_more), + onMoreOptionSelected + ) + } } else null, rightButton = if (activeEntry != null) { // Only one sign-in options exist { @@ -305,12 +327,15 @@ fun AllSignInOptionCard( bottomPadding = 0.dp, ) }) { + var isFirstSection = true // For username items(sortedUserNameToCredentialEntryList) { item -> PerUserNameCredentials( perUserNameCredentialEntryList = item, onEntrySelected = onEntrySelected, + isFirstSection = isFirstSection, ) + isFirstSection = false } // Locked password manager if (authenticationEntryList.isNotEmpty()) { @@ -318,7 +343,9 @@ fun AllSignInOptionCard( LockedCredentials( authenticationEntryList = authenticationEntryList, onEntrySelected = onEntrySelected, + isFirstSection = isFirstSection, ) + isFirstSection = false } } // From another device @@ -328,27 +355,43 @@ fun AllSignInOptionCard( RemoteEntryCard( remoteEntry = remoteEntry, onEntrySelected = onEntrySelected, + isFirstSection = isFirstSection, ) + isFirstSection = false } } // Manage sign-ins (action chips) item { ActionChips( providerInfoList = providerInfoList, - onEntrySelected = onEntrySelected + onEntrySelected = onEntrySelected, + isFirstSection = isFirstSection, ) + isFirstSection = false } } onLog(GetCredentialEvent.CREDMAN_GET_CRED_ALL_SIGN_IN_OPTION_CARD) } -// TODO: create separate rows for primary and secondary pages. -// TODO: reuse rows and columns across types. +@Composable +fun HeadlineProviderIconAndName( + icon: Drawable, + name: String, +) { + HeadlineIcon( + bitmap = icon.toBitmap().asImageBitmap(), + tint = Color.Unspecified, + ) + Divider(thickness = 4.dp, color = Color.Transparent) + LargeLabelTextOnSurfaceVariant(text = name) + Divider(thickness = 16.dp, color = Color.Transparent) +} @Composable fun ActionChips( providerInfoList: List<ProviderInfo>, onEntrySelected: (BaseEntry) -> Unit, + isFirstSection: Boolean, ) { val actionChips = providerInfoList.flatMap { it.actionEntryList } if (actionChips.isEmpty()) { @@ -356,7 +399,8 @@ fun ActionChips( } CredentialListSectionHeader( - text = stringResource(R.string.get_dialog_heading_manage_sign_ins) + text = stringResource(R.string.get_dialog_heading_manage_sign_ins), + isFirstSection = isFirstSection, ) CredentialContainerCard { Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { @@ -371,9 +415,11 @@ fun ActionChips( fun RemoteEntryCard( remoteEntry: RemoteEntryInfo, onEntrySelected: (BaseEntry) -> Unit, + isFirstSection: Boolean, ) { CredentialListSectionHeader( - text = stringResource(R.string.get_dialog_heading_from_another_device) + text = stringResource(R.string.get_dialog_heading_from_another_device), + isFirstSection = isFirstSection, ) CredentialContainerCard { Column( @@ -395,9 +441,11 @@ fun RemoteEntryCard( fun LockedCredentials( authenticationEntryList: List<AuthenticationEntryInfo>, onEntrySelected: (BaseEntry) -> Unit, + isFirstSection: Boolean, ) { CredentialListSectionHeader( - text = stringResource(R.string.get_dialog_heading_locked_password_managers) + text = stringResource(R.string.get_dialog_heading_locked_password_managers), + isFirstSection = isFirstSection, ) CredentialContainerCard { Column( @@ -415,11 +463,13 @@ fun LockedCredentials( fun PerUserNameCredentials( perUserNameCredentialEntryList: PerUserNameCredentialEntryList, onEntrySelected: (BaseEntry) -> Unit, + isFirstSection: Boolean, ) { CredentialListSectionHeader( text = stringResource( R.string.get_dialog_heading_for_username, perUserNameCredentialEntryList.userName - ) + ), + isFirstSection = isFirstSection, ) CredentialContainerCard { Column( @@ -438,7 +488,12 @@ fun CredentialEntryRow( credentialEntryInfo: CredentialEntryInfo, onEntrySelected: (BaseEntry) -> Unit, enforceOneLine: Boolean = false, + onTextLayout: (TextLayoutResult) -> Unit = {}, ) { + val (username, displayName) = if (credentialEntryInfo.credentialType == CredentialType.PASSKEY) + userAndDisplayNameForPasskey( + credentialEntryInfo.userName, credentialEntryInfo.displayName ?: "") + else Pair(credentialEntryInfo.userName, credentialEntryInfo.displayName) Entry( onClick = { onEntrySelected(credentialEntryInfo) }, iconImageBitmap = credentialEntryInfo.icon?.toBitmap()?.asImageBitmap(), @@ -447,13 +502,13 @@ fun CredentialEntryRow( iconPainter = if (credentialEntryInfo.icon == null) painterResource(R.drawable.ic_other_sign_in_24) else null, - entryHeadlineText = credentialEntryInfo.userName, + entryHeadlineText = username, entrySecondLineText = if ( credentialEntryInfo.credentialType == CredentialType.PASSWORD) { "••••••••••••" } else { val itemsToDisplay = listOf( - credentialEntryInfo.displayName, + displayName, credentialEntryInfo.credentialTypeDisplayName, credentialEntryInfo.providerDisplayName ).filterNot(TextUtils::isEmpty) @@ -463,6 +518,7 @@ fun CredentialEntryRow( ) }, enforceOneLine = enforceOneLine, + onTextLayout = onTextLayout, ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt index 7a8679038579..a4a163bbabc3 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt @@ -42,7 +42,7 @@ internal fun hasContentToDisplay(state: GetCredentialUiState): Boolean { } internal fun isFallbackScreen(state: GetCredentialUiState): Boolean { - return false + return state.requestDisplayInfo.preferIdentityDocUi } internal fun findAutoSelectEntry(providerDisplayInfo: ProviderDisplayInfo): CredentialEntryInfo? { @@ -172,6 +172,14 @@ class ActionEntryInfo( data class RequestDisplayInfo( val appName: String, val preferImmediatelyAvailableCredentials: Boolean, + val preferIdentityDocUi: Boolean, + // A top level branding icon + display name preferred by the app. + val preferTopBrandingContent: TopBrandingContent?, +) + +data class TopBrandingContent( + val icon: Drawable, + val displayName: String, ) /** diff --git a/packages/CredentialManager/src/com/android/credentialmanager/ui/theme/AndroidColorScheme.kt b/packages/CredentialManager/src/com/android/credentialmanager/ui/theme/AndroidColorScheme.kt index 8928e1869838..a33904d30393 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/ui/theme/AndroidColorScheme.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/ui/theme/AndroidColorScheme.kt @@ -42,6 +42,9 @@ val LocalAndroidColorScheme = class AndroidColorScheme internal constructor(context: Context) { val colorSurfaceBright = getColor(context, R.attr.materialColorSurfaceBright) val colorSurfaceContainerHigh = getColor(context, R.attr.materialColorSurfaceContainerHigh) + val colorOutlineVariant = getColor(context, R.attr.materialColorOutlineVariant) + val colorOnSurface = getColor(context, R.attr.materialColorOnSurface) + val colorOnSurfaceVariant = getColor(context, R.attr.materialColorOnSurfaceVariant) companion object { fun getColor(context: Context, attr: Int): Color { diff --git a/packages/DynamicSystemInstallationService/AndroidManifest.xml b/packages/DynamicSystemInstallationService/AndroidManifest.xml index c2aaeace1af6..776bf2b761ce 100644 --- a/packages/DynamicSystemInstallationService/AndroidManifest.xml +++ b/packages/DynamicSystemInstallationService/AndroidManifest.xml @@ -36,6 +36,10 @@ <data android:scheme="http" /> <data android:scheme="https" /> </intent-filter> + <intent-filter> + <action android:name="android.os.image.action.START_INSTALL" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> </activity> <receiver diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 2c4b4786c968..b265a425d2e7 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -19,6 +19,7 @@ package com.android.dynsystem; import static android.os.AsyncTask.Status.FINISHED; import static android.os.AsyncTask.Status.PENDING; import static android.os.AsyncTask.Status.RUNNING; +import static android.os.image.DynamicSystemClient.ACTION_HIDE_NOTIFICATION; import static android.os.image.DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE; import static android.os.image.DynamicSystemClient.ACTION_START_INSTALL; import static android.os.image.DynamicSystemClient.CAUSE_ERROR_EXCEPTION; @@ -27,6 +28,8 @@ import static android.os.image.DynamicSystemClient.CAUSE_ERROR_IO; import static android.os.image.DynamicSystemClient.CAUSE_INSTALL_CANCELLED; import static android.os.image.DynamicSystemClient.CAUSE_INSTALL_COMPLETED; import static android.os.image.DynamicSystemClient.CAUSE_NOT_SPECIFIED; +import static android.os.image.DynamicSystemClient.KEY_ENABLE_WHEN_COMPLETED; +import static android.os.image.DynamicSystemClient.KEY_ONE_SHOT; import static android.os.image.DynamicSystemClient.STATUS_IN_PROGRESS; import static android.os.image.DynamicSystemClient.STATUS_IN_USE; import static android.os.image.DynamicSystemClient.STATUS_NOT_STARTED; @@ -77,8 +80,6 @@ public class DynamicSystemInstallationService extends Service private static final String TAG = "DynamicSystemInstallationService"; - // TODO (b/131866826): This is currently for test only. Will move this to System API. - static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED"; static final String KEY_DSU_SLOT = "KEY_DSU_SLOT"; static final String DEFAULT_DSU_SLOT = "dsu"; static final String KEY_PUBKEY = "KEY_PUBKEY"; @@ -172,6 +173,8 @@ public class DynamicSystemInstallationService extends Service // This is for testing only now private boolean mEnableWhenCompleted; + private boolean mOneShot; + private boolean mHideNotification; private InstallationAsyncTask.Progress mInstallTaskProgress; private InstallationAsyncTask mInstallTask; @@ -229,6 +232,8 @@ public class DynamicSystemInstallationService extends Service executeRebootToNormalCommand(); } else if (ACTION_NOTIFY_IF_IN_USE.equals(action)) { executeNotifyIfInUseCommand(); + } else if (ACTION_HIDE_NOTIFICATION.equals(action)) { + executeHideNotificationCommand(); } return Service.START_NOT_STICKY; @@ -318,6 +323,7 @@ public class DynamicSystemInstallationService extends Service long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0); long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0); mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false); + mOneShot = intent.getBooleanExtra(KEY_ONE_SHOT, true); String dsuSlot = intent.getStringExtra(KEY_DSU_SLOT); String publicKey = intent.getStringExtra(KEY_PUBKEY); @@ -384,9 +390,9 @@ public class DynamicSystemInstallationService extends Service boolean enabled = false; if (mInstallTask != null && mInstallTask.isCompleted()) { - enabled = mInstallTask.commit(); + enabled = mInstallTask.commit(mOneShot); } else if (isDynamicSystemInstalled()) { - enabled = mDynSystem.setEnable(true, true); + enabled = mDynSystem.setEnable(true, mOneShot); } else { Log.e(TAG, "Trying to reboot to AOT while there is no complete installation"); return; @@ -439,12 +445,16 @@ public class DynamicSystemInstallationService extends Service private void executeNotifyIfInUseCommand() { switch (getStatus()) { case STATUS_IN_USE: - startForeground(NOTIFICATION_ID, - buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED)); + if (!mHideNotification) { + startForeground(NOTIFICATION_ID, + buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED)); + } break; case STATUS_READY: - startForeground(NOTIFICATION_ID, - buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED)); + if (!mHideNotification) { + startForeground(NOTIFICATION_ID, + buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED)); + } break; case STATUS_IN_PROGRESS: break; @@ -454,6 +464,16 @@ public class DynamicSystemInstallationService extends Service } } + private void executeHideNotificationCommand() { + mHideNotification = true; + switch (getStatus()) { + case STATUS_IN_USE: + case STATUS_READY: + stopForeground(STOP_FOREGROUND_REMOVE); + break; + } + } + private void resetTaskAndStop() { resetTaskAndStop(/* removeNotification= */ false); } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index a41399fb0d0d..42b620abe734 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -803,7 +803,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { return mIsCompleted; } - boolean commit() { - return mDynSystem.setEnable(true, true); + boolean commit(boolean oneShot) { + return mDynSystem.setEnable(true, oneShot); } } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java index 64e42cc595ec..b52272961e4b 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java @@ -16,6 +16,8 @@ package com.android.dynsystem; +import static android.os.image.DynamicSystemClient.KEY_KEYGUARD_USE_DEFAULT_STRINGS; + import android.app.Activity; import android.app.KeyguardManager; import android.content.Context; @@ -47,10 +49,7 @@ public class VerificationActivity extends Activity { KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); if (km != null) { - String title = getString(R.string.keyguard_title); - String description = getString(R.string.keyguard_description); - Intent intent = km.createConfirmDeviceCredentialIntent(title, description); - + Intent intent = createConfirmDeviceCredentialIntent(km); if (intent == null) { Log.d(TAG, "This device is not protected by a password/pin"); startInstallationService(); @@ -63,6 +62,23 @@ public class VerificationActivity extends Activity { } } + private Intent createConfirmDeviceCredentialIntent(KeyguardManager km) { + final boolean useDefaultStrings = + getIntent().getBooleanExtra(KEY_KEYGUARD_USE_DEFAULT_STRINGS, false); + final String title; + final String description; + if (useDefaultStrings) { + // Use default strings provided by keyguard manager + title = null; + description = null; + } else { + // Use custom strings provided by DSU + title = getString(R.string.keyguard_title); + description = getString(R.string.keyguard_description); + } + return km.createConfirmDeviceCredentialIntent(title, description); + } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) { diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp index 69a1d7fa59e4..ef0d122c7273 100644 --- a/packages/PrintSpooler/tests/outofprocess/Android.bp +++ b/packages/PrintSpooler/tests/outofprocess/Android.bp @@ -31,7 +31,7 @@ android_test { libs: ["android.test.runner.stubs"], static_libs: [ "androidx.test.rules", - "ub-uiautomator", + "androidx.test.uiautomator_uiautomator", "mockito-target-minus-junit4", "print-test-util-lib", ], diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java index 132545b2d5d2..1509b7077046 100644 --- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java @@ -35,15 +35,15 @@ import android.print.test.services.AddPrintersActivity; import android.print.test.services.FirstPrintService; import android.print.test.services.PrinterDiscoverySessionCallbacks; import android.print.test.services.StubbablePrinterDiscoverySession; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.UiSelector; -import android.support.test.uiautomator.Until; import android.util.Log; import androidx.test.filters.LargeTest; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiSelector; +import androidx.test.uiautomator.Until; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SettingsLib/AppPreference/res/values-af/strings.xml b/packages/SettingsLib/AppPreference/res/values-af/strings.xml new file mode 100644 index 000000000000..442059c809fd --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-af/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Kitsprogram"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-am/strings.xml b/packages/SettingsLib/AppPreference/res/values-am/strings.xml new file mode 100644 index 000000000000..f5786b393a74 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-am/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"በቅጽበት መተግበሪያ"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-as/strings.xml b/packages/SettingsLib/AppPreference/res/values-as/strings.xml new file mode 100644 index 000000000000..a7a666ec36cf --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-as/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"তাৎক্ষণিক এপ্"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-az/strings.xml b/packages/SettingsLib/AppPreference/res/values-az/strings.xml new file mode 100644 index 000000000000..8af282b93de1 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-az/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Ani tətbiq"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/AppPreference/res/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000000..009cf22f5be5 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant aplikacija"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-be/strings.xml b/packages/SettingsLib/AppPreference/res/values-be/strings.xml new file mode 100644 index 000000000000..39babeded72a --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-be/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Імгненная праграма"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-bg/strings.xml b/packages/SettingsLib/AppPreference/res/values-bg/strings.xml new file mode 100644 index 000000000000..6df64831c8dc --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-bg/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Мигновено приложение"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-bn/strings.xml b/packages/SettingsLib/AppPreference/res/values-bn/strings.xml new file mode 100644 index 000000000000..be1785e220ec --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-bn/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ইনস্ট্যান্ট অ্যাপ"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-bs/strings.xml b/packages/SettingsLib/AppPreference/res/values-bs/strings.xml new file mode 100644 index 000000000000..009cf22f5be5 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-bs/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant aplikacija"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ca/strings.xml b/packages/SettingsLib/AppPreference/res/values-ca/strings.xml new file mode 100644 index 000000000000..68b17cd561e6 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ca/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Aplicació instantània"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-cs/strings.xml b/packages/SettingsLib/AppPreference/res/values-cs/strings.xml new file mode 100644 index 000000000000..a423b22e7998 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-cs/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Okamžitá aplikace"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-da/strings.xml b/packages/SettingsLib/AppPreference/res/values-da/strings.xml new file mode 100644 index 000000000000..c648449ed933 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-da/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant-app"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-el/strings.xml b/packages/SettingsLib/AppPreference/res/values-el/strings.xml new file mode 100644 index 000000000000..ad834b1382dd --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-el/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant Εφαρμογή"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-en-rAU/strings.xml b/packages/SettingsLib/AppPreference/res/values-en-rAU/strings.xml new file mode 100644 index 000000000000..595fea362cb9 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-en-rAU/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant app"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-en-rGB/strings.xml b/packages/SettingsLib/AppPreference/res/values-en-rGB/strings.xml new file mode 100644 index 000000000000..595fea362cb9 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-en-rGB/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant app"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-en-rIN/strings.xml b/packages/SettingsLib/AppPreference/res/values-en-rIN/strings.xml new file mode 100644 index 000000000000..595fea362cb9 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-en-rIN/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant app"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-es-rUS/strings.xml b/packages/SettingsLib/AppPreference/res/values-es-rUS/strings.xml new file mode 100644 index 000000000000..0d95fd987819 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-es-rUS/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"App instantánea"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-es/strings.xml b/packages/SettingsLib/AppPreference/res/values-es/strings.xml new file mode 100644 index 000000000000..97fc538ffe78 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-es/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Aplicación instantánea"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-et/strings.xml b/packages/SettingsLib/AppPreference/res/values-et/strings.xml new file mode 100644 index 000000000000..73fd742e7c23 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-et/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Installimata avatav rakendus"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-eu/strings.xml b/packages/SettingsLib/AppPreference/res/values-eu/strings.xml new file mode 100644 index 000000000000..e35e1138a043 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-eu/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Zuzeneko aplikazioa"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-fa/strings.xml b/packages/SettingsLib/AppPreference/res/values-fa/strings.xml new file mode 100644 index 000000000000..d525e85c3ec3 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-fa/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"برنامه فوری"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-fi/strings.xml b/packages/SettingsLib/AppPreference/res/values-fi/strings.xml new file mode 100644 index 000000000000..b3d564d05379 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-fi/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Pikasovellus"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-fr/strings.xml b/packages/SettingsLib/AppPreference/res/values-fr/strings.xml new file mode 100644 index 000000000000..4771382de59b --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-fr/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Appli instantanée"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-gu/strings.xml b/packages/SettingsLib/AppPreference/res/values-gu/strings.xml new file mode 100644 index 000000000000..b58791c3e973 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-gu/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ઝટપટ ઍપ્લિકેશન"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-hi/strings.xml b/packages/SettingsLib/AppPreference/res/values-hi/strings.xml new file mode 100644 index 000000000000..8e8901085d1a --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-hi/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"इंस्टैंट ऐप्लिकेशन"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-hr/strings.xml b/packages/SettingsLib/AppPreference/res/values-hr/strings.xml new file mode 100644 index 000000000000..009cf22f5be5 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-hr/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant aplikacija"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-hu/strings.xml b/packages/SettingsLib/AppPreference/res/values-hu/strings.xml new file mode 100644 index 000000000000..0aa715474ef2 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-hu/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Azonnali alkalmazás"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-hy/strings.xml b/packages/SettingsLib/AppPreference/res/values-hy/strings.xml new file mode 100644 index 000000000000..4ed6de5530ce --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-hy/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Ակնթարթային հավելված"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-in/strings.xml b/packages/SettingsLib/AppPreference/res/values-in/strings.xml new file mode 100644 index 000000000000..ccb16e7769f2 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-in/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Aplikasi instan"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-is/strings.xml b/packages/SettingsLib/AppPreference/res/values-is/strings.xml new file mode 100644 index 000000000000..0bdbbbca782c --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-is/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Skyndiforrit"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-it/strings.xml b/packages/SettingsLib/AppPreference/res/values-it/strings.xml new file mode 100644 index 000000000000..5d200c4455c2 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-it/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"App istantanea"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-iw/strings.xml b/packages/SettingsLib/AppPreference/res/values-iw/strings.xml new file mode 100644 index 000000000000..9048f511fc60 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-iw/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"אפליקציה ללא התקנה"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ja/strings.xml b/packages/SettingsLib/AppPreference/res/values-ja/strings.xml new file mode 100644 index 000000000000..d48a9fafa866 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ja/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant App"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ka/strings.xml b/packages/SettingsLib/AppPreference/res/values-ka/strings.xml new file mode 100644 index 000000000000..bf94b4b3ce16 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ka/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"მყისიერი აპი"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-kk/strings.xml b/packages/SettingsLib/AppPreference/res/values-kk/strings.xml new file mode 100644 index 000000000000..78ffbfed1fc5 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-kk/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Лездік қолданба"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-km/strings.xml b/packages/SettingsLib/AppPreference/res/values-km/strings.xml new file mode 100644 index 000000000000..b60696d03d30 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-km/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"កម្មវិធីប្រើភ្លាមៗ"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-kn/strings.xml b/packages/SettingsLib/AppPreference/res/values-kn/strings.xml new file mode 100644 index 000000000000..f1224e49e0e3 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-kn/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ತತ್ಕ್ಷಣ ಆ್ಯಪ್"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ko/strings.xml b/packages/SettingsLib/AppPreference/res/values-ko/strings.xml new file mode 100644 index 000000000000..0b592d720b61 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ko/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"인스턴트 앱"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ky/strings.xml b/packages/SettingsLib/AppPreference/res/values-ky/strings.xml new file mode 100644 index 000000000000..9a5bf8f320ff --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ky/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Ыкчам ачылуучу колдонмо"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-lo/strings.xml b/packages/SettingsLib/AppPreference/res/values-lo/strings.xml new file mode 100644 index 000000000000..8d4c2fade54a --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-lo/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ອິນສະແຕນແອັບ"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-lt/strings.xml b/packages/SettingsLib/AppPreference/res/values-lt/strings.xml new file mode 100644 index 000000000000..b7702abc8639 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-lt/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Akimirksniu įkeliama programėlė"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-lv/strings.xml b/packages/SettingsLib/AppPreference/res/values-lv/strings.xml new file mode 100644 index 000000000000..571618835e3f --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-lv/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Tūlītējā lietotne"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-mk/strings.xml b/packages/SettingsLib/AppPreference/res/values-mk/strings.xml new file mode 100644 index 000000000000..9dacef25aa1c --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-mk/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Инстант апликација"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ml/strings.xml b/packages/SettingsLib/AppPreference/res/values-ml/strings.xml new file mode 100644 index 000000000000..e3b258e78b9e --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ml/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ഇൻസ്റ്റന്റ് ആപ്പ്"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-mn/strings.xml b/packages/SettingsLib/AppPreference/res/values-mn/strings.xml new file mode 100644 index 000000000000..b545ed6b5bca --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-mn/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Шуурхай апп"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-mr/strings.xml b/packages/SettingsLib/AppPreference/res/values-mr/strings.xml new file mode 100644 index 000000000000..027b050a5cb9 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-mr/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"इंस्टंट अॅप"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ms/strings.xml b/packages/SettingsLib/AppPreference/res/values-ms/strings.xml new file mode 100644 index 000000000000..65742a03c76c --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ms/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Apl segera"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-my/strings.xml b/packages/SettingsLib/AppPreference/res/values-my/strings.xml new file mode 100644 index 000000000000..2933fd725d8e --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-my/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"အသင့်သုံးအက်ပ်"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-nb/strings.xml b/packages/SettingsLib/AppPreference/res/values-nb/strings.xml new file mode 100644 index 000000000000..c648449ed933 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-nb/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant-app"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ne/strings.xml b/packages/SettingsLib/AppPreference/res/values-ne/strings.xml new file mode 100644 index 000000000000..9152882b15b3 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ne/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"इन्स्टेन्ट एप"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-nl/strings.xml b/packages/SettingsLib/AppPreference/res/values-nl/strings.xml new file mode 100644 index 000000000000..c648449ed933 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-nl/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant-app"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-or/strings.xml b/packages/SettingsLib/AppPreference/res/values-or/strings.xml new file mode 100644 index 000000000000..a64fa892995a --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-or/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ଇନଷ୍ଟାଣ୍ଟ ଆପ"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-pa/strings.xml b/packages/SettingsLib/AppPreference/res/values-pa/strings.xml new file mode 100644 index 000000000000..9d5b65527e7c --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-pa/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ਤਤਕਾਲ ਐਪ"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-pl/strings.xml b/packages/SettingsLib/AppPreference/res/values-pl/strings.xml new file mode 100644 index 000000000000..a4b4046edd90 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-pl/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Aplikacja błyskawiczna"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-pt-rBR/strings.xml b/packages/SettingsLib/AppPreference/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000000..6b0e04967697 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-pt-rBR/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"App instantâneo"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-pt-rPT/strings.xml b/packages/SettingsLib/AppPreference/res/values-pt-rPT/strings.xml new file mode 100644 index 000000000000..8fb947325098 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-pt-rPT/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"App instantânea"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-pt/strings.xml b/packages/SettingsLib/AppPreference/res/values-pt/strings.xml new file mode 100644 index 000000000000..6b0e04967697 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-pt/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"App instantâneo"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ro/strings.xml b/packages/SettingsLib/AppPreference/res/values-ro/strings.xml new file mode 100644 index 000000000000..820b45c53dcf --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ro/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Aplicație instantanee"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ru/strings.xml b/packages/SettingsLib/AppPreference/res/values-ru/strings.xml new file mode 100644 index 000000000000..64fbfa2c5447 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ru/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Приложение с мгновенным запуском"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-si/strings.xml b/packages/SettingsLib/AppPreference/res/values-si/strings.xml new file mode 100644 index 000000000000..3307b4ea0241 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-si/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ක්ෂණික යෙදුම"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-sk/strings.xml b/packages/SettingsLib/AppPreference/res/values-sk/strings.xml new file mode 100644 index 000000000000..fc00b9fddd2b --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-sk/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Okamžitá aplikácia"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-sl/strings.xml b/packages/SettingsLib/AppPreference/res/values-sl/strings.xml new file mode 100644 index 000000000000..4c4fdddf515d --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-sl/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Nenamestljiva aplikacija"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-sq/strings.xml b/packages/SettingsLib/AppPreference/res/values-sq/strings.xml new file mode 100644 index 000000000000..d6e9dd171f6f --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-sq/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Aplikacioni i çastit"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-sr/strings.xml b/packages/SettingsLib/AppPreference/res/values-sr/strings.xml new file mode 100644 index 000000000000..9dacef25aa1c --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-sr/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Инстант апликација"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-sv/strings.xml b/packages/SettingsLib/AppPreference/res/values-sv/strings.xml new file mode 100644 index 000000000000..5ef5d7f5a230 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-sv/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Snabbapp"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-sw/strings.xml b/packages/SettingsLib/AppPreference/res/values-sw/strings.xml new file mode 100644 index 000000000000..2f045b05b24a --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-sw/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Programu inayofunguka papo hapo"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-te/strings.xml b/packages/SettingsLib/AppPreference/res/values-te/strings.xml new file mode 100644 index 000000000000..2f93c2aa6de8 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-te/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"ఇన్స్టంట్ యాప్"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-th/strings.xml b/packages/SettingsLib/AppPreference/res/values-th/strings.xml new file mode 100644 index 000000000000..d48a9fafa866 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-th/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant App"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-tl/strings.xml b/packages/SettingsLib/AppPreference/res/values-tl/strings.xml new file mode 100644 index 000000000000..595fea362cb9 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-tl/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Instant app"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-tr/strings.xml b/packages/SettingsLib/AppPreference/res/values-tr/strings.xml new file mode 100644 index 000000000000..d90ce9ca927b --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-tr/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Hazır uygulama"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-uk/strings.xml b/packages/SettingsLib/AppPreference/res/values-uk/strings.xml new file mode 100644 index 000000000000..eff0e783ae8e --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-uk/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Додаток із миттєвим запуском"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-ur/strings.xml b/packages/SettingsLib/AppPreference/res/values-ur/strings.xml new file mode 100644 index 000000000000..f62fe6213ceb --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-ur/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"فوری ایپ"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-uz/strings.xml b/packages/SettingsLib/AppPreference/res/values-uz/strings.xml new file mode 100644 index 000000000000..b9ac33050f1b --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-uz/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Darhol ochiladigan ilova"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-vi/strings.xml b/packages/SettingsLib/AppPreference/res/values-vi/strings.xml new file mode 100644 index 000000000000..d23dad71ad04 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-vi/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Ứng dụng tức thì"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-zh-rCN/strings.xml b/packages/SettingsLib/AppPreference/res/values-zh-rCN/strings.xml new file mode 100644 index 000000000000..0a00c52b74b8 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-zh-rCN/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"免安装应用"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-zh-rHK/strings.xml b/packages/SettingsLib/AppPreference/res/values-zh-rHK/strings.xml new file mode 100644 index 000000000000..da93bfc9f0ff --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-zh-rHK/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"免安裝應用程式"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-zh-rTW/strings.xml b/packages/SettingsLib/AppPreference/res/values-zh-rTW/strings.xml new file mode 100644 index 000000000000..da93bfc9f0ff --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-zh-rTW/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"免安裝應用程式"</string> +</resources> diff --git a/packages/SettingsLib/AppPreference/res/values-zu/strings.xml b/packages/SettingsLib/AppPreference/res/values-zu/strings.xml new file mode 100644 index 000000000000..d73467c41ee3 --- /dev/null +++ b/packages/SettingsLib/AppPreference/res/values-zu/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="install_type_instant" msgid="7217305006127216917">"Ama-app asheshayo"</string> +</resources> diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java index 8cda37665035..bf24c86b8d8b 100644 --- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java +++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java @@ -59,32 +59,36 @@ public class FooterPreference extends Preference { public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); TextView title = holder.itemView.findViewById(android.R.id.title); - if (!TextUtils.isEmpty(mContentDescription)) { + if (title != null && !TextUtils.isEmpty(mContentDescription)) { title.setContentDescription(mContentDescription); } TextView learnMore = holder.itemView.findViewById(R.id.settingslib_learn_more); - if (learnMore != null && mLearnMoreListener != null) { - learnMore.setVisibility(View.VISIBLE); - if (TextUtils.isEmpty(mLearnMoreText)) { - mLearnMoreText = learnMore.getText(); + if (learnMore != null) { + if (mLearnMoreListener != null) { + learnMore.setVisibility(View.VISIBLE); + if (TextUtils.isEmpty(mLearnMoreText)) { + mLearnMoreText = learnMore.getText(); + } else { + learnMore.setText(mLearnMoreText); + } + SpannableString learnMoreText = new SpannableString(mLearnMoreText); + if (mLearnMoreSpan != null) { + learnMoreText.removeSpan(mLearnMoreSpan); + } + mLearnMoreSpan = new FooterLearnMoreSpan(mLearnMoreListener); + learnMoreText.setSpan(mLearnMoreSpan, 0, + learnMoreText.length(), 0); + learnMore.setText(learnMoreText); } else { - learnMore.setText(mLearnMoreText); + learnMore.setVisibility(View.GONE); } - SpannableString learnMoreText = new SpannableString(mLearnMoreText); - if (mLearnMoreSpan != null) { - learnMoreText.removeSpan(mLearnMoreSpan); - } - mLearnMoreSpan = new FooterLearnMoreSpan(mLearnMoreListener); - learnMoreText.setSpan(mLearnMoreSpan, 0, - learnMoreText.length(), 0); - learnMore.setText(learnMoreText); - } else { - learnMore.setVisibility(View.GONE); } View icon = holder.itemView.findViewById(R.id.icon_frame); - icon.setVisibility(mIconVisibility); + if (icon != null) { + icon.setVisibility(mIconVisibility); + } } @Override diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS index 1b3020af3d78..81340f561bc1 100644 --- a/packages/SettingsLib/OWNERS +++ b/packages/SettingsLib/OWNERS @@ -3,9 +3,8 @@ dsandler@android.com edgarwang@google.com evanlaird@google.com juliacr@google.com -lijun@google.com -songchenxi@google.com yantingyang@google.com +ykhung@google.com # Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS) per-file *.xml=* diff --git a/packages/SettingsLib/ProfileSelector/res/values-af/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-af/strings.xml new file mode 100644 index 000000000000..8055736b368e --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-af/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Persoonlik"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Werk"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-as/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-as/strings.xml new file mode 100644 index 000000000000..9ac55bbea3a9 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-as/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ব্যক্তিগত"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"কৰ্মস্থান"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-az/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-az/strings.xml new file mode 100644 index 000000000000..5e9d3fb2e051 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-az/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Şəxsi"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"İş"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000000..7f9cf212af3a --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Lično"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Posao"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-be/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-be/strings.xml new file mode 100644 index 000000000000..b7774de2130c --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-be/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Асабістыя"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Працоўныя"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-bg/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-bg/strings.xml new file mode 100644 index 000000000000..f1ca6b21bf8c --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-bg/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Лични"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Служебни"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-bn/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-bn/strings.xml new file mode 100644 index 000000000000..385a90153f05 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-bn/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ব্যক্তিগত"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"অফিস"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-bs/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-bs/strings.xml new file mode 100644 index 000000000000..19390c2df5d9 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-bs/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Lično"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Poslovno"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ca/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ca/strings.xml new file mode 100644 index 000000000000..0190b9129112 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ca/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Feina"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml new file mode 100644 index 000000000000..d5f920a363d3 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobní"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Prácovní"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-da/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-da/strings.xml new file mode 100644 index 000000000000..9d41b9c1f3f3 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-da/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personlig"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Arbejde"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml new file mode 100644 index 000000000000..0832eab2ea17 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Προσωπικά"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Εργασία"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-en-rAU/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-en-rAU/strings.xml new file mode 100644 index 000000000000..478e6035b1d1 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-en-rAU/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Work"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-en-rGB/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-en-rGB/strings.xml new file mode 100644 index 000000000000..478e6035b1d1 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-en-rGB/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Work"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-en-rIN/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-en-rIN/strings.xml new file mode 100644 index 000000000000..478e6035b1d1 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-en-rIN/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Work"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-es-rUS/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-es-rUS/strings.xml new file mode 100644 index 000000000000..b73026ab56d0 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-es-rUS/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Trabajo"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-es/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-es/strings.xml new file mode 100644 index 000000000000..b73026ab56d0 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-es/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Trabajo"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-et/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-et/strings.xml new file mode 100644 index 000000000000..e8fc44b1aaea --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-et/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Isiklik"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Töö"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-eu/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-eu/strings.xml new file mode 100644 index 000000000000..c22f4dae061c --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-eu/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Pertsonala"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Lanekoa"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-fa/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-fa/strings.xml new file mode 100644 index 000000000000..6eaf057283ec --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-fa/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"شخصی"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"محل کار"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-fi/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-fi/strings.xml new file mode 100644 index 000000000000..8d0b9bfb53a7 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-fi/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Henkilökohtainen"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Työ"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-fr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-fr/strings.xml new file mode 100644 index 000000000000..43e4a59d2f12 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-fr/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personnel"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Professionnel"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-gu/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-gu/strings.xml new file mode 100644 index 000000000000..4aba6db8862c --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-gu/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"વ્યક્તિગત"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ઑફિસ"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml new file mode 100644 index 000000000000..a930032108ab --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-hi/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"निजी"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ऑफ़िस"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-hr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hr/strings.xml new file mode 100644 index 000000000000..cb434a83a5b2 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-hr/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobno"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Posao"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-hu/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hu/strings.xml new file mode 100644 index 000000000000..01277173b917 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-hu/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Személyes"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Munkahelyi"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml new file mode 100644 index 000000000000..353a6d389315 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-hy/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Անձնական"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Աշխատանքային"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-in/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-in/strings.xml new file mode 100644 index 000000000000..173d56f986a2 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-in/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Pribadi"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Kerja"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml new file mode 100644 index 000000000000..cc3bdd5dd027 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Persónulegt"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Vinna"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-it/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-it/strings.xml new file mode 100644 index 000000000000..1d1e70e7c82a --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-it/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personale"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Lavoro"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-iw/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-iw/strings.xml new file mode 100644 index 000000000000..424514519262 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-iw/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"פרופיל אישי"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"פרופיל עבודה"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml new file mode 100644 index 000000000000..f52d80324169 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"個人用"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"仕事用"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ka/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ka/strings.xml new file mode 100644 index 000000000000..e93adff156f8 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ka/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"პირადი"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"სამსახური"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-kk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-kk/strings.xml new file mode 100644 index 000000000000..94eab4de3c17 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-kk/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Жеке"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Жұмыс істейтін"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-km/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-km/strings.xml new file mode 100644 index 000000000000..40fe4ff66672 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-km/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ផ្ទាល់ខ្លួន"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ការងារ"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-kn/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-kn/strings.xml new file mode 100644 index 000000000000..41b70e86d450 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-kn/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ವೈಯಕ್ತಿಕ"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ಕೆಲಸ"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ko/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ko/strings.xml new file mode 100644 index 000000000000..3577efcdb1a2 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ko/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"개인"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"업무"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ky/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ky/strings.xml new file mode 100644 index 000000000000..a65965c5807a --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ky/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Жеке"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Жумуш"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml new file mode 100644 index 000000000000..1e47347d7a1c --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-lo/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ສ່ວນຕົວ"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ບ່ອນເຮັດວຽກ"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-lt/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-lt/strings.xml new file mode 100644 index 000000000000..3ea900490735 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-lt/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Asmeninė"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Darbo"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-lv/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-lv/strings.xml new file mode 100644 index 000000000000..528deeb49802 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-lv/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personīgais"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Darba"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml new file mode 100644 index 000000000000..773b3f1beff9 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Лични"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Работа"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ml/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ml/strings.xml new file mode 100644 index 000000000000..6ae94ccc978e --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ml/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"വ്യക്തിപരം"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ഔദ്യോഗികം"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-mn/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-mn/strings.xml new file mode 100644 index 000000000000..e2361b72d9b2 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-mn/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Хувийн"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Ажил"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-mr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-mr/strings.xml new file mode 100644 index 000000000000..0a48d0f78d43 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-mr/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"वैयक्तिक"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ऑफिस"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ms/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ms/strings.xml new file mode 100644 index 000000000000..607a290f4f2c --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ms/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Peribadi"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Kerja"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-my/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-my/strings.xml new file mode 100644 index 000000000000..a6f8d2371503 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-my/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ကိုယ်ရေးကိုယ်တာ"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"အလုပ်"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-nb/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-nb/strings.xml new file mode 100644 index 000000000000..0a6ff7d826c1 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-nb/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personlig"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Jobb"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml new file mode 100644 index 000000000000..7c0d9e6a5227 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ne/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"व्यक्तिगत"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"कामसम्बन्धी"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-nl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-nl/strings.xml new file mode 100644 index 000000000000..932057f6565b --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-nl/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Persoonlijk"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Werk"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-or/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-or/strings.xml new file mode 100644 index 000000000000..eea417735496 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-or/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ବ୍ୟକ୍ତିଗତ"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ୱାର୍କ"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml new file mode 100644 index 000000000000..48d915e7dddb --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ਨਿੱਜੀ"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ਕਾਰਜ"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml new file mode 100644 index 000000000000..8300df826b83 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-pl/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobiste"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Służbowe"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000000..6e98dc9b185d --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Trabalho"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt-rPT/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt-rPT/strings.xml new file mode 100644 index 000000000000..a89bb04baa42 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-pt-rPT/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Profissional"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml new file mode 100644 index 000000000000..6e98dc9b185d --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Trabalho"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ro/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ro/strings.xml new file mode 100644 index 000000000000..317b4e388530 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ro/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Serviciu"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml new file mode 100644 index 000000000000..165fda1fed95 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Личный профиль"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Рабочий профиль"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-si/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-si/strings.xml new file mode 100644 index 000000000000..746e6e74c374 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-si/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"පුද්ගලික"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"කාර්ය"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml new file mode 100644 index 000000000000..5e882b50da13 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-sk/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobné"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Pracovné"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-sl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sl/strings.xml new file mode 100644 index 000000000000..83ef2911f8bd --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-sl/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Osebno"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Služba"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-sq/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sq/strings.xml new file mode 100644 index 000000000000..84ce28167a49 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-sq/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personale"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Puna"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-sr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sr/strings.xml new file mode 100644 index 000000000000..70b4793f45bd --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-sr/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Лично"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Посао"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-sv/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sv/strings.xml new file mode 100644 index 000000000000..8d1c657c2e9c --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-sv/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Privat"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Arbete"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-sw/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-sw/strings.xml new file mode 100644 index 000000000000..63d150c1b5e2 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-sw/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Binafsi"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Kazini"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-te/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-te/strings.xml new file mode 100644 index 000000000000..75ee30fbd367 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-te/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"వ్యక్తిగతం"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ఆఫీస్"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-th/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-th/strings.xml new file mode 100644 index 000000000000..f35e8fc4b074 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-th/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ส่วนตัว"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"งาน"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-tl/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-tl/strings.xml new file mode 100644 index 000000000000..92b6f16a9ca6 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-tl/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Personal"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Trabaho"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml new file mode 100644 index 000000000000..680ebfe60098 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Kişisel"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"İş"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-uk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-uk/strings.xml new file mode 100644 index 000000000000..953e72c845d2 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-uk/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Особисті"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Робочі"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ur/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ur/strings.xml new file mode 100644 index 000000000000..336a7e03b2c3 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-ur/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"ذاتی"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"کام"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-uz/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-uz/strings.xml new file mode 100644 index 000000000000..5c1e4c0b0b29 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-uz/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Shaxsiy"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Ish"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-vi/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-vi/strings.xml new file mode 100644 index 000000000000..7e04838fae55 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-vi/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Cá nhân"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Công việc"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-zh-rCN/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-zh-rCN/strings.xml new file mode 100644 index 000000000000..d5a1c0391e98 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-zh-rCN/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"个人"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"工作"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-zh-rHK/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-zh-rHK/strings.xml new file mode 100644 index 000000000000..ec247c9ebc41 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-zh-rHK/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"個人"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"工作"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-zh-rTW/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-zh-rTW/strings.xml new file mode 100644 index 000000000000..ec247c9ebc41 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-zh-rTW/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"個人"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"工作"</string> +</resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-zu/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-zu/strings.xml new file mode 100644 index 000000000000..c53aba878583 --- /dev/null +++ b/packages/SettingsLib/ProfileSelector/res/values-zu/strings.xml @@ -0,0 +1,22 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_category_personal" msgid="1142302328104700620">"Okomuntu siqu"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Umsebenzi"</string> +</resources> diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt index 47ac2df67c76..e07a6298a627 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt @@ -69,6 +69,7 @@ import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp @@ -460,6 +461,9 @@ private fun TopAppBarLayout( ProvideTextStyle(value = titleTextStyle) { CompositionLocalProvider( LocalContentColor provides titleContentColor, + // Disable the title font scaling by only passing the density but not the + // font scale. + LocalDensity provides Density(density = LocalDensity.current.density), content = title ) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTab.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTab.kt index 30a4349e942f..6f2c38caa3bc 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTab.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTab.kt @@ -18,11 +18,11 @@ package com.android.settingslib.spa.widget.scaffold import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Tab import androidx.compose.material3.Text +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -46,7 +46,7 @@ internal fun SettingsTab( selected = selected, onClick = onClick, modifier = Modifier - .height(48.dp) + .minimumInteractiveComponentSize() .padding(horizontal = 4.dp, vertical = 6.dp) .clip(SettingsShape.CornerMedium) .background( diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt index 5342def0003d..2c3e58ece8e0 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt @@ -20,9 +20,12 @@ import android.content.Context import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.PackageManager +import android.content.pm.PackageManager.ApplicationInfoFlags import android.content.pm.ResolveInfo import com.android.internal.R +import com.android.settingslib.spaprivileged.framework.common.userManager import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -33,7 +36,11 @@ import kotlinx.coroutines.runBlocking */ internal interface AppListRepository { /** Loads the list of [ApplicationInfo]. */ - suspend fun loadApps(userId: Int, showInstantApps: Boolean): List<ApplicationInfo> + suspend fun loadApps( + userId: Int, + showInstantApps: Boolean = false, + matchAnyUserForAdmin: Boolean = false, + ): List<ApplicationInfo> /** Gets the flow of predicate that could used to filter system app. */ fun showSystemPredicate( @@ -61,10 +68,12 @@ object AppListRepositoryUtil { internal class AppListRepositoryImpl(private val context: Context) : AppListRepository { private val packageManager = context.packageManager + private val userManager = context.userManager override suspend fun loadApps( userId: Int, showInstantApps: Boolean, + matchAnyUserForAdmin: Boolean, ): List<ApplicationInfo> = coroutineScope { val hiddenSystemModulesDeferred = async { packageManager.getInstalledModules(0) @@ -75,12 +84,8 @@ internal class AppListRepositoryImpl(private val context: Context) : AppListRepo val hideWhenDisabledPackagesDeferred = async { context.resources.getStringArray(R.array.config_hideWhenDisabled_packageNames) } - val flags = PackageManager.ApplicationInfoFlags.of( - (PackageManager.MATCH_DISABLED_COMPONENTS or - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() - ) val installedApplicationsAsUser = - packageManager.getInstalledApplicationsAsUser(flags, userId) + getInstalledApplications(userId, matchAnyUserForAdmin) val hiddenSystemModules = hiddenSystemModulesDeferred.await() val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await() @@ -89,6 +94,46 @@ internal class AppListRepositoryImpl(private val context: Context) : AppListRepo } } + private suspend fun getInstalledApplications( + userId: Int, + matchAnyUserForAdmin: Boolean, + ): List<ApplicationInfo> { + val regularFlags = ApplicationInfoFlags.of( + (PackageManager.MATCH_DISABLED_COMPONENTS or + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong() + ) + return if (!matchAnyUserForAdmin || !userManager.getUserInfo(userId).isAdmin) { + packageManager.getInstalledApplicationsAsUser(regularFlags, userId) + } else { + coroutineScope { + val deferredPackageNamesInChildProfiles = + userManager.getProfileIdsWithDisabled(userId) + .filter { it != userId } + .map { + async { + packageManager.getInstalledApplicationsAsUser(regularFlags, it) + .map { it.packageName } + } + } + val adminFlags = ApplicationInfoFlags.of( + PackageManager.MATCH_ANY_USER.toLong() or regularFlags.value + ) + val allInstalledApplications = + packageManager.getInstalledApplicationsAsUser(adminFlags, userId) + val packageNamesInChildProfiles = deferredPackageNamesInChildProfiles + .awaitAll() + .flatten() + .toSet() + // If an app is for a child profile and not installed on the owner, not display as + // 'not installed for this user' in the owner. This will prevent duplicates of work + // only apps showing up in the personal profile. + allInstalledApplications.filter { + it.installed || it.packageName !in packageNamesInChildProfiles + } + } + } + } + override fun showSystemPredicate( userIdFlow: Flow<Int>, showSystemFlow: Flow<Boolean>, diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt index 889604209b08..bd99ebdfa3e5 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListViewModel.kt @@ -80,12 +80,15 @@ internal open class AppListViewModelImpl<T : AppRecord>( private val scope = viewModelScope + Dispatchers.IO private val userSubGraphsFlow = appListConfig.flow.map { config -> - config.userIds.map { userId -> UserSubGraph(userId, config.showInstantApps) } + config.userIds.map { userId -> + UserSubGraph(userId, config.showInstantApps, config.matchAnyUserForAdmin) + } }.shareIn(scope = scope, started = SharingStarted.Eagerly, replay = 1) private inner class UserSubGraph( private val userId: Int, private val showInstantApps: Boolean, + private val matchAnyUserForAdmin: Boolean, ) { private val userIdFlow = flowOf(userId) @@ -110,7 +113,8 @@ internal open class AppListViewModelImpl<T : AppRecord>( fun reloadApps() { scope.launch { - appsStateFlow.value = appListRepository.loadApps(userId, showInstantApps) + appsStateFlow.value = + appListRepository.loadApps(userId, showInstantApps, matchAnyUserForAdmin) } } } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt index f4a6b59d4c4b..066db3475b36 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt @@ -62,6 +62,7 @@ private const val CONTENT_TYPE_HEADER = "header" data class AppListConfig( val userIds: List<Int>, val showInstantApps: Boolean, + val matchAnyUserForAdmin: Boolean, ) data class AppListState( diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt index 2ebbe8aab809..89bfa0eb646b 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt @@ -38,6 +38,7 @@ fun <T : AppRecord> AppListPage( title: String, listModel: AppListModel<T>, showInstantApps: Boolean = false, + matchAnyUserForAdmin: Boolean = false, primaryUserOnly: Boolean = false, noItemMessage: String? = null, moreOptions: @Composable MoreOptionsScope.() -> Unit = {}, @@ -59,6 +60,7 @@ fun <T : AppRecord> AppListPage( config = AppListConfig( userIds = userGroup.userInfos.map { it.id }, showInstantApps = showInstantApps, + matchAnyUserForAdmin = matchAnyUserForAdmin, ), listModel = listModel, state = AppListState( diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt index 57972edc6d3a..b732a6a4495e 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt @@ -23,9 +23,13 @@ import android.content.pm.PackageManager import android.content.pm.PackageManager.ApplicationInfoFlags import android.content.pm.PackageManager.ResolveInfoFlags import android.content.pm.ResolveInfo +import android.content.pm.UserInfo import android.content.res.Resources +import android.os.UserManager +import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.internal.R +import com.android.settingslib.spaprivileged.framework.common.userManager import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first @@ -35,10 +39,13 @@ 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.Mockito.any import org.mockito.Mockito.anyInt import org.mockito.Mockito.eq +import org.mockito.Mockito.verify +import org.mockito.Spy import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule import org.mockito.Mockito.`when` as whenever @@ -49,8 +56,8 @@ class AppListRepositoryTest { @get:Rule val mockito: MockitoRule = MockitoJUnit.rule() - @Mock - private lateinit var context: Context + @Spy + private val context: Context = ApplicationProvider.getApplicationContext() @Mock private lateinit var resources: Resources @@ -58,6 +65,9 @@ class AppListRepositoryTest { @Mock private lateinit var packageManager: PackageManager + @Mock + private lateinit var userManager: UserManager + private lateinit var repository: AppListRepository @Before @@ -66,36 +76,116 @@ class AppListRepositoryTest { whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)) .thenReturn(emptyArray()) whenever(context.packageManager).thenReturn(packageManager) + whenever(context.userManager).thenReturn(userManager) whenever(packageManager.getInstalledModules(anyInt())).thenReturn(emptyList()) whenever( - packageManager.queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), eq(USER_ID)) + packageManager.queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), anyInt()) ).thenReturn(emptyList()) + whenever(userManager.getUserInfo(ADMIN_USER_ID)).thenReturn(UserInfo().apply { + flags = UserInfo.FLAG_ADMIN + }) + whenever(userManager.getProfileIdsWithDisabled(ADMIN_USER_ID)) + .thenReturn(intArrayOf(ADMIN_USER_ID, MANAGED_PROFILE_USER_ID)) repository = AppListRepositoryImpl(context) } - private fun mockInstalledApplications(apps: List<ApplicationInfo>) { + private fun mockInstalledApplications(apps: List<ApplicationInfo>, userId: Int) { whenever( - packageManager.getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(USER_ID)) + packageManager.getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(userId)) ).thenReturn(apps) } @Test fun loadApps_notShowInstantApps() = runTest { - mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP)) + mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP), ADMIN_USER_ID) - val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) + val appList = repository.loadApps( + userId = ADMIN_USER_ID, + showInstantApps = false, + ) - assertThat(appListFlow).containsExactly(NORMAL_APP) + assertThat(appList).containsExactly(NORMAL_APP) } @Test fun loadApps_showInstantApps() = runTest { - mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP)) + mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP), ADMIN_USER_ID) + + val appList = repository.loadApps( + userId = ADMIN_USER_ID, + showInstantApps = true, + ) + + assertThat(appList).containsExactly(NORMAL_APP, INSTANT_APP) + } + + @Test + fun loadApps_notMatchAnyUserForAdmin_withRegularFlags() = runTest { + mockInstalledApplications(listOf(NORMAL_APP), ADMIN_USER_ID) + + val appList = repository.loadApps( + userId = ADMIN_USER_ID, + matchAnyUserForAdmin = false, + ) + + assertThat(appList).containsExactly(NORMAL_APP) + val flags = ArgumentCaptor.forClass(ApplicationInfoFlags::class.java) + verify(packageManager).getInstalledApplicationsAsUser(flags.capture(), eq(ADMIN_USER_ID)) + assertThat(flags.value.value).isEqualTo( + PackageManager.MATCH_DISABLED_COMPONENTS or + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + ) + } - val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = true) + @Test + fun loadApps_matchAnyUserForAdmin_withMatchAnyUserFlag() = runTest { + mockInstalledApplications(listOf(NORMAL_APP), ADMIN_USER_ID) + + val appList = repository.loadApps( + userId = ADMIN_USER_ID, + matchAnyUserForAdmin = true, + ) + + assertThat(appList).containsExactly(NORMAL_APP) + val flags = ArgumentCaptor.forClass(ApplicationInfoFlags::class.java) + verify(packageManager).getInstalledApplicationsAsUser(flags.capture(), eq(ADMIN_USER_ID)) + assertThat(flags.value.value and PackageManager.MATCH_ANY_USER.toLong()).isGreaterThan(0L) + } + + @Test + fun loadApps_matchAnyUserForAdminAndInstalledOnManagedProfileOnly_notDisplayed() = runTest { + val managedProfileOnlyPackageName = "installed.on.managed.profile.only" + mockInstalledApplications(listOf(ApplicationInfo().apply { + packageName = managedProfileOnlyPackageName + }), ADMIN_USER_ID) + mockInstalledApplications(listOf(ApplicationInfo().apply { + packageName = managedProfileOnlyPackageName + flags = ApplicationInfo.FLAG_INSTALLED + }), MANAGED_PROFILE_USER_ID) + + val appList = repository.loadApps( + userId = ADMIN_USER_ID, + matchAnyUserForAdmin = true, + ) - assertThat(appListFlow).containsExactly(NORMAL_APP, INSTANT_APP) + assertThat(appList).isEmpty() + } + + @Test + fun loadApps_matchAnyUserForAdminAndInstalledOnSecondaryUserOnly_displayed() = runTest { + val secondaryUserOnlyApp = ApplicationInfo().apply { + packageName = "installed.on.secondary.user.only" + } + mockInstalledApplications(listOf(secondaryUserOnlyApp), ADMIN_USER_ID) + mockInstalledApplications(emptyList(), MANAGED_PROFILE_USER_ID) + + val appList = repository.loadApps( + userId = ADMIN_USER_ID, + matchAnyUserForAdmin = true, + ) + + assertThat(appList).containsExactly(secondaryUserOnlyApp) } @Test @@ -106,11 +196,11 @@ class AppListRepositoryTest { } whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)) .thenReturn(arrayOf(app.packageName)) - mockInstalledApplications(listOf(app)) + mockInstalledApplications(listOf(app), ADMIN_USER_ID) - val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) + val appList = repository.loadApps(userId = ADMIN_USER_ID) - assertThat(appListFlow).isEmpty() + assertThat(appList).isEmpty() } @Test @@ -122,11 +212,11 @@ class AppListRepositoryTest { } whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)) .thenReturn(arrayOf(app.packageName)) - mockInstalledApplications(listOf(app)) + mockInstalledApplications(listOf(app), ADMIN_USER_ID) - val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) + val appList = repository.loadApps(userId = ADMIN_USER_ID) - assertThat(appListFlow).isEmpty() + assertThat(appList).isEmpty() } @Test @@ -137,11 +227,11 @@ class AppListRepositoryTest { } whenever(resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)) .thenReturn(arrayOf(app.packageName)) - mockInstalledApplications(listOf(app)) + mockInstalledApplications(listOf(app), ADMIN_USER_ID) - val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) + val appList = repository.loadApps(userId = ADMIN_USER_ID) - assertThat(appListFlow).containsExactly(app) + assertThat(appList).containsExactly(app) } @Test @@ -151,11 +241,11 @@ class AppListRepositoryTest { enabled = false enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER } - mockInstalledApplications(listOf(app)) + mockInstalledApplications(listOf(app), ADMIN_USER_ID) - val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) + val appList = repository.loadApps(userId = ADMIN_USER_ID) - assertThat(appListFlow).containsExactly(app) + assertThat(appList).containsExactly(app) } @Test @@ -164,11 +254,11 @@ class AppListRepositoryTest { packageName = "disabled" enabled = false } - mockInstalledApplications(listOf(app)) + mockInstalledApplications(listOf(app), ADMIN_USER_ID) - val appListFlow = repository.loadApps(userId = USER_ID, showInstantApps = false) + val appList = repository.loadApps(userId = ADMIN_USER_ID) - assertThat(appListFlow).isEmpty() + assertThat(appList).isEmpty() } @Test @@ -219,7 +309,11 @@ class AppListRepositoryTest { val app = IN_LAUNCHER_APP whenever( - packageManager.queryIntentActivitiesAsUser(any(), any<ResolveInfoFlags>(), eq(USER_ID)) + packageManager.queryIntentActivitiesAsUser( + any(), + any<ResolveInfoFlags>(), + eq(ADMIN_USER_ID) + ) ).thenReturn(listOf(resolveInfoOf(packageName = app.packageName))) val showSystemPredicate = getShowSystemPredicate(showSystem = false) @@ -229,12 +323,16 @@ class AppListRepositoryTest { @Test fun getSystemPackageNames_returnExpectedValues() = runTest { - mockInstalledApplications(listOf( - NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUNCHER_APP)) + mockInstalledApplications( + apps = listOf( + NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUNCHER_APP + ), + userId = ADMIN_USER_ID, + ) val systemPackageNames = AppListRepositoryUtil.getSystemPackageNames( context = context, - userId = USER_ID, + userId = ADMIN_USER_ID, showInstantApps = false, ) @@ -243,12 +341,13 @@ class AppListRepositoryTest { private suspend fun getShowSystemPredicate(showSystem: Boolean) = repository.showSystemPredicate( - userIdFlow = flowOf(USER_ID), + userIdFlow = flowOf(ADMIN_USER_ID), showSystemFlow = flowOf(showSystem), ).first() private companion object { - const val USER_ID = 0 + const val ADMIN_USER_ID = 0 + const val MANAGED_PROFILE_USER_ID = 11 val NORMAL_APP = ApplicationInfo().apply { packageName = "normal" diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt index 4f0cddef078b..36d9db5ef251 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt @@ -85,7 +85,11 @@ class AppListViewModelTest { } private object FakeAppListRepository : AppListRepository { - override suspend fun loadApps(userId: Int, showInstantApps: Boolean) = listOf(APP) + override suspend fun loadApps( + userId: Int, + showInstantApps: Boolean, + matchAnyUserForAdmin: Boolean, + ) = listOf(APP) override fun showSystemPredicate( userIdFlow: Flow<Int>, @@ -112,7 +116,11 @@ class AppListViewModelTest { const val USER_ID = 0 const val PACKAGE_NAME = "package.name" const val LABEL = "Label" - val CONFIG = AppListConfig(userIds = listOf(USER_ID), showInstantApps = false) + val CONFIG = AppListConfig( + userIds = listOf(USER_ID), + showInstantApps = false, + matchAnyUserForAdmin = false, + ) val APP = ApplicationInfo().apply { packageName = PACKAGE_NAME } diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt index a99d02de0df0..241a134b6a76 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt @@ -114,7 +114,11 @@ class AppListTest { ) { composeTestRule.setContent { AppListInput( - config = AppListConfig(userIds = listOf(USER_ID), showInstantApps = false), + config = AppListConfig( + userIds = listOf(USER_ID), + showInstantApps = false, + matchAnyUserForAdmin = false, + ), listModel = TestAppListModel(enableGrouping = enableGrouping), state = AppListState( showSystem = false.toState(), diff --git a/packages/SettingsLib/res/drawable/ic_dock_device.xml b/packages/SettingsLib/res/drawable/ic_dock_device.xml new file mode 100644 index 000000000000..96a4900f361f --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_dock_device.xml @@ -0,0 +1,26 @@ +<!-- + ~ 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="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="#000000" + android:pathData="M480,280Q497,280 508.5,268.5Q520,257 520,240Q520,223 508.5,211.5Q497,200 480,200Q463,200 451.5,211.5Q440,223 440,240Q440,257 451.5,268.5Q463,280 480,280ZM120,720Q87,720 63.5,696.5Q40,673 40,640L60,160Q60,127 83.5,103.5Q107,80 140,80L820,80Q853,80 876.5,103.5Q900,127 900,160L920,640Q920,673 896.5,696.5Q873,720 840,720L120,720ZM120,640L840,640Q840,640 840,640Q840,640 840,640L820,160Q820,160 820,160Q820,160 820,160L140,160Q140,160 140,160Q140,160 140,160L120,640Q120,640 120,640Q120,640 120,640ZM320,880Q259,880 209.5,850Q160,820 160,765L160,720L240,720L240,760Q253,780 274.5,790Q296,800 320,800L640,800Q664,800 685.5,790.5Q707,781 720,761L720,720L800,720L800,765Q800,820 750.5,850Q701,880 640,880L320,880ZM480,400Q480,400 480,400Q480,400 480,400L480,400Q480,400 480,400Q480,400 480,400L480,400Q480,400 480,400Q480,400 480,400L480,400Q480,400 480,400Q480,400 480,400L480,400Z"/> +</vector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 8fa6b3391a60..42311ef7f885 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -509,7 +509,7 @@ <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"استفاده از زبانهای سیستم"</string> <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"تنظیمات <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> بازنشد"</string> <string name="ime_security_warning" msgid="6547562217880551450">"این روش ورودی ممکن است بتواند تمام متنی را که تایپ میکنید جمعآوری کند، از جمله اطلاعات شخصی مانند گذرواژهها و شمارههای کارت اعتباری. این روش توسط برنامه <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ارائه میشود. از این روش ورودی استفاده میکنید؟"</string> - <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"توجه: بعد از راهاندازی تا زمانیکه قفل تلفنتان را باز نکنید، این برنامه نمیتواند شروع شود"</string> + <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"توجه: بعداز بازراهاندازی تا زمانیکه قفل تلفنتان را باز نکنید، این برنامه نمیتواند شروع شود"</string> <string name="ims_reg_title" msgid="8197592958123671062">"وضعیت ثبت IMS"</string> <string name="ims_reg_status_registered" msgid="884916398194885457">"ثبتشده"</string> <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ثبت نشده است"</string> @@ -629,7 +629,7 @@ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"پیشفرض دستگاه"</string> <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیرفعال"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string> - <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاهتان باید راهاندازی مجدد شود. اکنون راهاندازی مجدد کنید یا لغو کنید."</string> + <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاه باید بازراهاندازی شود. یا اکنون بازراهاندازی کنید یا لغو کنید."</string> <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"هدفون سیمی"</string> <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"روشن"</string> <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"خاموش"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 04c225c2ce32..2866f9e856c8 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -486,7 +486,7 @@ <string name="disabled" msgid="8017887509554714950">"बंद किया गया"</string> <string name="external_source_trusted" msgid="1146522036773132905">"अनुमति है"</string> <string name="external_source_untrusted" msgid="5037891688911672227">"अनुमति नहीं है"</string> - <string name="install_other_apps" msgid="3232595082023199454">"अनजान ऐप्लिकेशन इंस्टॉल करने की अनुमति देना"</string> + <string name="install_other_apps" msgid="3232595082023199454">"अज्ञात ऐप्लिकेशन इंस्टॉल करने की अनुमति देना"</string> <string name="home" msgid="973834627243661438">"सेटिंग का होम पेज"</string> <string-array name="battery_labels"> <item msgid="7878690469765357158">"0%"</item> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 242c855c3844..34d646d63ca4 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -485,7 +485,7 @@ <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ຄວບຄຸມໂດຍການຕັ້ງຄ່າທີ່ຈຳກັດໄວ້"</string> <string name="disabled" msgid="8017887509554714950">"ປິດການນຳໃຊ້"</string> <string name="external_source_trusted" msgid="1146522036773132905">"ອະນຸຍາດແລ້ວ"</string> - <string name="external_source_untrusted" msgid="5037891688911672227">"ບໍ່ອະນຸຍາດແລ້ວ"</string> + <string name="external_source_untrusted" msgid="5037891688911672227">"ບໍ່ອະນຸຍາດ"</string> <string name="install_other_apps" msgid="3232595082023199454">"ຕິດຕັ້ງແອັບທີ່ບໍ່ຮູ້ຈັກ"</string> <string name="home" msgid="973834627243661438">"ໜ້າທຳອິດຂອງການຕັ້ງຄ່າ"</string> <string-array name="battery_labels"> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 08c2f7b3b720..18b1f50b75bc 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -251,7 +251,7 @@ <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skann QR-koden"</string> <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via wifi ved å skanne en QR-kode"</string> - <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koble til et Wifi-nettverk"</string> + <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koble til et wifi-nettverk"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, feilsøking, utvikler"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Snarvei til feilrapport"</string> <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Vis en knapp for generering av feilrapport i batterimenyen"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 628bd930786a..f8945c7dd80e 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -665,7 +665,7 @@ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziksel klavye"</string> <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klavye düzenini seçin"</string> <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Varsayılan"</string> - <string name="turn_screen_on_title" msgid="3266937298097573424">"Ekranı aç"</string> + <string name="turn_screen_on_title" msgid="3266937298097573424">"Ekranı açma"</string> <string name="allow_turn_screen_on" msgid="6194845766392742639">"Ekranı açmaya izin ver"</string> <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Bir uygulamanın ekranı açmasına izin verin. İzin verildiğinde, uygulama sizin belirgin niyetiniz olmadan istediği zaman ekranı açabilir."</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında anons durdurulsun mu?"</string> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index ff80f52218ad..214c9035fc8e 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1262,6 +1262,12 @@ <!-- Button label for generic cancel action [CHAR LIMIT=20] --> <string name="cancel">Cancel</string> + <!-- Button label for generic next action [CHAR LIMIT=20] --> + <string name="next">Next</string> + <!-- Button label for generic back action [CHAR LIMIT=20] --> + <string name="back">Back</string> + <!-- Button label for generic save action [CHAR LIMIT=20] --> + <string name="save">Save</string> <!-- Button label for generic OK action [CHAR LIMIT=20] --> <string name="okay">OK</string> <!-- Button label for generic Done action, to be pressed when an action has been completed [CHAR LIMIT=20] --> @@ -1388,9 +1394,11 @@ <!-- Message for add user confirmation dialog - short version. [CHAR LIMIT=none] --> <string name="user_add_user_message_short">When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users. </string> <!-- Title for grant user admin privileges dialog [CHAR LIMIT=65] --> - <string name="user_grant_admin_title">Give this user admin privileges?</string> + <string name="user_grant_admin_title">Make this user an admin?</string> <!-- Message for grant admin privileges dialog. [CHAR LIMIT=none] --> - <string name="user_grant_admin_message">As an admin, they will be able to manage other users, modify device settings and factory reset the device.</string> + <string name="user_grant_admin_message">Admins have special privileges that other users don\’t. An admin can manage all users, update or reset this device, modify settings, see all installed apps, and grant or revoke admin privileges for others.</string> + <!-- Confirmation button for grant user admin privileges dialog [CHAR LIMIT=65] --> + <string name="user_grant_admin_button">Make admin</string> <!-- Title of dialog to setup a new user [CHAR LIMIT=30] --> <string name="user_setup_dialog_title">Set up user now?</string> <!-- Message in dialog to setup a new user after creation [CHAR LIMIT=none] --> @@ -1458,9 +1466,9 @@ <string name="guest_exit_dialog_message">This will delete apps and data from the current guest session</string> <!-- Dialog message on action grant admin privileges [CHAR LIMIT=60] --> - <string name="grant_admin">Give this user admin privileges</string> + <string name="grant_admin">Yes, make them an admin</string> <!-- Dialog message on action not grant admin privileges [CHAR LIMIT=60] --> - <string name="not_grant_admin">Do not give user admin privileges</string> + <string name="not_grant_admin">No, don\’t make them an admin</string> <!-- Dialog button on action exit guest (ephemeral guest) [CHAR LIMIT=80] --> <string name="guest_exit_dialog_button">Exit</string> <!-- Dialog title on action exit guest (non-ephemeral guest) [CHAR LIMIT=32] --> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index e22f3f0e720d..5fbb4c3e5712 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -37,8 +37,6 @@ import com.android.settingslib.Utils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -287,16 +285,7 @@ public class HearingAidProfile implements LocalBluetoothProfile { return defaultValue; } - try { - Method method = mService.getClass().getDeclaredMethod("getDeviceSideInternal", - BluetoothDevice.class); - method.setAccessible(true); - return (int) method.invoke(mService, device); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - Log.e(TAG, "fail to get getDeviceSideInternal\n" + e.toString() + "\n" - + Log.getStackTraceString(new Throwable())); - return defaultValue; - } + return mService.getDeviceSide(device); } /** @@ -313,17 +302,7 @@ public class HearingAidProfile implements LocalBluetoothProfile { return defaultValue; } - try { - Method method = mService.getClass().getDeclaredMethod("getDeviceModeInternal", - BluetoothDevice.class); - method.setAccessible(true); - return (int) method.invoke(mService, device); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - Log.e(TAG, "fail to get getDeviceModeInternal\n" + e.toString() + "\n" - + Log.getStackTraceString(new Throwable())); - - return defaultValue; - } + return mService.getDeviceMode(device); } public String toString() { diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverLogging.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverLogging.java new file mode 100644 index 000000000000..5326e73a3f82 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverLogging.java @@ -0,0 +1,53 @@ +/* + * 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.settingslib.fuelgauge; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Utilities related to battery saver logging. + */ +public final class BatterySaverLogging { + /** + * Record the reason while enabling power save mode manually. + * See {@link SaverManualEnabledReason} for all available states. + */ + public static final String EXTRA_POWER_SAVE_MODE_MANUAL_ENABLED_REASON = + "extra_power_save_mode_manual_enabled_reason"; + + /** Broadcast action to record battery saver manual enabled reason. */ + public static final String ACTION_SAVER_MANUAL_ENABLED_REASON = + "com.android.settingslib.fuelgauge.ACTION_SAVER_MANUAL_ENABLED_REASON"; + + /** An interface for the battery saver manual enable reason. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({SAVER_ENABLED_UNKNOWN, SAVER_ENABLED_CONFIRMATION, SAVER_ENABLED_VOICE, + SAVER_ENABLED_SETTINGS, SAVER_ENABLED_QS, SAVER_ENABLED_LOW_WARNING, + SAVER_ENABLED_SEVERE_WARNING}) + public @interface SaverManualEnabledReason {} + + public static final int SAVER_ENABLED_UNKNOWN = 0; + public static final int SAVER_ENABLED_CONFIRMATION = 1; + public static final int SAVER_ENABLED_VOICE = 2; + public static final int SAVER_ENABLED_SETTINGS = 3; + public static final int SAVER_ENABLED_QS = 4; + public static final int SAVER_ENABLED_LOW_WARNING = 5; + public static final int SAVER_ENABLED_SEVERE_WARNING = 6; +} diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java index 52f3111d967c..e28ada4771c9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java @@ -16,6 +16,10 @@ package com.android.settingslib.fuelgauge; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.ACTION_SAVER_MANUAL_ENABLED_REASON; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.EXTRA_POWER_SAVE_MODE_MANUAL_ENABLED_REASON; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.SaverManualEnabledReason; + import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -116,9 +120,9 @@ public class BatterySaverUtils { * @return true if the request succeeded. */ public static synchronized boolean setPowerSaveMode(Context context, - boolean enable, boolean needFirstTimeWarning) { + boolean enable, boolean needFirstTimeWarning, @SaverManualEnabledReason int reason) { if (DEBUG) { - Log.d(TAG, "Battery saver turning " + (enable ? "ON" : "OFF")); + Log.d(TAG, "Battery saver turning " + (enable ? "ON" : "OFF") + ", reason: " + reason); } final ContentResolver cr = context.getContentResolver(); @@ -145,8 +149,10 @@ public class BatterySaverUtils { && Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0 && Secure.getInt(cr, Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) { - showAutoBatterySaverSuggestion(context, confirmationExtras); + sendSystemUiBroadcast(context, ACTION_SHOW_AUTO_SAVER_SUGGESTION, + confirmationExtras); } + recordBatterySaverEnabledReason(context, reason); } return true; @@ -175,21 +181,23 @@ public class BatterySaverUtils { // Already shown. return false; } - context.sendBroadcast( - getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION, extras)); + sendSystemUiBroadcast(context, ACTION_SHOW_START_SAVER_CONFIRMATION, extras); return true; } - private static void showAutoBatterySaverSuggestion(Context context, Bundle extras) { - context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION, extras)); + private static void recordBatterySaverEnabledReason(Context context, + @SaverManualEnabledReason int reason) { + final Bundle enabledReasonExtras = new Bundle(1); + enabledReasonExtras.putInt(EXTRA_POWER_SAVE_MODE_MANUAL_ENABLED_REASON, reason); + sendSystemUiBroadcast(context, ACTION_SAVER_MANUAL_ENABLED_REASON, enabledReasonExtras); } - private static Intent getSystemUiBroadcast(String action, Bundle extras) { - final Intent i = new Intent(action); - i.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); - i.setPackage(SYSUI_PACKAGE); - i.putExtras(extras); - return i; + private static void sendSystemUiBroadcast(Context context, String action, Bundle extras) { + final Intent intent = new Intent(action); + intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); + intent.setPackage(SYSUI_PACKAGE); + intent.putExtras(extras); + context.sendBroadcast(intent); } private static void setBatterySaverConfirmationAcknowledged(Context context) { diff --git a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java index 6c0eab3fb016..e38e041a87dc 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java @@ -55,7 +55,7 @@ public class DeviceIconUtil { new Device( AudioDeviceInfo.TYPE_DOCK, MediaRoute2Info.TYPE_DOCK, - R.drawable.ic_headphone), + R.drawable.ic_dock_device), new Device( AudioDeviceInfo.TYPE_HDMI, MediaRoute2Info.TYPE_HDMI, diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java index ad022a63eaf6..cb386fbff4ed 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java @@ -16,6 +16,7 @@ package com.android.settingslib.fuelgauge; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_UNKNOWN; import static com.android.settingslib.fuelgauge.BatterySaverUtils.KEY_NO_SCHEDULE; import static com.android.settingslib.fuelgauge.BatterySaverUtils.KEY_PERCENTAGE; @@ -72,7 +73,8 @@ public class BatterySaverUtilsTest { Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); - assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isFalse(); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true, + SAVER_ENABLED_UNKNOWN)).isFalse(); verify(mMockContext, times(1)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(0)).setPowerSaveModeEnabled(anyBoolean()); @@ -92,7 +94,8 @@ public class BatterySaverUtilsTest { Secure.putInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); - assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue(); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true, + SAVER_ENABLED_UNKNOWN)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true)); @@ -111,7 +114,8 @@ public class BatterySaverUtilsTest { Secure.putInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1); Secure.putInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 1); - assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue(); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true, + SAVER_ENABLED_UNKNOWN)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true)); @@ -129,7 +133,8 @@ public class BatterySaverUtilsTest { Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); - assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, false)).isTrue(); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, false, + SAVER_ENABLED_UNKNOWN)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true)); @@ -147,7 +152,8 @@ public class BatterySaverUtilsTest { Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); // When disabling, needFirstTimeWarning doesn't matter. - assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, false, false)).isTrue(); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, false, false, + SAVER_ENABLED_UNKNOWN)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(false)); @@ -166,7 +172,8 @@ public class BatterySaverUtilsTest { Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); // When disabling, needFirstTimeWarning doesn't matter. - assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, false, true)).isTrue(); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, false, true, + SAVER_ENABLED_UNKNOWN)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(false)); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java index 55125c53b4c9..049c90e971a9 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java @@ -18,6 +18,9 @@ package com.android.settingslib.widget; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -87,4 +90,52 @@ public class FooterPreferenceTest { assertThat(mFooterPreference.mIconVisibility).isEqualTo(View.GONE); } + + @Test + public void onBindViewHolder_whenTitleIsNull_shouldNotRaiseNpe() { + PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests( + LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null))); + when(viewHolder.findViewById(R.id.title)).thenReturn(null); + + Throwable actualThrowable = null; + try { + mFooterPreference.onBindViewHolder(viewHolder); + } catch (Throwable throwable) { + actualThrowable = throwable; + } + + assertThat(actualThrowable).isNull(); + } + + @Test + public void onBindViewHolder_whenLearnMoreIsNull_shouldNotRaiseNpe() { + PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests( + LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null))); + when(viewHolder.findViewById(R.id.settingslib_learn_more)).thenReturn(null); + + Throwable actualThrowable = null; + try { + mFooterPreference.onBindViewHolder(viewHolder); + } catch (Throwable throwable) { + actualThrowable = throwable; + } + + assertThat(actualThrowable).isNull(); + } + + @Test + public void onBindViewHolder_whenIconFrameIsNull_shouldNotRaiseNpe() { + PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests( + LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null))); + when(viewHolder.findViewById(R.id.icon_frame)).thenReturn(null); + + Throwable actualThrowable = null; + try { + mFooterPreference.onBindViewHolder(viewHolder); + } catch (Throwable throwable) { + actualThrowable = throwable; + } + + assertThat(actualThrowable).isNull(); + } } diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 59cd7a051fad..a93cd62e6301 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -43,6 +43,8 @@ <bool name="def_install_non_market_apps">false</bool> <!-- 0 == off, 3 == on --> <integer name="def_location_mode">3</integer> + <!-- 0 == off, 1 == on--> + <integer name="def_paired_device_location_mode">1</integer> <bool name="assisted_gps_enabled">true</bool> <bool name="def_netstats_enabled">true</bool> <bool name="def_usb_mass_storage_enabled">true</bool> diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java index e50f52229a16..41ce58eb7b4e 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java @@ -103,5 +103,7 @@ public class GlobalSettings { Settings.Global.Wearable.UPGRADE_DATA_MIGRATION_STATUS, Settings.Global.HDR_CONVERSION_MODE, Settings.Global.HDR_FORCE_CONVERSION_TYPE, + Settings.Global.Wearable.RTL_SWIPE_TO_DISMISS_ENABLED_DEV, + Settings.Global.Wearable.REDUCE_MOTION, }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index d5386c1d75ac..a1c01723ad55 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -285,7 +285,6 @@ public class GlobalSettingsValidators { })); VALIDATORS.put(Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.Wearable.SIDE_BUTTON, BOOLEAN_VALIDATOR); - VALIDATORS.put(Global.Wearable.BUTTON_SET, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.Wearable.ANDROID_WEAR_VERSION, ANY_INTEGER_VALIDATOR); VALIDATORS.put(Global.Wearable.SYSTEM_CAPABILITIES, ANY_INTEGER_VALIDATOR); VALIDATORS.put(Global.Wearable.SYSTEM_EDITION, ANY_INTEGER_VALIDATOR); @@ -345,6 +344,7 @@ public class GlobalSettingsValidators { String.valueOf(Global.Wearable.HFP_CLIENT_DISABLED) })); VALIDATORS.put(Global.Wearable.COMPANION_OS_VERSION, ANY_INTEGER_VALIDATOR); + VALIDATORS.put(Global.Wearable.COMPANION_APP_NAME, ANY_STRING_VALIDATOR); VALIDATORS.put(Global.Wearable.ENABLE_ALL_LANGUAGES, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.Wearable.OEM_SETUP_VERSION, ANY_INTEGER_VALIDATOR); VALIDATORS.put( @@ -404,16 +404,6 @@ public class GlobalSettingsValidators { VALIDATORS.put(Global.Wearable.CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.Wearable.BEDTIME_MODE, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.Wearable.BEDTIME_HARD_MODE, BOOLEAN_VALIDATOR); - VALIDATORS.put( - Global.Wearable.EARLY_UPDATES_STATUS, - new DiscreteValueValidator( - new String[] { - String.valueOf(Global.Wearable.EARLY_UPDATES_STATUS_NOT_STARTED), - String.valueOf(Global.Wearable.EARLY_UPDATES_STATUS_STARTED), - String.valueOf(Global.Wearable.EARLY_UPDATES_STATUS_SUCCESS), - String.valueOf(Global.Wearable.EARLY_UPDATES_STATUS_SKIPPED), - String.valueOf(Global.Wearable.EARLY_UPDATES_STATUS_ABORTED), - })); VALIDATORS.put(Global.Wearable.DYNAMIC_COLOR_THEME_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.Wearable.SCREENSHOT_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.Wearable.UPGRADE_DATA_MIGRATION_STATUS, @@ -423,5 +413,22 @@ public class GlobalSettingsValidators { String.valueOf(Global.Wearable.UPGRADE_DATA_MIGRATION_PENDING), String.valueOf(Global.Wearable.UPGRADE_DATA_MIGRATION_DONE) })); + VALIDATORS.put(Global.Wearable.DISABLE_AOD_WHILE_PLUGGED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Global.Wearable.NETWORK_LOCATION_OPT_IN, BOOLEAN_VALIDATOR); + VALIDATORS.put(Global.Wearable.PHONE_SWITCHING_STATUS, + new InclusiveIntegerRangeValidator( + Global.Wearable.PHONE_SWITCHING_STATUS_NOT_STARTED, + Global.Wearable.PHONE_SWITCHING_STATUS_IN_PROGRESS_MIGRATION_SUCCESS)); + VALIDATORS.put(Global.Wearable.REDUCE_MOTION, BOOLEAN_VALIDATOR); + VALIDATORS.put(Global.Wearable.RTL_SWIPE_TO_DISMISS_ENABLED_DEV, BOOLEAN_VALIDATOR); + VALIDATORS.put( + Global.Wearable.TETHER_CONFIG_STATE, + new DiscreteValueValidator( + new String[] { + String.valueOf(Global.Wearable.TETHERED_CONFIG_UNKNOWN), + String.valueOf(Global.Wearable.TETHERED_CONFIG_STANDALONE), + String.valueOf(Global.Wearable.TETHERED_CONFIG_TETHERED) + })); + VALIDATORS.put(Global.Wearable.PHONE_SWITCHING_SUPPORTED, BOOLEAN_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index b0a19270018a..284b06b86cb6 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -3748,7 +3748,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 217; + private static final int SETTINGS_VERSION = 218; private final int mUserId; @@ -5334,74 +5334,73 @@ public class SettingsProvider extends ContentProvider { if (currentVersion == 203) { // Version 203: initialize entries migrated from wear settings provide. - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.HAS_PAY_TOKENS, false); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN, 6); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.HOTWORD_DETECTION_ENABLED, getContext() .getResources() .getBoolean(R.bool.def_wearable_hotwordDetectionEnabled)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.SMART_REPLIES_ENABLED, true); Setting locationMode = getSecureSettingsLocked(userId).getSettingLocked(Secure.LOCATION_MODE); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION, !locationMode.isNull() && !Integer.toString(Secure.LOCATION_MODE_OFF) .equals(locationMode.getValue())); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY, Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY_UNKNOWN); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.BUG_REPORT, "user".equals(Build.TYPE) // is user build? ? Global.Wearable.BUG_REPORT_DISABLED : Global.Wearable.BUG_REPORT_ENABLED); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.SMART_ILLUMINATE_ENABLED, getContext() .getResources() .getBoolean(R.bool.def_wearable_smartIlluminateEnabled)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.CLOCKWORK_AUTO_TIME, Global.Wearable.SYNC_TIME_FROM_PHONE); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.CLOCKWORK_AUTO_TIME_ZONE, Global.Wearable.SYNC_TIME_ZONE_FROM_PHONE); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.CLOCKWORK_24HR_TIME, false); - initGlobalSettingsDefaultValForWearLocked(Global.Wearable.AUTO_WIFI, true); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked(Global.Wearable.AUTO_WIFI, true); + initGlobalSettingsDefaultValLocked( Global.Wearable.WIFI_POWER_SAVE, getContext() .getResources() .getInteger( R.integer .def_wearable_offChargerWifiUsageLimitMinutes)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS, 0L); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.SETUP_SKIPPED, Global.Wearable.SETUP_SKIPPED_UNKNOWN); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.LAST_CALL_FORWARD_ACTION, Global.Wearable.CALL_FORWARD_NO_LAST_ACTION); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED, getContext() .getResources() .getBoolean(R.bool.def_wearable_muteWhenOffBodyEnabled)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.WEAR_OS_VERSION_STRING, ""); - initGlobalSettingsDefaultValForWearLocked(Global.Wearable.BUTTON_SET, false); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.SIDE_BUTTON, getContext() .getResources() .getBoolean(R.bool.def_wearable_sideButtonPresent)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.ANDROID_WEAR_VERSION, Long.parseLong( getContext() @@ -5410,55 +5409,55 @@ public class SettingsProvider extends ContentProvider { final int editionGlobal = 1; final int editionLocal = 2; boolean isLe = getContext().getPackageManager().hasSystemFeature("cn.google"); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.SYSTEM_EDITION, isLe ? editionLocal : editionGlobal); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.SYSTEM_CAPABILITIES, getWearSystemCapabilities(isLe)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.WEAR_PLATFORM_MR_NUMBER, SystemProperties.getInt("ro.cw_build.platform_mr", 0)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.MOBILE_SIGNAL_DETECTOR, getContext() .getResources() .getBoolean(R.bool.def_wearable_mobileSignalDetectorAllowed)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.AMBIENT_ENABLED, getContext() .getResources() .getBoolean(R.bool.def_wearable_ambientEnabled)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.AMBIENT_TILT_TO_WAKE, getContext() .getResources() .getBoolean(R.bool.def_wearable_tiltToWakeEnabled)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.AMBIENT_LOW_BIT_ENABLED_DEV, false); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.AMBIENT_TOUCH_TO_WAKE, getContext() .getResources() .getBoolean(R.bool.def_wearable_touchToWakeEnabled)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.AMBIENT_TILT_TO_BRIGHT, getContext() .getResources() .getBoolean(R.bool.def_wearable_tiltToBrightEnabled)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Global.Wearable.DECOMPOSABLE_WATCHFACE, false); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.AMBIENT_FORCE_WHEN_DOCKED, SystemProperties.getBoolean("ro.ambient.force_when_docked", false)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.AMBIENT_LOW_BIT_ENABLED, SystemProperties.getBoolean("ro.ambient.low_bit_enabled", false)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.AMBIENT_PLUGGED_TIMEOUT_MIN, SystemProperties.getInt("ro.ambient.plugged_timeout_min", -1)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.PAIRED_DEVICE_OS_TYPE, Settings.Global.Wearable.PAIRED_DEVICE_OS_TYPE_UNKNOWN); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.USER_HFP_CLIENT_SETTING, Settings.Global.Wearable.HFP_CLIENT_UNSET); Setting disabledProfileSetting = @@ -5468,7 +5467,7 @@ public class SettingsProvider extends ContentProvider { disabledProfileSetting.isNull() ? 0 : Long.parseLong(disabledProfileSetting.getValue()); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.COMPANION_OS_VERSION, Settings.Global.Wearable.COMPANION_OS_VERSION_UNDEFINED); final boolean defaultBurnInProtectionEnabled = @@ -5482,17 +5481,17 @@ public class SettingsProvider extends ContentProvider { .config_enableBurnInProtection); final boolean forceBurnInProtection = SystemProperties.getBoolean("persist.debug.force_burn_in", false); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED, defaultBurnInProtectionEnabled || forceBurnInProtection); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.CLOCKWORK_SYSUI_PACKAGE, getContext() .getResources() .getString( com.android.internal.R.string.config_wearSysUiPackage)); - initGlobalSettingsDefaultValForWearLocked( + initGlobalSettingsDefaultValLocked( Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY, getContext() .getResources() @@ -5622,63 +5621,16 @@ public class SettingsProvider extends ContentProvider { currentVersion = 210; } if (currentVersion == 210) { - final SettingsState secureSettings = getSecureSettingsLocked(userId); - final Setting currentSetting = secureSettings.getSettingLocked( - Secure.STATUS_BAR_SHOW_VIBRATE_ICON); - if (currentSetting.isNull()) { - final int defaultValueVibrateIconEnabled = getContext().getResources() - .getInteger(R.integer.def_statusBarVibrateIconEnabled); - secureSettings.insertSettingOverrideableByRestoreLocked( - Secure.STATUS_BAR_SHOW_VIBRATE_ICON, - String.valueOf(defaultValueVibrateIconEnabled), - null /* tag */, true /* makeDefault */, - SettingsState.SYSTEM_PACKAGE_NAME); - } + // Unused. Moved to version 217. currentVersion = 211; } if (currentVersion == 211) { - // Version 211: Set default value for - // Secure#LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS - final SettingsState secureSettings = getSecureSettingsLocked(userId); - final Setting lockScreenUnseenSetting = secureSettings - .getSettingLocked(Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS); - if (lockScreenUnseenSetting.isNull()) { - final boolean defSetting = getContext().getResources() - .getBoolean(R.bool.def_lock_screen_show_only_unseen_notifications); - secureSettings.insertSettingOverrideableByRestoreLocked( - Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, - defSetting ? "1" : "0", - null /* tag */, - true /* makeDefault */, - SettingsState.SYSTEM_PACKAGE_NAME); - } - + // Unused. Moved to version 217. currentVersion = 212; } if (currentVersion == 212) { - final SettingsState globalSettings = getGlobalSettingsLocked(); - final SettingsState secureSettings = getSecureSettingsLocked(userId); - - final Setting bugReportInPowerMenu = globalSettings.getSettingLocked( - Global.BUGREPORT_IN_POWER_MENU); - - if (!bugReportInPowerMenu.isNull()) { - Slog.i(LOG_TAG, "Setting bugreport_in_power_menu to " - + bugReportInPowerMenu.getValue() + " in Secure settings."); - secureSettings.insertSettingLocked( - Secure.BUGREPORT_IN_POWER_MENU, - bugReportInPowerMenu.getValue(), null /* tag */, - false /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME); - - // set global bug_report_in_power_menu setting to null since it's deprecated - Slog.i(LOG_TAG, "Setting bugreport_in_power_menu to null" - + " in Global settings since it's deprecated."); - globalSettings.insertSettingLocked( - Global.BUGREPORT_IN_POWER_MENU, null /* value */, null /* tag */, - true /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME); - } - + // Unused. Moved to version 217. currentVersion = 213; } @@ -5804,6 +5756,89 @@ public class SettingsProvider extends ContentProvider { currentVersion = 217; } + if (currentVersion == 217) { + // Version 217: merge and rebase wear settings init logic. + + final SettingsState secureSettings = getSecureSettingsLocked(userId); + final SettingsState globalSettings = getGlobalSettingsLocked(); + + // Following init logic is moved from version 210 to this version in order to + // resolve version conflict with wear branch. + final Setting currentSetting = secureSettings.getSettingLocked( + Secure.STATUS_BAR_SHOW_VIBRATE_ICON); + if (currentSetting.isNull()) { + final int defaultValueVibrateIconEnabled = getContext().getResources() + .getInteger(R.integer.def_statusBarVibrateIconEnabled); + secureSettings.insertSettingOverrideableByRestoreLocked( + Secure.STATUS_BAR_SHOW_VIBRATE_ICON, + String.valueOf(defaultValueVibrateIconEnabled), + null /* tag */, true /* makeDefault */, + SettingsState.SYSTEM_PACKAGE_NAME); + } + + // Set default value for Secure#LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS + // Following init logic is moved from version 211 to this version in order to + // resolve version conflict with wear branch. + final Setting lockScreenUnseenSetting = secureSettings + .getSettingLocked(Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS); + if (lockScreenUnseenSetting.isNull()) { + final boolean defSetting = getContext().getResources() + .getBoolean(R.bool.def_lock_screen_show_only_unseen_notifications); + secureSettings.insertSettingOverrideableByRestoreLocked( + Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, + defSetting ? "1" : "0", + null /* tag */, + true /* makeDefault */, + SettingsState.SYSTEM_PACKAGE_NAME); + } + + // Following init logic is moved from version 212 to this version in order to + // resolve version conflict with wear branch. + final Setting bugReportInPowerMenu = globalSettings.getSettingLocked( + Global.BUGREPORT_IN_POWER_MENU); + + if (!bugReportInPowerMenu.isNull()) { + Slog.i(LOG_TAG, "Setting bugreport_in_power_menu to " + + bugReportInPowerMenu.getValue() + " in Secure settings."); + secureSettings.insertSettingLocked( + Secure.BUGREPORT_IN_POWER_MENU, + bugReportInPowerMenu.getValue(), null /* tag */, + false /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME); + + // set global bug_report_in_power_menu setting to null since it's deprecated + Slog.i(LOG_TAG, "Setting bugreport_in_power_menu to null" + + " in Global settings since it's deprecated."); + globalSettings.insertSettingLocked( + Global.BUGREPORT_IN_POWER_MENU, null /* value */, null /* tag */, + true /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME); + } + + // Following init logic is rebased from wear OS branch. + // Initialize default value of tether configuration to unknown. + initGlobalSettingsDefaultValLocked( + Settings.Global.Wearable.TETHER_CONFIG_STATE, + Global.Wearable.TETHERED_CONFIG_UNKNOWN); + // Init paired device location setting from resources. + initGlobalSettingsDefaultValLocked( + Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION, + getContext() + .getResources() + .getInteger(R.integer.def_paired_device_location_mode)); + // Init media packages from resources. + final String mediaControlsPackage = getContext().getResources().getString( + com.android.internal.R.string.config_wearMediaControlsPackage); + final String mediaSessionsPackage = getContext().getResources().getString( + com.android.internal.R.string.config_wearMediaSessionsPackage); + initGlobalSettingsDefaultValLocked( + Global.Wearable.WEAR_MEDIA_CONTROLS_PACKAGE, + mediaControlsPackage); + initGlobalSettingsDefaultValLocked( + Global.Wearable.WEAR_MEDIA_SESSIONS_PACKAGE, + mediaSessionsPackage); + + currentVersion = 218; + } + // vXXX: Add new settings above this point. if (currentVersion != newVersion) { @@ -5821,19 +5856,19 @@ public class SettingsProvider extends ContentProvider { return currentVersion; } - private void initGlobalSettingsDefaultValForWearLocked(String key, boolean val) { - initGlobalSettingsDefaultValForWearLocked(key, val ? "1" : "0"); + private void initGlobalSettingsDefaultValLocked(String key, boolean val) { + initGlobalSettingsDefaultValLocked(key, val ? "1" : "0"); } - private void initGlobalSettingsDefaultValForWearLocked(String key, int val) { - initGlobalSettingsDefaultValForWearLocked(key, String.valueOf(val)); + private void initGlobalSettingsDefaultValLocked(String key, int val) { + initGlobalSettingsDefaultValLocked(key, String.valueOf(val)); } - private void initGlobalSettingsDefaultValForWearLocked(String key, long val) { - initGlobalSettingsDefaultValForWearLocked(key, String.valueOf(val)); + private void initGlobalSettingsDefaultValLocked(String key, long val) { + initGlobalSettingsDefaultValLocked(key, String.valueOf(val)); } - private void initGlobalSettingsDefaultValForWearLocked(String key, String val) { + private void initGlobalSettingsDefaultValLocked(String key, String val) { final SettingsState globalSettings = getGlobalSettingsLocked(); Setting currentSetting = globalSettings.getSettingLocked(key); if (currentSetting.isNull()) { diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 19f1a86ec90c..a202e1614b67 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -627,7 +627,6 @@ public class SettingsBackupTest { Settings.Global.Wearable.STEM_3_DATA, Settings.Global.Wearable.STEM_3_DEFAULT_DATA, Settings.Global.Wearable.WEAR_OS_VERSION_STRING, - Settings.Global.Wearable.BUTTON_SET, Settings.Global.Wearable.SIDE_BUTTON, Settings.Global.Wearable.ANDROID_WEAR_VERSION, Settings.Global.Wearable.SYSTEM_CAPABILITIES, @@ -643,6 +642,7 @@ public class SettingsBackupTest { Settings.Global.Wearable.PAIRED_DEVICE_OS_TYPE, Settings.Global.Wearable.COMPANION_BLE_ROLE, Settings.Global.Wearable.COMPANION_NAME, + Settings.Global.Wearable.COMPANION_APP_NAME, Settings.Global.Wearable.USER_HFP_CLIENT_SETTING, Settings.Global.Wearable.COMPANION_OS_VERSION, Settings.Global.Wearable.ENABLE_ALL_LANGUAGES, @@ -662,13 +662,21 @@ public class SettingsBackupTest { Settings.Global.Wearable.SCREEN_UNLOCK_SOUND_ENABLED, Settings.Global.Wearable.BEDTIME_MODE, Settings.Global.Wearable.BEDTIME_HARD_MODE, - Settings.Global.Wearable.EARLY_UPDATES_STATUS, Settings.Global.Wearable.RSB_WAKE_ENABLED, Settings.Global.Wearable.LOCK_SCREEN_STATE, Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_ENABLED, Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_TYPE, Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_SPEED, - Settings.Global.Wearable.SCREENSHOT_ENABLED); + Settings.Global.Wearable.SCREENSHOT_ENABLED, + Settings.Global.Wearable.DISABLE_AOD_WHILE_PLUGGED, + Settings.Global.Wearable.NETWORK_LOCATION_OPT_IN, + Settings.Global.Wearable.CUSTOM_COLOR_FOREGROUND, + Settings.Global.Wearable.CUSTOM_COLOR_BACKGROUND, + Settings.Global.Wearable.PHONE_SWITCHING_STATUS, + Settings.Global.Wearable.TETHER_CONFIG_STATE, + Settings.Global.Wearable.PHONE_SWITCHING_SUPPORTED, + Settings.Global.Wearable.WEAR_MEDIA_CONTROLS_PACKAGE, + Settings.Global.Wearable.WEAR_MEDIA_SESSIONS_PACKAGE); private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS = newHashSet( diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index fedfb43535cc..78d93bd19a15 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -58,7 +58,6 @@ <uses-permission android:name="android.permission.ACCEPT_HANDOVER" /> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> <uses-permission android:name="android.permission.BODY_SENSORS" /> - <uses-permission android:name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE" /> <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" /> <uses-permission android:name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" /> diff --git a/packages/Shell/res/values-or/strings.xml b/packages/Shell/res/values-or/strings.xml index 517183972e4d..190dc5b851fe 100644 --- a/packages/Shell/res/values-or/strings.xml +++ b/packages/Shell/res/values-or/strings.xml @@ -35,7 +35,7 @@ <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"ଜିପ୍ ଫାଇଲରେ ବଗ୍ ରିପୋର୍ଟ ବିବରଣୀ ଯୋଡ଼ାଯାଇପାରିଲା ନାହିଁ"</string> <string name="bugreport_unnamed" msgid="2800582406842092709">"ବେନାମୀ"</string> <string name="bugreport_info_action" msgid="2158204228510576227">"ବିବରଣୀ"</string> - <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ସ୍କ୍ରିନ୍ସଟ୍"</string> + <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ସ୍କ୍ରିନସଟ"</string> <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ସଫଳତାପୂର୍ବକ ସ୍କ୍ରୀନଶଟ୍ ନିଆଗଲା"</string> <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ସ୍କ୍ରୀନ୍ଶଟ୍ ନିଆଯାଇପାରିଲା ନାହିଁ।"</string> <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ବଗ୍ ରିପୋର୍ଟ <xliff:g id="ID">#%d</xliff:g>ର ବିବରଣୀ"</string> diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 3007d4a79d13..9d32e905d85d 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -156,9 +156,10 @@ android_library { "WifiTrackerLib", "WindowManager-Shell", "SystemUIAnimationLib", + "SystemUICommon", + "SystemUICustomizationLib", "SystemUIPluginLib", "SystemUISharedLib", - "SystemUICustomizationLib", "SystemUI-statsd", "SettingsLib", "androidx.core_core-ktx", @@ -258,6 +259,24 @@ filegroup { "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt", "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt", "tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt", + + // Biometric + "tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt", + "tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt", + "tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt", + "tests/src/com/android/systemui/biometrics/AuthControllerTest.java", + "tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java", + "tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt", + "tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt", + "tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt", + "tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java", + "tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java", + "tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java", + "tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java", + "tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java", + "tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt", + "tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt", + "tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt", ], path: "tests/src", } @@ -402,6 +421,10 @@ android_app { privileged: true, resource_dirs: [], kotlincflags: ["-Xjvm-default=all"], + optimize: { + shrink_resources: false, + proguard_flags_files: ["proguard.flags"], + }, plugins: ["dagger2-compiler"], } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 36a0b5dd72b8..a00f401756f7 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -347,15 +347,6 @@ <uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" /> - <!-- Intent Chooser --> - <permission - android:name="android.permission.ADD_CHOOSER_PINS" - android:protectionLevel="signature" /> - <uses-permission android:name="android.permission.ADD_CHOOSER_PINS" /> - <permission - android:name="android.permission.RECEIVE_CHOOSER_PIN_MIGRATION" - android:protectionLevel="signature" /> - <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" /> @@ -993,7 +984,13 @@ android:exported="true" android:excludeFromRecents="true" android:resizeableActivity="false" - android:theme="@android:style/Theme.NoDisplay" /> + android:theme="@android:style/Theme.NoDisplay" > + + <intent-filter> + <action android:name="com.android.systemui.action.LAUNCH_NOTE_TASK"/> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> <!-- LaunchNoteTaskManagedProfileProxyActivity MUST NOT be exported because it allows caller to specify an Android user when launching the default notes app. --> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/preferences_action_bar.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/preferences_action_bar.xml new file mode 100644 index 000000000000..1d67066028be --- /dev/null +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/preferences_action_bar.xml @@ -0,0 +1,29 @@ +<?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="match_parent" + android:layout_height="match_parent"> + + <TextView + android:id="@+id/action_bar_title" + style="@style/TextAppearance.AppCompat.Title" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:maxLines="5"/> +</LinearLayout> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bg/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bg/strings.xml index 165b9276adce..8faa67048846 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-bg/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-bg/strings.xml @@ -22,7 +22,7 @@ <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">"Увеличаване на размера на бутоните в менюто за достъпност"</string> <string name="pref_help_title" msgid="6871558837025010641">"Помощ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml index 9214197ee9bd..fb31e1da6361 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-de/strings.xml @@ -10,8 +10,8 @@ <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> <string name="lockscreen_label" msgid="648347953557887087">"Sperrbildschirm"</string> - <string name="quick_settings_label" msgid="2999117381487601865">"Schnelleinstellungen"</string> - <string name="notifications_label" msgid="6829741046963013567">"Benachrichtigungen"</string> + <string name="quick_settings_label" msgid="2999117381487601865">"Schnelleinstellungen"</string> + <string name="notifications_label" msgid="6829741046963013567">"Benachrichtigungen"</string> <string name="screenshot_label" msgid="863978141223970162">"Screenshot"</string> <string name="screenshot_utterance" msgid="1430760563401895074">"Screenshot erstellen"</string> <string name="volume_up_label" msgid="8592766918780362870">"Lautstärke erhöhen"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-el/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-el/strings.xml index c51c9afa07cc..60e49ae0fbc1 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-el/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-el/strings.xml @@ -5,7 +5,7 @@ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Το μενού προσβασιμότητας παρέχει ένα μεγάλο μενού στην οθόνη για να ελέγχετε τη συσκευή σας. Μπορείτε να κλειδώνετε τη συσκευή, να ελέγχετε την ένταση ήχου και τη φωτεινότητα, να λαμβάνετε στιγμιότυπα οθόνης και άλλα."</string> <string name="assistant_label" msgid="6796392082252272356">"Βοηθός"</string> <string name="assistant_utterance" msgid="65509599221141377">"Βοηθός"</string> - <string name="a11y_settings_label" msgid="3977714687248445050">"Ρυθμίσεις προσβασιμότητας"</string> + <string name="a11y_settings_label" msgid="3977714687248445050">"Ρυθμίσεις προσβU+00ADασιμότητας"</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 46702917a7a3..5968179563cd 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rAU/strings.xml @@ -22,7 +22,7 @@ <string name="next_button_content_description" msgid="6810058269847364406">"Go to next screen"</string> <string name="accessibility_menu_description" msgid="4458354794093858297">"The Accessibility menu provides a large on-screen menu to control your device. You can lock your device, control volume and brightness, take screenshots and more."</string> <string name="accessibility_menu_summary" msgid="340071398148208130">"Control device via large menu"</string> - <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Accessibility menu settings"</string> + <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Accessibility Menu settings"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Large buttons"</string> <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Increase size of Accessibility menu buttons"</string> <string name="pref_help_title" msgid="6871558837025010641">"Help"</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 46702917a7a3..5968179563cd 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rGB/strings.xml @@ -22,7 +22,7 @@ <string name="next_button_content_description" msgid="6810058269847364406">"Go to next screen"</string> <string name="accessibility_menu_description" msgid="4458354794093858297">"The Accessibility menu provides a large on-screen menu to control your device. You can lock your device, control volume and brightness, take screenshots and more."</string> <string name="accessibility_menu_summary" msgid="340071398148208130">"Control device via large menu"</string> - <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Accessibility menu settings"</string> + <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Accessibility Menu settings"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Large buttons"</string> <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Increase size of Accessibility menu buttons"</string> <string name="pref_help_title" msgid="6871558837025010641">"Help"</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 46702917a7a3..5968179563cd 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-en-rIN/strings.xml @@ -22,7 +22,7 @@ <string name="next_button_content_description" msgid="6810058269847364406">"Go to next screen"</string> <string name="accessibility_menu_description" msgid="4458354794093858297">"The Accessibility menu provides a large on-screen menu to control your device. You can lock your device, control volume and brightness, take screenshots and more."</string> <string name="accessibility_menu_summary" msgid="340071398148208130">"Control device via large menu"</string> - <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Accessibility menu settings"</string> + <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Accessibility Menu settings"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Large buttons"</string> <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Increase size of Accessibility menu buttons"</string> <string name="pref_help_title" msgid="6871558837025010641">"Help"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml index 28b560a71de7..f6dcdd3dc0bd 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-eu/strings.xml @@ -5,7 +5,7 @@ <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> <string name="assistant_utterance" msgid="65509599221141377">"Laguntzailea"</string> - <string name="a11y_settings_label" msgid="3977714687248445050">"Erabilerraztasun-ezarpenak"</string> + <string name="a11y_settings_label" msgid="3977714687248445050">"Erabilerraztasun-&#173;ezarpenak"</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-fr-rCA/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml index 87a95037178e..1715d56ede7a 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fr-rCA/strings.xml @@ -1,7 +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"> - <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu Accessibilité"</string> + <string name="accessibility_menu_service_name" msgid="730136711554740131">"menu 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> <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hy/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hy/strings.xml index 135d44326c66..e06787fdd297 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hy/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hy/strings.xml @@ -10,7 +10,7 @@ <string name="power_utterance" msgid="7444296686402104807">"Սնուցման կոճակի ընտրանքներ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"Վերջին հավելվածներ"</string> <string name="lockscreen_label" msgid="648347953557887087">"Կողպէկրան"</string> - <string name="quick_settings_label" msgid="2999117381487601865">"Արագ կարգավորումներ"</string> + <string name="quick_settings_label" msgid="2999117381487601865">"Արագ\\nկարգավորումներ"</string> <string name="notifications_label" msgid="6829741046963013567">"Ծանուցումներ"</string> <string name="screenshot_label" msgid="863978141223970162">"Սքրինշոթ"</string> <string name="screenshot_utterance" msgid="1430760563401895074">"Ստանալ սքրինշոթը"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml index 68f3fae65dbb..9726f2056a36 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kk/strings.xml @@ -11,7 +11,7 @@ <string name="recent_apps_label" msgid="6583276995616385847">"Соңғы қолданбалар"</string> <string name="lockscreen_label" msgid="648347953557887087">"Құлып экраны"</string> <string name="quick_settings_label" msgid="2999117381487601865">"Жылдам параметрлер"</string> - <string name="notifications_label" msgid="6829741046963013567">"Хабарландырулар"</string> + <string name="notifications_label" msgid="6829741046963013567">"Хабарланды00ADрулар"</string> <string name="screenshot_label" msgid="863978141223970162">"Скриншот"</string> <string name="screenshot_utterance" msgid="1430760563401895074">"Скриншот жасау"</string> <string name="volume_up_label" msgid="8592766918780362870">"Дыбысын арттыру"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-or/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-or/strings.xml index ba2259616075..3a40b9f2511d 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-or/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-or/strings.xml @@ -23,7 +23,7 @@ <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_large_buttons_title" msgid="8978499601044961736">"ବଡ଼ ବଟନ୍"</string> + <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"ବଡ଼ ବଟନ"</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> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pa/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pa/strings.xml index 31fab247336b..bfe0980666fd 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pa/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pa/strings.xml @@ -9,7 +9,7 @@ <string name="power_label" msgid="7699720321491287839">"ਪਾਵਰ"</string> <string name="power_utterance" msgid="7444296686402104807">"ਪਾਵਰ ਵਿਕਲਪ"</string> <string name="recent_apps_label" msgid="6583276995616385847">"ਹਾਲੀਆ ਐਪਾਂ"</string> - <string name="lockscreen_label" msgid="648347953557887087">"ਲਾਕ ਸਕ੍ਰੀਨ"</string> + <string name="lockscreen_label" msgid="648347953557887087">"ਸਕ੍ਰੀਨ ਲਾਕ ਕਰੋ"</string> <string name="quick_settings_label" msgid="2999117381487601865">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ"</string> <string name="notifications_label" msgid="6829741046963013567">"ਸੂਚਨਾਵਾਂ"</string> <string name="screenshot_label" msgid="863978141223970162">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/activity/A11yMenuSettingsActivity.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/activity/A11yMenuSettingsActivity.java index 02d279fa4962..5ed450abede5 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/activity/A11yMenuSettingsActivity.java +++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/activity/A11yMenuSettingsActivity.java @@ -16,6 +16,7 @@ package com.android.systemui.accessibility.accessibilitymenu.activity; +import android.app.ActionBar; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -24,6 +25,7 @@ import android.net.Uri; import android.os.Bundle; import android.provider.Browser; import android.provider.Settings; +import android.widget.TextView; import android.view.View; import androidx.annotation.Nullable; @@ -46,6 +48,13 @@ public class A11yMenuSettingsActivity extends FragmentActivity { .beginTransaction() .replace(android.R.id.content, new A11yMenuPreferenceFragment()) .commit(); + + ActionBar actionBar = getActionBar(); + actionBar.setDisplayShowCustomEnabled(true); + actionBar.setCustomView(R.layout.preferences_action_bar); + ((TextView) findViewById(R.id.action_bar_title)).setText( + getResources().getString(R.string.accessibility_menu_settings_name) + ); } /** diff --git a/packages/SystemUI/common/.gitignore b/packages/SystemUI/common/.gitignore new file mode 100644 index 000000000000..f9a33dbbcc7e --- /dev/null +++ b/packages/SystemUI/common/.gitignore @@ -0,0 +1,9 @@ +.idea/ +.gradle/ +gradle/ +build/ +gradlew* +local.properties +*.iml +android.properties +buildSrc
\ No newline at end of file diff --git a/core/tests/expresslog/Android.bp b/packages/SystemUI/common/Android.bp index cab49a76a734..e36ada89b207 100644 --- a/core/tests/expresslog/Android.bp +++ b/packages/SystemUI/common/Android.bp @@ -15,33 +15,25 @@ package { // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" + // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license" // to get the below license kinds: // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], } -android_test { - name: "ExpressLogTests", +android_library { + + name: "SystemUICommon", srcs: [ "src/**/*.java", + "src/**/*.kt", ], static_libs: [ - "androidx.test.rules", - "modules-utils-build", - ], - - libs: [ - "android.test.base", - "android.test.runner", - ], - - platform_apis: true, - test_suites: [ - "general-tests", + "androidx.core_core-ktx", ], - certificate: "platform", + manifest: "AndroidManifest.xml", + kotlincflags: ["-Xjvm-default=all"], } diff --git a/core/tests/expresslog/AndroidManifest.xml b/packages/SystemUI/common/AndroidManifest.xml index 94a39e06c974..6f757eb67d2e 100644 --- a/core/tests/expresslog/AndroidManifest.xml +++ b/packages/SystemUI/common/AndroidManifest.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2023 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. @@ -15,15 +16,6 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - android:installLocation="internalOnly" - package="com.android.internal.expresslog" > - - <application > - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.internal.expresslog" - android:label="Telemetry Express Logging Helper Tests" /> + package="com.android.systemui.common"> </manifest> diff --git a/packages/SystemUI/common/OWNERS b/packages/SystemUI/common/OWNERS new file mode 100644 index 000000000000..9b8a79e6f3c7 --- /dev/null +++ b/packages/SystemUI/common/OWNERS @@ -0,0 +1,2 @@ +darrellshi@google.com +evanlaird@google.com diff --git a/packages/SystemUI/common/README.md b/packages/SystemUI/common/README.md new file mode 100644 index 000000000000..1cc5277aa83e --- /dev/null +++ b/packages/SystemUI/common/README.md @@ -0,0 +1,5 @@ +# SystemUICommon + +`SystemUICommon` is a module within SystemUI that hosts standalone helper libraries. It is intended to be used by other modules, and therefore should not have other SystemUI dependencies to avoid circular dependencies. + +To maintain the structure of this module, please refrain from adding components at the top level. Instead, add them to specific sub-packages, such as `systemui/common/buffer/`. This will help to keep the module organized and easy to navigate. diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt b/packages/SystemUI/common/src/com/android/systemui/common/buffer/RingBuffer.kt index 4773f54a079e..4734a3887f78 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt +++ b/packages/SystemUI/common/src/com/android/systemui/common/buffer/RingBuffer.kt @@ -14,19 +14,21 @@ * limitations under the License. */ -package com.android.systemui.plugins.util +package com.android.systemui.common.buffer import kotlin.math.max /** - * A simple ring buffer implementation + * A simple ring buffer of recycled items * - * Use [advance] to get the least recent item in the buffer (and then presumably fill it with - * appropriate data). This will cause it to become the most recent item. + * Use [advance] to add items to the buffer. * * As the buffer is used, it will grow, allocating new instances of T using [factory] until it - * reaches [maxSize]. After this point, no new instances will be created. Instead, the "oldest" - * instances will be recycled from the back of the buffer and placed at the front. + * reaches [maxSize]. After this point, no new instances will be created. Instead, calls to + * [advance] will recycle the "oldest" instance from the start of the buffer, placing it at the end. + * + * The items in the buffer are "recycled" in that they are reused, but it is up to the caller of + * [advance] to properly reset any data that was previously stored on those items. * * @param maxSize The maximum size the buffer can grow to before it begins functioning as a ring. * @param factory A function that creates a fresh instance of T. Used by the buffer while it's @@ -37,11 +39,13 @@ class RingBuffer<T>(private val maxSize: Int, private val factory: () -> T) : It private val buffer = MutableList<T?>(maxSize) { null } /** - * An abstract representation that points to the "end" of the buffer. Increments every time - * [advance] is called and never wraps. Use [indexOf] to calculate the associated index into the - * backing array. Always points to the "next" available slot in the buffer. Before the buffer - * has completely filled, the value pointed to will be null. Afterward, it will be the value at - * the "beginning" of the buffer. + * An abstract representation that points to the "end" of the buffer, i.e. one beyond the + * location of the last item. Increments every time [advance] is called and is never wrapped. + * + * Use [indexOf] to calculate the associated index into the backing array. Before the buffer has + * been completely filled, this will point to the next empty slot to fill; afterwards it will + * point to the next item that should be recycled (which, because the buffer is a ring, is the + * "start" of the buffer). * * This value is unlikely to overflow. Assuming [advance] is called at rate of 100 calls/ms, * omega will overflow after a little under three million years of continuous operation. @@ -56,12 +60,15 @@ class RingBuffer<T>(private val maxSize: Int, private val factory: () -> T) : It get() = if (omega < maxSize) omega.toInt() else maxSize /** - * Advances the buffer's position by one and returns the value that is now present at the "end" - * of the buffer. If the buffer is not yet full, uses [factory] to create a new item. Otherwise, - * reuses the value that was previously at the "beginning" of the buffer. + * Adds an item to the end of the buffer. The caller should reset the returned item's contents + * and then fill it with appropriate data. + * + * If the buffer is not yet full, uses [factory] to create a new item. Otherwise, it recycles + * the oldest item from the front of the buffer and moves it to the end. * - * IMPORTANT: The value is returned as-is, without being reset. It will retain any data that was - * previously stored on it. + * Importantly, recycled items are returned as-is, without being reset. They will retain any + * data that was previously stored on them. Callers must make sure to clear any historical data, + * if necessary. */ fun advance(): T { val index = indexOf(omega) @@ -72,8 +79,7 @@ class RingBuffer<T>(private val maxSize: Int, private val factory: () -> T) : It /** * Returns the value stored at [index], which can range from 0 (the "start", or oldest element - * of the buffer) to [size] - * - 1 (the "end", or newest element of the buffer). + * of the buffer) to [size] - 1 (the "end", or newest element of the buffer). */ operator fun get(index: Int): T { if (index < 0 || index >= size) { @@ -89,12 +95,6 @@ class RingBuffer<T>(private val maxSize: Int, private val factory: () -> T) : It return buffer[indexOf(start + index)]!! } - inline fun forEach(action: (T) -> Unit) { - for (i in 0 until size) { - action(get(i)) - } - } - override fun iterator(): Iterator<T> { return object : Iterator<T> { private var position: Int = 0 diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index a7e95b58a6e4..eaf3229bf0c8 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -33,6 +33,7 @@ import com.android.systemui.plugins.PluginLifecycleManager import com.android.systemui.plugins.PluginListener import com.android.systemui.plugins.PluginManager import com.android.systemui.util.Assert +import java.io.PrintWriter import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicBoolean import kotlinx.coroutines.CoroutineDispatcher @@ -485,6 +486,14 @@ open class ClockRegistry( return availableClocks[targetClockId]?.provider?.createClock(settings) } + fun dump(pw: PrintWriter, args: Array<out String>) { + pw.println("ClockRegistry:") + pw.println(" settings = $settings") + for ((id, info) in availableClocks) { + pw.println(" availableClocks[$id] = $info") + } + } + private data class ClockInfo( val metadata: ClockMetadata, var provider: ClockProvider?, diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp index fb1c454de70d..e306d4aac398 100644 --- a/packages/SystemUI/plugin/Android.bp +++ b/packages/SystemUI/plugin/Android.bp @@ -37,6 +37,7 @@ java_library { "error_prone_annotations", "PluginCoreLib", "SystemUIAnimationLib", + "SystemUICommon", ], } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index 1fec3314a13e..6d4dbf632d76 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java @@ -79,6 +79,11 @@ public interface ActivityStarter { void postStartActivityDismissingKeyguard(Intent intent, int delay); void postStartActivityDismissingKeyguard(Intent intent, int delay, @Nullable ActivityLaunchAnimator.Controller animationController); + + /** Posts a start activity intent that dismisses keyguard. */ + void postStartActivityDismissingKeyguard(Intent intent, int delay, + @Nullable ActivityLaunchAnimator.Controller animationController, + @Nullable String customMessage); void postStartActivityDismissingKeyguard(PendingIntent intent); /** @@ -93,6 +98,10 @@ public interface ActivityStarter { void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel, boolean afterKeyguardGone); + /** Authenticates if needed and dismisses keyguard to execute an action. */ + void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel, + boolean afterKeyguardGone, @Nullable String customMessage); + interface Callback { void onActivityStarted(int resultCode); } 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 322fc774e805..05630e795476 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt @@ -199,6 +199,9 @@ data class ClockConfig( */ val hasCustomPositionUpdatedAnimation: Boolean = false, + /** Transition to AOD should move smartspace like large clock instead of small clock */ + val useAlternateSmartspaceAODTransition: Boolean = false, + /** True if the clock will react to tone changes in the seed color. */ val isReactiveToTone: Boolean = true, ) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt index 52dfc55c105d..2dd146c5134d 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt @@ -4,7 +4,7 @@ import android.os.Bundle import androidx.annotation.VisibleForTesting class WeatherData -private constructor( +constructor( val description: String, val state: WeatherStateIcon, val useCelsius: Boolean, @@ -47,6 +47,7 @@ private constructor( } } + // Values for WeatherStateIcon must stay in sync with go/g3-WeatherStateIcon enum class WeatherStateIcon(val id: Int) { UNKNOWN_ICON(0), diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt index 3e34885a6d9c..0a7ccc525a73 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt @@ -18,7 +18,7 @@ package com.android.systemui.plugins.log import android.os.Trace import android.util.Log -import com.android.systemui.plugins.util.RingBuffer +import com.android.systemui.common.buffer.RingBuffer import com.google.errorprone.annotations.CompileTimeConstant import java.io.PrintWriter import java.util.concurrent.ArrayBlockingQueue @@ -253,8 +253,8 @@ constructor( @Synchronized fun unfreeze() { if (frozen) { - log(TAG, LogLevel.DEBUG, { str1 = name }, { "$str1 unfrozen" }) frozen = false + log(TAG, LogLevel.DEBUG, { str1 = name }, { "$str1 unfrozen" }) } } diff --git a/packages/SystemUI/res-keyguard/drawable/fp_to_locked.xml b/packages/SystemUI/res-keyguard/drawable/fp_to_locked.xml new file mode 100644 index 000000000000..61a1cb5f1d31 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/fp_to_locked.xml @@ -0,0 +1,165 @@ +<?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 + --> +<animated-vector + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46"> + <group android:name="_R_G"> + <group android:name="_R_G_L_1_G" android:translateX="3.75" android:translateY="8.25"> + <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 "/> + <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 "/> + <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 "/> + <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 "/> + </group> + <group android:name="_R_G_L_0_G" android:translateX="20.357" android:translateY="35.75" android:pivotX="2.75" android:pivotY="2.75" android:scaleX="1.41866" android:scaleY="1.41866"> + <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#FF000000" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c "/> + </group> + </group> + <group android:name="time_group"/> + </vector> + </aapt:attr> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="0" android:valueFrom="M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " android:valueTo="M30.81 32.26 C30.56,32.49 30.27,38.76 29.96,38.9 C29.77,39.46 29.13,39.94 28.57,40.26 C28.15,40.51 26.93,40.65 26.4,40.65 C26.18,40.65 11.91,40.62 11.71,40.58 C10.68,40.53 9.06,39.79 8.89,38.88 C8.6,38.74 8.34,32.48 8.1,32.27 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="143" android:startOffset="107" android:valueFrom="M30.81 32.26 C30.56,32.49 30.27,38.76 29.96,38.9 C29.77,39.46 29.13,39.94 28.57,40.26 C28.15,40.51 26.93,40.65 26.4,40.65 C26.18,40.65 11.91,40.62 11.71,40.58 C10.68,40.53 9.06,39.79 8.89,38.88 C8.6,38.74 8.34,32.48 8.1,32.27 " android:valueTo="M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.331,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_1_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="strokeAlpha" android:duration="140" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="strokeAlpha" android:duration="50" android:startOffset="140" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_1_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="0" android:valueFrom="M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " android:valueTo="M18.93 32.18 C17.11,32.68 16.62,30.26 16.62,30.26 C16.62,28.78 17.81,27.59 19.39,27.59 C20.96,27.59 22.15,28.78 22.15,30.26 C22.15,30.26 22.15,30.34 22.15,30.34 C22.15,30.89 21.11,32.54 19.57,32.19 C19.19,32.1 20.48,31.09 20.34,30.71 C20.34,30.71 20.02,29.88 20.02,29.88 C19.88,29.5 19.53,29.25 19.15,29.25 C18.63,29.25 18,29.67 18,30.22 C18,30.57 18.06,31.08 18.32,31.51 C18.49,31.8 19.02,32.25 19.79,32.04 C20.41,31.7 20.38,31.36 20.38,31.36 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="107" android:valueFrom="M18.93 32.18 C17.11,32.68 16.62,30.26 16.62,30.26 C16.62,28.78 17.81,27.59 19.39,27.59 C20.96,27.59 22.15,28.78 22.15,30.26 C22.15,30.26 22.15,30.34 22.15,30.34 C22.15,30.89 21.11,32.54 19.57,32.19 C19.19,32.1 20.48,31.09 20.34,30.71 C20.34,30.71 20.02,29.88 20.02,29.88 C19.88,29.5 19.53,29.25 19.15,29.25 C18.63,29.25 18,29.67 18,30.22 C18,30.57 18.06,31.08 18.32,31.51 C18.49,31.8 19.02,32.25 19.79,32.04 C20.41,31.7 20.38,31.36 20.38,31.36 " android:valueTo="M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_2_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="250" android:startOffset="0" android:valueFrom="M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " android:valueTo="M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.189,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_3_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="95" android:startOffset="0" android:valueFrom="M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " android:valueTo="M11.47 14.84 C11.47,14.84 12.21,11.43 13.54,9.84 C14.84,8.28 16.68,7.22 19.35,7.22 C22.01,7.22 23.98,8.4 25.19,10.18 C26.39,11.96 27.25,14.84 27.25,14.84 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="24" android:startOffset="95" android:valueFrom="M11.47 14.84 C11.47,14.84 12.21,11.43 13.54,9.84 C14.84,8.28 16.68,7.22 19.35,7.22 C22.01,7.22 23.98,8.4 25.19,10.18 C26.39,11.96 27.25,14.84 27.25,14.84 " android:valueTo="M12.11 16.85 C12.11,16.85 12.82,12.71 13.37,11.5 C14.17,9.24 16.38,7.53 19.35,7.53 C22.32,7.53 24.61,9.32 25.35,11.72 C25.61,12.64 26.62,16.85 26.62,16.85 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.833,0.767 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="81" android:startOffset="119" android:valueFrom="M12.11 16.85 C12.11,16.85 12.82,12.71 13.37,11.5 C14.17,9.24 16.38,7.53 19.35,7.53 C22.32,7.53 24.61,9.32 25.35,11.72 C25.61,12.64 26.62,16.85 26.62,16.85 " android:valueTo="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.261,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="fillAlpha" android:duration="120" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="20" android:startOffset="120" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="scaleX" android:duration="120" android:startOffset="0" android:valueFrom="1.4186600000000003" android:valueTo="1.4186600000000003" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="120" android:startOffset="0" android:valueFrom="1.4186600000000003" android:valueTo="1.4186600000000003" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="130" android:startOffset="120" android:valueFrom="1.4186600000000003" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="130" android:startOffset="120" android:valueFrom="1.4186600000000003" android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/> + </set> + </aapt:attr> + </target> +</animated-vector> diff --git a/packages/SystemUI/res-keyguard/drawable/ic_palette.xml b/packages/SystemUI/res-keyguard/drawable/ic_palette.xml new file mode 100644 index 000000000000..cbea369c0236 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_palette.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="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960"> + <path + android:fillColor="@android:color/white" + android:pathData="M480,880Q398,880 325,848.5Q252,817 197.5,762.5Q143,708 111.5,635Q80,562 80,480Q80,395 112,322Q144,249 199.5,195Q255,141 329.5,110.5Q404,80 489,80Q568,80 639,106.5Q710,133 763.5,180Q817,227 848.5,291.5Q880,356 880,433Q880,541 817,603.5Q754,666 650,666L575,666Q557,666 544,680Q531,694 531,711Q531,738 545.5,757Q560,776 560,801Q560,839 539,859.5Q518,880 480,880ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM247,506Q267,506 282,491Q297,476 297,456Q297,436 282,421Q267,406 247,406Q227,406 212,421Q197,436 197,456Q197,476 212,491Q227,506 247,506ZM373,336Q393,336 408,321Q423,306 423,286Q423,266 408,251Q393,236 373,236Q353,236 338,251Q323,266 323,286Q323,306 338,321Q353,336 373,336ZM587,336Q607,336 622,321Q637,306 637,286Q637,266 622,251Q607,236 587,236Q567,236 552,251Q537,266 537,286Q537,306 552,321Q567,336 587,336ZM718,506Q738,506 753,491Q768,476 768,456Q768,436 753,421Q738,406 718,406Q698,406 683,421Q668,436 668,456Q668,476 683,491Q698,506 718,506ZM480,820Q491,820 495.5,815.5Q500,811 500,801Q500,787 485.5,775Q471,763 471,722Q471,676 501,641Q531,606 577,606L650,606Q726,606 773,561.5Q820,517 820,433Q820,301 720,220.5Q620,140 489,140Q343,140 241.5,238.5Q140,337 140,480Q140,621 239.5,720.5Q339,820 480,820Z"/> +</vector> diff --git a/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml index 951d6fed0a17..f3325ecefada 100644 --- a/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml +++ b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml @@ -104,4 +104,9 @@ android:fromId="@id/unlocked" android:toId="@id/locked" android:drawable="@drawable/unlocked_to_locked" /> + + <transition + android:fromId="@id/locked_fp" + android:toId="@id/locked" + android:drawable="@drawable/fp_to_locked" /> </animated-selector> diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml index 526b654c2522..39b418394a13 100644 --- a/packages/SystemUI/res-keyguard/values-af/strings.xml +++ b/packages/SystemUI/res-keyguard/values-af/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Voer jou PIN in"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Voer PIN in"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Voer jou patroon in"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Teken patroon"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Voer jou wagwoord in"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Voer wagwoord in"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ongeldige kaart."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Gelaai"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laai tans draadloos"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Die e-SIM kan weens \'n fout nie gedeaktiveer word nie."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Verkeerde patroon"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Verkeerde patroon. Probeer weer."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Verkeerde wagwoord"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Verkeerde wagwoord. Probeer weer."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Verkeerde PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Verkeerde PIN. Probeer weer."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Of ontsluit met vingerafdruk"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Vingerafdruk nie herken nie"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Gesig nie erken nie"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Probeer weer of voer PIN in"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Probeer weer of voer wagwoord in"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Probeer weer of voer patroon in"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN word vereis as daar te veel pogings was"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Wagwoord word vereis as daar te veel pogings was"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Patroon word vereis as daar te veel pogings was"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Ontsluit met PIN of vingerafdruk"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Ontsluit met wagwoord of vingerafdruk"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Ontsluit met patroon of vingerafdruk"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Toestel deur werkbeleid gesluit vir meer sekuriteit"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN word vereis ná vassluit"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Wagwoord word vereis ná vassluit"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Patroon word vereis ná vassluit"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Opdatering word tydens onaktiewe ure geïnstalleer"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Meer sekuriteit vereis. PIN ruk lank nie gebruik nie."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Meer sekuriteit vereis. Wagwoord ruk lank nie gebruik nie."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Meer sekuriteit vereis. Patroon ruk lank nie gebruik nie."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Meer sekuriteit vereis. Toestel ruk lank nie ontsluit nie."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Kan nie met gesig ontsluit nie. Te veel pogings."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Kan nie met vingerafdruk ontsluit nie. Te veel pogings."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Vertrouensagent is nie beskikbaar nie"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Te veel pogings met verkeerde PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Te veel pogings met verkeerde patroon"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Te veel pogings met verkeerde wagwoord"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Probeer weer oor # sekonde.}other{Probeer weer oor # sekondes.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Voer SIM se PIN in."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Voer SIM se PIN vir \"<xliff:g id="CARRIER">%1$s</xliff:g>\" in."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-PUK-bewerking het misluk!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Wissel invoermetode"</string> <string name="airplane_mode" msgid="2528005343938497866">"Vliegtuigmodus"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Patroon word vereis nadat toestel herbegin"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN word vereis nadat toestel herbegin"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Wagwoord word vereis nadat toestel herbegin"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik eerder ’n patroon vir bykomende sekuriteit"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik eerder ’n PIN vir bykomende sekuriteit"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik eerder ’n wagwoord vir bykomende sekuriteit"</string> diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml index ae7e1f98a41b..e175007b76e9 100644 --- a/packages/SystemUI/res-keyguard/values-am/strings.xml +++ b/packages/SystemUI/res-keyguard/values-am/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"የእርስዎን ፒን ያስገቡ"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"ፒን ያስገቡ"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"ሥርዓተ-ጥለትዎን ያስገቡ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ስርዓተ ጥለት ይሳሉ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"ይለፍ ቃልዎን ያስገቡ"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"የይለፍ ቃል ያስገቡ"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ልክ ያልሆነ ካርድ።"</string> <string name="keyguard_charged" msgid="5478247181205188995">"ባትሪ ሞልቷል"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • በገመድ አልባ ኃይል በመሙላት ላይ"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"በአንድ ስህተት ምክንያት eSIM ሊሰናከል አልቻለም።"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"አስገባ"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"የተሳሳተ ሥርዓተ ጥለት"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"የተሳሳተ ስርዓተ ጥለት። እንደገና ይሞክሩ።"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"የተሳሳተ የይለፍ ቃል"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"የተሳሳተ የይለፍ ቃል። እንደገና ይሞክሩ።"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"የተሳሳተ ፒን"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"የተሳሳተ ፒን። እንደገና ይሞክሩ።"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"ወይም በጣት አሻራ ይክፈቱ"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"የጣት አሻራ አልታወቀም"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ፊት አልታወቀም"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"እንደገና ይሞክሩ ወይም ፒን ያስገቡ"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"እንደገና ይሞክሩ ወይም የይለፍ ቃል ያስገቡ"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"እንደገና ይሞክሩ ወይም ስርዓተ ጥለት ይሳሉ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"በጣም ከብዙ ሙከራዎች በኋላ ፒን ያስፈልጋል"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"በጣም ከብዙ ሙከራዎች በኋላ የይለፍ ቃል ያስፈልጋል"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"በጣም ከብዙ ሙከራዎች በኋላ ስርዓተ ጥለት ያስፈልጋል"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"በፒን ወይም የጣት አሻራ ይክፈቱ"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"በይለፍ ቃል ወይም የጣት አሻራ ይክፈቱ"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"በስርዓተ ጥለት ወይም የጣት አሻራ ይክፈቱ"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"ለተጨማሪ ደህንነት፣ መሣሪያ በሥራ መመሪያ ተቆልፏል"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ከመቆለፊያ በኋላ ፒን ያስፈልጋል"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ከመቆለፊያ በኋላ የይለፍ ቃል ያስፈልጋል"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ከመቆለፊያ በኋላ ስርዓተ ጥለት ያስፈልጋል"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"ዝማኔ በቦዘኑ ሰዓታት ወቅት ይጭናል"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ተጨማሪ የደህንነት ጥበቃ ያስፈልጋል። ፒን ለተወሰነ ጊዜ ጥቅም ላይ አልዋለም።"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ተጨማሪ የደህንነት ጥበቃ ያስፈልጋል። የይለፍ ቃል ለተወሰነ ጊዜ ጥቅም ላይ አልዋለም።"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ተጨማሪ የደህንነት ጥበቃ ያስፈልጋል። ስርዓተ ጥለት ለተወሰነ ጊዜ ጥቅም ላይ አልዋለም።"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"ተጨማሪ የደህንነት ጥበቃ ያስፈልጋል። መሣሪያ ለተወሰነ ጊዜ አልተቆለፈም ነበር።"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"በፊት መክፈት አልተቻለም። በጣም ብዙ ሙከራዎች።"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"በጣት አሻራ መክፈት አልተቻለም። በጣም ብዙ ሙከራዎች።"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"የተአማኒነት ወኪል አይገኝም"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"በተሳሳተ ፒን በጣም ብዙ ሙከራዎች"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"በተሳሳተ ስርዓተ ጥለት በጣም ብዙ ሙከራዎች"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"በተሳሳተ የይለፍ ቃል በጣም ብዙ ሙከራዎች"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{በ# ሰከንድ ውስጥ እንደገና ይሞክሩ።}one{በ# ሰከንድ ውስጥ እንደገና ይሞክሩ።}other{በ# ሰከንዶች ውስጥ እንደገና ይሞክሩ።}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"የሲም ፒን ያስገቡ።"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"የ«<xliff:g id="CARRIER">%1$s</xliff:g>» ሲም ፒን ያስገቡ።"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"የሲም PUK ክወና አልተሳካም!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"የግቤት ስልት ቀይር"</string> <string name="airplane_mode" msgid="2528005343938497866">"የአውሮፕላን ሁነታ"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"መሣሪያ እንደገና ከጀመረ በኋላ ስርዓተ ጥለት ያስፈልጋል"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"መሣሪያ እንደገና ከጀመረ በኋላ ፒን ያስፈልጋል"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"መሣሪያ እንደገና ከጀመረ በኋላ የይለፍ ቃል ያስፈልጋል"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ለተጨማሪ ደህንነት በምትኩ ስርዓተ ጥለት ይጠቀሙ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ለተጨማሪ ደህንነት በምትኩ ፒን ይጠቀሙ"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ለተጨማሪ ደህንነት በምትኩ የይለፍ ቃል ይጠቀሙ"</string> diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml index 4991d62975f9..686891fc0049 100644 --- a/packages/SystemUI/res-keyguard/values-as/strings.xml +++ b/packages/SystemUI/res-keyguard/values-as/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"আপোনাৰ পিন দিয়ক"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"পিন দিয়ক"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"আপোনাৰ আৰ্হি দিয়ক"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"আৰ্হি আঁকক"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"আপোনাৰ পাছৱর্ড দিয়ক"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"পাছৱৰ্ড দিয়ক"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ব্যৱহাৰৰ অযোগ্য ছিম কাৰ্ড"</string> <string name="keyguard_charged" msgid="5478247181205188995">"চ্চার্জ কৰা হ’ল"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • বেতাঁৰৰ জৰিয়তে চাৰ্জ কৰি থকা হৈছে"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"এটা আসোঁৱাহৰ কাৰণে ই-ছিম অক্ষম কৰিব পৰা নাযায়।"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"এণ্টাৰ বুটাম"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"ভুল আৰ্হি"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ভুল আৰ্হি। পুনৰ চেষ্টা কৰক।"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"ভুল পাছৱৰ্ড"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"ভুল পাছৱৰ্ড। পুনৰ চেষ্টা কৰক।"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ভুল পিন"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"ভুল পিন। পুনৰ চেষ্টা কৰক।"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"অথবা ফিংগাৰপ্ৰিণ্টেৰে আনলক কৰক"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"অচিনাক্ত ফিংগাৰপ্ৰিণ্ট"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"মুখাৱয়ব চিনি পোৱা নাই"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"পুনৰ চেষ্টা কৰক অথবা পিন দিয়ক"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"পুনৰ চেষ্টা কৰক অথবা পাছৱৰ্ড দিয়ক"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"পুনৰ চেষ্টা কৰক অথবা আৰ্হি আঁকক"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"অত্যধিক প্ৰয়াসৰ পাছত পিন দিয়াৰ আৱশ্যক"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"অত্যধিক প্ৰয়াসৰ পাছত পাছৱৰ্ড দিয়াৰ আৱশ্যক"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"অত্যধিক প্ৰয়াসৰ পাছত আৰ্হি দিয়াৰ আৱশ্যক"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"পিন অথবা ফিংগাৰপ্ৰিণ্টেৰে আনলক কৰক"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"পাছৱৰ্ড অথবা ফিংগাৰপ্ৰিণ্টেৰে আনলক কৰক"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"আৰ্হি অথবা ফিংগাৰপ্ৰিণ্টেৰে আনলক কৰক"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"অধিক সুৰক্ষাৰ বাবে, কৰ্মস্থানৰ নীতিয়ে ডিভাইচটো লক কৰিছে"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"লকডাউনৰ পাছত পিন দিয়াৰ আৱশ্যক"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"লকডাউনৰ পাছত পাছৱৰ্ড দিয়াৰ আৱশ্যক"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"লকডাউনৰ পাছত আৰ্হি দিয়াৰ আৱশ্যক"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"নিষ্ক্ৰিয় হৈ থকাৰ সময়ত আপডে’ট ইনষ্টল কৰা হ’ব"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"অতিৰিক্ত সুৰক্ষাৰ আৱশ্যক। কিছু সময় ধৰি আৰ্হি ব্যৱহাৰ কৰা হোৱা নাই।"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"অতিৰিক্ত সুৰক্ষাৰ আৱশ্যক। কিছু সময় ধৰি পাছৱৰ্ড ব্যৱহাৰ কৰা হোৱা নাই।"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"অতিৰিক্ত সুৰক্ষাৰ আৱশ্যক। কিছু সময় ধৰি আৰ্হি ব্যৱহাৰ কৰা হোৱা নাই।"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"অতিৰিক্ত সুৰক্ষাৰ আৱশ্যক। ডিভাইচটো কিছু সময় ধৰি আনলক কৰা হোৱা নাই।"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"মুখাৱয়বেৰে আনলক কৰিব নোৱাৰি। অতি বেছিসংখ্যক প্ৰয়াস।"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ফিংগাৰপ্ৰিণ্টেৰে আনলক কৰিব নোৱাৰি। অতি বেছিসংখ্যক প্ৰয়াস।"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"বিশ্বাসী এজেণ্ট উপলব্ধ নহয়"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ভুল পিন দি অতি বেছিসংখ্যক প্ৰয়াস কৰা হৈছে"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ভুল আৰ্হি দি অতি বেছিসংখ্যক প্ৰয়াস কৰা হৈছে"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ভুল পাছৱৰ্ড দি অতি বেছিসংখ্যক প্ৰয়াস কৰা হৈছে"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{১ ছেকেণ্ডত আকৌ চেষ্টা কৰক।}one{# ছেকেণ্ডৰ পাছত আকৌ চেষ্টা কৰক।}other{# ছেকেণ্ডৰ পাছত আকৌ চেষ্টা কৰক।}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"ছিমৰ পিন দিয়ক।"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\"ৰ ছিমৰ পিন দিয়ক।"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"ছিম PUKৰ জৰিয়তে আনলক কৰিব পৰা নগ\'ল!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ইনপুট পদ্ধতি সলনি কৰক"</string> <string name="airplane_mode" msgid="2528005343938497866">"এয়াৰপ্লে’ন ম’ড"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত আৰ্হিৰ আৱশ্যক"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত পিনৰ আৱশ্যক"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত পাছৱৰ্ডৰ আৱশ্যক"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে আৰ্হি ব্যৱহাৰ কৰক"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে পিন ব্যৱহাৰ কৰক"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে পাছৱৰ্ড ব্যৱহাৰ কৰক"</string> diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml index 6861f6a801ef..6eb36bd64b66 100644 --- a/packages/SystemUI/res-keyguard/values-az/strings.xml +++ b/packages/SystemUI/res-keyguard/values-az/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"PIN kodu daxil edin"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN daxil edin"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Modeli daxil edin"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Model çəkin"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Şifrənizi daxil edin"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Parol daxil edin"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Yanlış Kart."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Enerji yığılıb"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Simsiz şəkildə batareya yığır"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM xəta səbəbi ilə deaktiv edilmədi."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Daxil edin"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Yanlış model"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Səhv model. Yenə sınayın."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Yanlış parol"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Səhv parol. Yenə sınayın."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Yanlış PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Səhv PIN. Yenə sınayın."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Yaxud barmaq izi ilə kiliddən çıxarın"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Barmaq izi tanınmır"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Üz tanınmır"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Təkrar sınayın və ya PIN daxil edin"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Təkrar sınayın və ya parol daxil edin"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Təkrar sınayın və ya model çəkin"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Çoxlu cəhddən sonra PIN tələb edilir"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Çoxlu cəhddən sonra parol tələb edilir"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Çoxlu cəhddən sonra model tələb edilir"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN/barmaq izi ilə açın"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Parol/barmaq izi ilə açın"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Model/barmaq izi ilə açın"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Qoruma üçün cihaz iş siyasətinə uyğun kilidləndi"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Kilidləmədən sonra PIN tələb edilir"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Kilidləmədən sonra parol tələb edilir"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Kilidləmədən sonra model tələb edilir"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Güncəllənmə qeyri-işlək saatlarda quraşdırılacaq"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Qoruma lazımdır. PIN bir müddət işlənməyib."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Qoruma lazımdır. Parol bir müddət işlənməyib."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Qoruma lazımdır. Model bir müddət işlənməyib."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Qoruma lazımdır. Cihaz bir müddət açılmayıb."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Üz ilə açmaq olmur. Çox cəhd edilib."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Barmaq izi ilə açmaq olmur. Çox cəhd edilib."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"İnam agenti əlçatan deyil"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Səhv PIN ilə çox cəhd edildi"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Səhv model ilə çox cəhd edildi"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Səhv parol ilə çox cəhd edildi"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# saniyə sonra yenidən cəhd edin.}other{# saniyə sonra yenidən cəhd edin.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN\'ni daxil edin."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" üçün SIM PIN\'ni daxil edin."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK əməliyyatı alınmadı!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Daxiletmə metoduna keçin"</string> <string name="airplane_mode" msgid="2528005343938497866">"Təyyarə rejimi"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Cihaz təkrar başladıldıqdan sonra model tələb edilir"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Cihaz təkrar başladıldıqdan sonra PIN tələb edilir"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Cihaz təkrar başladıldıqdan sonra parol tələb edilir"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Əlavə təhlükəsizlik üçün modeldən istifadə edin"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Əlavə təhlükəsizlik üçün PIN istifadə edin"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Əlavə təhlükəsizlik üçün paroldan istifadə edin"</string> diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml index 1b938032d139..6e2dd24c3068 100644 --- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Unesite PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Unesite PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Unesite šablon"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Nacrtajte šablon"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Unesite lozinku"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Unesite lozinku"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Nevažeća kartica."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Napunjena je"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bežično punjenje"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM ne može da se onemogući zbog greške."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Pogrešan šablon"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Pogrešan šablon. Probajte ponovo."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Pogrešna lozinka"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Pogrešna lozinka. Probajte ponovo."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Pogrešan PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Pogrešan PIN. Probajte ponovo."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ili otključajte otiskom prsta"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Otisak prsta neprepoznat"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Lice nije prepoznato"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Probajte ponovo ili unesite PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Probajte ponovo ili unesite lozinku"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Probajte ponovo ili nacrtajte šablon"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN je obavezan posle previše pokušaja"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Lozinka je obavezna posle previše pokušaja"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Šablon je obavezan posle previše pokušaja"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Otključajte PIN-om ili otiskom prsta"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Otključajte lozinkom ili otiskom prsta"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Otključajte šablonom ili otiskom prsta"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Radi bezbednosti smernice za posao su zaključ. uređaj"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN je obavezan posle zaključavanja"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Lozinka je obavezna posle zaključavanja"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Šablon je obavezan posle zaključavanja"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Ažuriranje se instalira tokom neaktivnosti"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Potrebna je dodatna zaštita. PIN dugo nije korišćen."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Potrebna je dodatna zaštita. Lozinka dugo nije korišćena."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Potrebna je dodatna zaštita. Šablon dugo nije korišćen."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Potrebna je dodatna zaštita. Uređaj dugo nije otključan."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Otključavanje licem nije uspelo. Previše pokušaja."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Otključavanje otiskom nije uspelo. Previše pokušaja."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Pouzdani agent je nedostupan"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Previše pokušaja sa netačnim PIN-om"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Previše pokušaja sa netačnim šablonom"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Previše pokušaja sa netačnom lozinkom"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Probajte ponovo za # sekundu.}one{Probajte ponovo za # sekundu.}few{Probajte ponovo za # sekunde.}other{Probajte ponovo za # sekundi.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Unesite PIN za SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Unesite PIN za SIM „<xliff:g id="CARRIER">%1$s</xliff:g>“."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Radnja sa PUK kodom za SIM nije uspela!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Promeni metod unosa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Režim rada u avionu"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Šablon je obavezan posle restarta uređaja"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN je obavezan posle restarta uređaja"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Lozinka je obavezna posle restarta uređaja"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatnu bezbednost koristite šablon"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatnu bezbednost koristite PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatnu bezbednost koristite lozinku"</string> diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml index 98d28632da8c..4781c3aa2068 100644 --- a/packages/SystemUI/res-keyguard/values-be/strings.xml +++ b/packages/SystemUI/res-keyguard/values-be/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Увядзіце PIN-код"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Увядзіце PIN-код"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Увядзіце ўзор разблакіроўкі"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Увядзіце ўзор"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Увядзіце пароль"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Увядзіце пароль"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Несапраўдная картка."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Зараджаны"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе бесправадная зарадка"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Немагчыма адключыць eSIM-карту з-за памылкі."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Увесці"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Няправільны ўзор разблакіроўкі"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Памылка. Паўтарыце спробу."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Няправільны пароль"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Памылка. Паўтарыце спробу."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Няправільны PIN-код"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Памылка. Паўтарыце спробу."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Або разблакіруйце адбіткам пальца"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Адбітак пальца не распазнаны"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Твар не распазнаны"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Паўтарыце спробу або ўвядзіце PIN-код"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Паўтарыце спробу або ўвядзіце пароль"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Паўтарыце спробу або ўвядзіце ўзор разблакіроўкі"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Занадта шмат няўдалых спроб. Увядзіце PIN-код"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Занадта шмат няўдалых спроб. Увядзіце пароль"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Занадта шмат спроб. Увядзіце ўзор разблакіроўкі"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Разблакіруйце PIN-кодам або адбіткам пальца"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Разблакіруйце паролем або адбіткам пальца"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Разблакіруйце ўзорам або адбіткам пальца"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Прылада заблакіравана згодна з палітыкай арганізацыі"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Пасля блакіроўкі неабходна ўвесці PIN-код"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Пасля блакіроўкі неабходна ўвесці пароль"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Пасля блакіроўкі неабходна ўвесці ўзор разблакіроўкі"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Абнаўленне ўсталюецца, калі прылада будзе неактыўная"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Патрабуецца дадатковая праверка. Даўно не выкарыстоўваўся PIN-код."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Патрабуецца дадатковая праверка. Даўно не выкарыстоўваўся пароль."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Патрабуецца дадатковая праверка. Даўно не выкарыстоўваўся ўзор разблакіроўкі."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Патрабуецца дадатковая праверка. Прылада даўно заблакіравана."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Нельга разблакіраваць тварам. Занадта шмат спроб."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Нельга разблакіраваць пальцам. Занадта шмат спроб."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Даверчы агент недаступны"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Занадта шмат спроб увесці няправільны PIN-код"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Занадта шмат спроб увесці няправільны ўзор"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Занадта шмат спроб увесці няправільны пароль"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Паўтарыце спробу праз # секунду.}one{Паўтарыце спробу праз # секунду.}few{Паўтарыце спробу праз # секунды.}many{Паўтарыце спробу праз # секунд.}other{Паўтарыце спробу праз # секунды.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Увядзіце PIN-код SIM-карты."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Увядзіце PIN-код SIM-карты для \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Разблакіраваць SIM-карту PUK-кодам не атрымалася!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Пераключэнне рэжыму ўводу"</string> <string name="airplane_mode" msgid="2528005343938497866">"Рэжым палёту"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Пасля перазапуску прылады неабходна ўвесці ўзор разблакіроўкі"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Пасля перазапуску прылады неабходна ўвесці PIN-код"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Пасля перазапуску прылады неабходна ўвесці пароль"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"У мэтах дадатковай бяспекі скарыстайце ўзор разблакіроўкі"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"У мэтах дадатковай бяспекі скарыстайце PIN-код"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"У мэтах дадатковай бяспекі скарыстайце пароль"</string> diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml index 7a2f5e98c0e0..483a18352b0f 100644 --- a/packages/SystemUI/res-keyguard/values-bg/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Въведете ПИН кода си"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Въведете ПИН кода"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Въведете фигурата си"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Начертайте фигурата"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Въведете паролата си"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Въведете паролата"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Картата е невалидна."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Заредена"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се безжично"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Електронната SIM карта не може да бъде деактивирана поради грешка."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"„Enter“"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Грешна фигура"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Грешна фигура. Нов опит."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Грешна парола"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Грешна парола. Нов опит."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Грешен ПИН код"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Грешен ПИН. Опитайте пак."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Или отключете с отпечатък"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Отпечатъкът не е разпознат"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Лицето не е разпознато"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Опитайте отново или въведете ПИН кода"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Опитайте отново или въведете паролата"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Опитайте отново или начертайте фигурата"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"След твърде много опити се изисква ПИН код"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"След твърде много опити се изисква парола"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"След твърде много опити се изисква фигура"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Отключете с ПИН/отпечатък"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Отключ. с парола/отпечатък"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Отключ. с фигура/отпечатък"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Устройството бе заключено от служебните правила"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"След заключването се изисква ПИН код"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"След заключването се изисква парола"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"След заключването се изисква фигура"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Актуализацията ще се инсталира при неактивност"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Изисква се допъл. защита. ПИН кодът не е ползван скоро."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Изисква се допъл. защита. Паролата не е ползвана скоро."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Изисква се допъл. защита. Фигурата не е ползвана скоро."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Изисква се допъл. защита. У-вото не е отключвано скоро."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Не може да се отключи с лице. Твърде много опити."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Не може да се откл. с отпечатък. Твърде много опити."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Функцията за надежден агент не е налице"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Твърде много опити с грешен ПИН код"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Твърде много опити с грешна фигура"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Твърде много опити с грешна парола"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Опитайте отново след # секунда.}other{Опитайте отново след # секунди.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Въведете ПИН кода за SIM картата."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Въведете ПИН кода на SIM картата за „<xliff:g id="CARRIER">%1$s</xliff:g>“."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Операцията с PUK кода за SIM картата не бе успешна!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Превключване на метода на въвеждане"</string> <string name="airplane_mode" msgid="2528005343938497866">"Самолет. режим"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"След рестартирането на у-вото се изисква фигура"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"След рестартирането на у-вото се изисква ПИН код"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"След рестартирането на у-вото се изисква парола"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"За допълнителна сигурност използвайте фигура вместо това"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"За допълнителна сигурност използвайте ПИН код вместо това"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"За допълнителна сигурност използвайте парола вместо това"</string> diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml index 1d9bc2d8eb0a..4dcceab49189 100644 --- a/packages/SystemUI/res-keyguard/values-bn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"পিন লিখুন"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"পিন লিখুন"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"প্যাটার্ন আঁকুন"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"প্যাটার্ন দিন"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"পাসওয়ার্ড লিখুন"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"পাসওয়ার্ড লিখুন"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ভুল কার্ড।"</string> <string name="keyguard_charged" msgid="5478247181205188995">"চার্জ হয়েছে"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ওয়্যারলেস পদ্ধতিতে চার্জ হচ্ছে"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"একটি সমস্যার কারণে ই-সিমটি বন্ধ করা যাচ্ছে না।"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"এন্টার"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"ভুল প্যাটার্ন"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ভুল প্যাটার্ন। আবার চেষ্টা করুন।"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"ভুল পাসওয়ার্ড"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"ভুল পাসওয়ার্ড। আবার চেষ্টা করুন।"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ভুল পিন"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"ভুল পিন, আবার চেষ্টা করুন।"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"বা ফিঙ্গারপ্রিন্টের সাহায্যে আনলক করুন"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ফিঙ্গারপ্রিন্ট শনাক্ত হয়নি"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ফেস চেনা যায়নি"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"আবার চেষ্টা করুন বা পিন লিখুন"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"আবার চেষ্টা করুন বা পাসওয়ার্ড লিখুন"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"আবার চেষ্টা করুন বা প্যাটার্ন দিন"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"অনেক বেশিবার চেষ্টা করার পরে পিন দিতে হবে"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"অনেক বেশিবার চেষ্টা করার পরে পাসওয়ার্ড দিতে হবে"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"অনেক বেশিবার চেষ্টা করার পরে প্যাটার্ন দিতে হবে"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"পিন বা ফিঙ্গারপ্রিন্টের সাহায্যে আনলক করুন"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"পাসওয়ার্ড বা ফিঙ্গারপ্রিন্টের সাহায্যে আনলক করুন"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"প্যাটার্ন বা ফিঙ্গারপ্রিন্টের সাহায্যে আনলক করুন"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"অতিরিক্ত সুরক্ষার জন্য, কাজ সংক্রান্ত নীতি অনুসারে ডিভাইস লক করে দেওয়া হয়েছে"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"লকডাউন হওয়ার পরে পিন দিতে হবে"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"লকডাউন হওয়ার পরে পাসওয়ার্ড দিতে হবে"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"লকডাউন হওয়ার পরে প্যাটার্ন দিতে হবে"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"ডিভাইস অ্যাক্টিভ না থাকাকালীন আপডেট ইনস্টল হবে"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"অতিরিক্ত সুরক্ষা দরকার। পিন কিছুক্ষণ ব্যবহার করা হয়নি।"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"অতিরিক্ত সুরক্ষা দরকার। পাসওয়ার্ড কিছুক্ষণ ব্যবহার করা হয়নি।"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"অতিরিক্ত সুরক্ষা দরকার। প্যাটার্ন কিছুক্ষণ ব্যবহার করা হয়নি।"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"অতিরিক্ত সুরক্ষা দরকার। ডিভাইস কিছুক্ষণ আনলক ছিল না।"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"ফেস দিয়ে আনলক করা যাচ্ছে না। অনেকবার চেষ্টা করেছেন।"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ফিঙ্গারপ্রিন্ট দিয়ে আনলক করা যাচ্ছে না। অনেকবার চেষ্টা করেছেন।"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"\'বিশ্বস্ত এজেন্ট\' ফিচার উপলভ্য নেই"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ভুল পিন দিয়ে অনেক বেশিবার চেষ্টা করা হয়েছে"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ভুল প্যাটার্ন দিয়ে অনেক বেশিবার চেষ্টা করা হয়েছে"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ভুল পাসওয়ার্ড দিয়ে অনেক বেশিবার চেষ্টা করা হয়েছে"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# সেকেন্ডের মধ্যে আবার চেষ্টা করুন।}one{# সেকেন্ডের মধ্যে আবার চেষ্টা করুন।}other{# সেকেন্ডের মধ্যে আবার চেষ্টা করুন।}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"সিমের পিন লিখুন।"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" এর জন্য সিমের পিন লিখুন।"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"সিম PUK দিয়ে আনলক করা যায়নি!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ইনপুট পদ্ধতি পরিবর্তন করুন"</string> <string name="airplane_mode" msgid="2528005343938497866">"বিমান মোড"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ডিভাইস রিস্টার্ট হওয়ার পরে প্যাটার্ন দিতে হবে"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ডিভাইস রিস্টার্ট হওয়ার পরে পিন দিতে হবে"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ডিভাইস রিস্টার্ট হওয়ার পরে পাসওয়ার্ড দিতে হবে"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"অতিরিক্ত সুরক্ষার জন্য, এর বদলে প্যাটার্ন ব্যবহার করুন"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"অতিরিক্ত সুরক্ষার জন্য, এর বদলে পিন ব্যবহার করুন"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"অতিরিক্ত সুরক্ষার জন্য, এর বদলে পাসওয়ার্ড ব্যবহার করুন"</string> diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml index 6ae7b18a675c..3770c7d5fb27 100644 --- a/packages/SystemUI/res-keyguard/values-bs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Unesite svoj PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Unesite PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Unesite uzorak"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Unesite uzorak"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Unesite lozinku"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Unesite lozinku"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Nevažeća kartica."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Napunjeno"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bežično punjenje"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM nije moguće onemogućiti zbog greške."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Pogrešan uzorak"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Pogrešan uzorak. Pokušajte ponovo."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Pogrešna lozinka"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Pogrešna lozinka Pokušajte ponovo."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Pogrešan PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Pogrešan PIN. Pokušajte ponovo."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ili otključajte otiskom prsta"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Otisak nije prepoznat"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Lice nije prepoznato"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Pokušajte ponovo ili unesite PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Pokušajte ponovo ili unesite lozinku"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Pokušajte ponovo ili unesite uzorak"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN je potreban nakon previše pokušaja"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Lozinka je potrebna nakon previše pokušaja"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Uzorak je potreban nakon previše pokušaja"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Otključajte PIN-om ili otiskom"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Otključajte lozinkom ili otiskom"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Otključajte uzorkom ili otiskom"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Radi sigurnosti uređaj je zaključan radnim pravilima"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN je potreban nakon zaključavanja"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Lozinka je potrebna nakon zaključavanja"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Uzorak je potreban nakon zaključavanja"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Ažuriranje će se instalirati u periodu neaktivnosti"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Potrebna je dodatna zaštita. PIN dugo nije unošen."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Potrebna je dodatna zaštita. Lozinka dugo nije unošena."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Potrebna je dodatna zaštita. Uzorak dugo nije unošen."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Potrebna je dodatna zaštita. Uređaj dugo nije otključavan."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nije moguće otključati licem. Previše pokušaja."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nije moguće otključati otiskom. Previše pokušaja."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Pouzdani agent nije dostupan"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Previše pokušaja s pogrešnim PIN-om"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Previše pokušaja s pogrešnim uzorkom"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Previše pokušaja s pogrešnom lozinkom"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Pokušajte ponovo za # s.}one{Pokušajte ponovo za # s.}few{Pokušajte ponovo za # s.}other{Pokušajte ponovo za # s.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Unesite PIN SIM kartice."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Unesite PIN SIM kartice operatera \"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Korištenje PUK-a za SIM nije uspjelo!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Promjena načina unosa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Način rada u avionu"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Uzorak je potreban nakon ponovnog pokretanja uređaja"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN je potreban nakon ponovnog pokretanja uređaja"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Lozinka je potrebna nakon pokretanja uređaja"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Radi dodatne zaštite, umjesto toga koristite uzorak"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Radi dodatne zaštite, umjesto toga koristite PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Radi dodatne zašitite, umjesto toga koristite lozinku"</string> diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml index eefd49148bfe..89c3635fcec7 100644 --- a/packages/SystemUI/res-keyguard/values-ca/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Introdueix el PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Introdueix el PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Introdueix el patró"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Dibuixa el patró"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introdueix la contrasenya"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Introdueix la contrasenya"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"La targeta no és vàlida."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Bateria carregada"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant sense fil"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"S\'ha produït un error i no es pot desactivar l\'eSIM."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Retorn"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Patró incorrecte"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Patró incorrecte. Torna-hi."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Contrasenya incorrecta"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Contrasenya incorrecta. Torna-hi."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"El PIN no és correcte"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN incorrecte. Torna-hi."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"O desbloqueja amb l\'empremta digital"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"L\'empremta no es reconeix"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"No s\'ha reconegut la cara"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Torna-ho a provar o introdueix el PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Torna-ho a provar o introdueix la contrasenya"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Torna-ho a provar o dibuixa el patró"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Es requereix el PIN després de massa intents"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Es requereix la contrasenya després de massa intents"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Es requereix el patró després de massa intents"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desbloqueja amb PIN o empremta"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Desbloqueja amb contrasenya o empremta"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desbloqueja amb patró o empremta"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Per política de treball, s\'ha bloquejat per seguretat"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Cal el PIN després del bloqueig de seguretat"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Cal la contrasenya després del bloqueig de seguretat"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Cal el patró després del bloqueig de seguretat"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"S\'actualitzarà durant les hores d\'inactivitat"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Cal més seguretat. Fa temps que no utilitzes el PIN."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Cal més seguretat. Contrasenya no utilitzada fa temps."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Cal més seguretat. Fa temps que no utilitzes el patró."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Cal més seguretat. Dispositiu no desbloquejat fa temps."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"No pots desbloquejar amb la cara. Massa intents."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"No pots desbloquejar amb l\'empremta. Massa intents."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"L\'agent de confiança no està disponible"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Massa intents amb un PIN incorrecte"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Massa intents amb un patró incorrecte"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Massa intents amb una contrasenya incorrecta"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Torna-ho a provar d\'aquí a # segon.}many{Torna-ho a provar d\'aquí a # segons.}other{Torna-ho a provar d\'aquí a # segons.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introdueix el PIN de la SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introdueix el PIN de la SIM de: <xliff:g id="CARRIER">%1$s</xliff:g>."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"No s\'ha pogut desbloquejar la SIM amb el codi PUK."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Canvia el mètode d\'introducció"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mode d\'avió"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Cal el patró després de reiniciar el dispositiu"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Cal el PIN després de reiniciar el dispositiu"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Cal la contrasenya després de reiniciar el dispositiu"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Per a més seguretat, utilitza el patró"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Per a més seguretat, utilitza el PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Per a més seguretat, utilitza la contrasenya"</string> diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml index c3de04d9d968..22f46a0022ab 100644 --- a/packages/SystemUI/res-keyguard/values-cs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Zadejte PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Zadejte kód PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Zadejte gesto"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Nakreslete gesto"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Zadejte heslo"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Zadejte heslo"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Neplatná karta."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Nabito"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bezdrátové nabíjení"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM kartu kvůli chybě nelze deaktivovat."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Nesprávné gesto"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Nesprávné gesto. Zkuste to znovu."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Špatné heslo"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Nesprávné heslo. Zkuste to znovu."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Nesprávný kód PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Nesprávný PIN. Zkuste to znovu."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Nebo odemkněte otiskem prstu"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Otisk prstu nebyl rozpoznán"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Obličej nebyl rozpoznán"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Zkuste to znovu nebo zadejte PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Zkuste to znovu nebo zadejte heslo"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Zkuste to znovu nebo nakreslete gesto"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Po příliš mnoha pokusech je vyžadován PIN"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Po příliš mnoha pokusech je vyžadováno heslo"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Po příliš mnoha pokusech je vyžadováno gesto"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Zadejte PIN nebo otisk"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Zadejte heslo nebo otisk"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Zadejte gesto nebo otisk"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Kvůli zabezpečení se zařízení zamkne prac. zásadami"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po uzamčení je třeba zadat PIN"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po uzamčení je třeba zadat heslo"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po uzamčení je třeba zadat gesto"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Aktualizace se nainstaluje v období neaktivity"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Je potřeba další krok. PIN dlouho nepoužit."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Je potřeba další krok. Heslo dlouho nepoužito."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Je potřeba další krok. Gesto dlouho nepoužito."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Je potřeba další krok. Zařízení dlouho odemknuto."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nelze odemknout obličejem. Příliš mnoho pokusů."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nelze odemknout otiskem prstu. Příliš mnoho pokusů."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Agent důvěry není k dispozici"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Příliš mnoho pokusů s nesprávným kódem PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Příliš mnoho pokusů s nesprávným gestem"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Příliš mnoho pokusů s nesprávným heslem"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Zkuste to znovu za # sekundu.}few{Zkuste to znovu za # sekundy.}many{Zkuste to znovu za # sekundy.}other{Zkuste to znovu za # sekund.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Zadejte kód PIN SIM karty."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Zadejte kód PIN SIM karty <xliff:g id="CARRIER">%1$s</xliff:g>."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operace pomocí kódu PUK SIM karty se nezdařila."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Přepnout metodu zadávání"</string> <string name="airplane_mode" msgid="2528005343938497866">"Režim Letadlo"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Po restartu zařízení je vyžadováno gesto"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Po restartu zařízení je vyžadován PIN"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Po restartu zařízení je vyžadováno heslo"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Z bezpečnostních důvodů raději použijte gesto"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Z bezpečnostních důvodů raději použijte PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Z bezpečnostních důvodů raději použijte heslo"</string> diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml index a453bb515646..5f3c2e788ec9 100644 --- a/packages/SystemUI/res-keyguard/values-da/strings.xml +++ b/packages/SystemUI/res-keyguard/values-da/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Angiv din pinkode"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Angiv pinkode"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Angiv dit mønster"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Tegn mønster"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Angiv din adgangskode"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Angiv adgangskode"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ugyldigt kort."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Opladet"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Trådløs opladning"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM kan ikke deaktiveres på grund af en fejl."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Forkert mønster"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Forkert mønster. Prøv igen."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Forkert adgangskode"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Forkert adgangskode. Prøv igen."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Forkert pinkode"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Forkert pinkode. Prøv igen."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Eller lås op med fingeraftryk"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Fingeraftryk blev ikke genkendt"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Ansigt blev ikke genkendt"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Prøv igen, eller angiv pinkode"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Prøv igen, eller angiv adgangskode"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Prøv igen, eller tegn mønster"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Pinkode er påkrævet efter for mange forsøg"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Adgangskode er påkrævet efter for mange forsøg"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Mønster er påkrævet efter for mange forsøg"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Lås op med pinkode eller fingeraftryk"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Lås op med adgangskode eller fingeraftryk"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Lås op med mønster eller fingeraftryk"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Enhed låst af arbejdspolitik af hensyn til sikkerhed"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pinkode er påkrævet efter brug af ekstralås"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Adgangskode er påkrævet efter brug af ekstralås"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mønster er påkrævet efter brug af ekstralås"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Opdateringen installeres under inaktivitet"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Mere sikkerhed er påkrævet. Pinkoden er ikke blevet brugt i et stykke tid."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Mere sikkerhed er påkrævet. Adgangskoden er ikke blevet brugt i et stykke tid."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Mere sikkerhed er påkrævet. Mønsteret er ikke blevet brugt i et stykke tid."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Mere sikkerhed er påkrævet. Enheden er ikke blevet låst op i et stykke tid."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Oplåsning med ansigt mislykkedes. For mange forsøg."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Oplåsning med finger mislykkedes. For mange forsøg."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Trust agent er ikke tilgængelig"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"For mange forsøg med forkert pinkode"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"For mange forsøg med forkert mønster"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"For mange forsøg med forkert adgangskode"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Prøv igen om # sekund.}one{Prøv igen om # sekund.}other{Prøv igen om # sekunder.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Angiv pinkoden til SIM-kortet."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Angiv pinkoden til SIM-kortet fra \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"PUK-koden til SIM-kortet blev afvist"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Skift indtastningsmetode"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flytilstand"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Mønster er påkrævet efter genstart af enheden"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Pinkode er påkrævet efter genstart af enheden"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Adgangskode er påkrævet efter genstart af enheden"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Øg sikkerheden ved at bruge dit oplåsningsmønter i stedet"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Øg sikkerheden ved at bruge din pinkode i stedet"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Øg sikkerheden ved at bruge din adgangskode i stedet"</string> diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml index 069cb507b50f..23e566816a41 100644 --- a/packages/SystemUI/res-keyguard/values-el/strings.xml +++ b/packages/SystemUI/res-keyguard/values-el/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Εισαγάγετε τον αριθμό PIN σας"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Εισαγωγή PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Εισαγάγετε το μοτίβο σας"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Σχεδίαση μοτίβου"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Εισαγάγετε κωδικό πρόσβασης"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Εισαγωγή κωδικού πρόσβασης"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Μη έγκυρη κάρτα."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Φορτίστηκε"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ασύρματη φόρτιση"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Δεν είναι δυνατή η απενεργοποίηση της eSIM, εξαιτίας κάποιου σφάλματος."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Λανθασμένο μοτίβο"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Λάθος μοτίβο. Δοκ. ξανά."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Λανθασμένος κωδικός πρόσβασης"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Λάθ. κωδ. πρόσ. Δοκ. ξανά."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Λανθασμένο PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Λάθος PIN. Δοκιμάστε ξανά."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Εναλλακτικά, ξεκλειδώστε με δακτυλικό αποτύπωμα"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Δεν αναγν. το δακτ. αποτ."</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Το πρόσωπο δεν αναγνωρίστ."</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Δοκιμάστε ξανά ή εισαγάγετε το PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Δοκιμάστε ξανά ή εισαγάγετε τον κωδικό πρόσβασης"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Δοκιμάστε ξανά ή σχεδιάστε το μοτίβο"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Απαιτείται PIN μετά από πολλές προσπάθειες"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Απαιτείται κωδ. πρόσβ. μετά από πολλές προσπάθειες"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Απαιτείται μοτίβο μετά από πολλές προσπάθειες"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Ξεκλ. με PIN ή δακτ. αποτ."</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Ξεκλ. με κωδ. πρόσβ. ή δακτ. αποτ."</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Ξεκλ. με μοτίβο ή δακτ. αποτ."</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Για πρόσθ. ασφάλ. η συσκ. κλειδ. από πολιτ. εργασίας"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Απαιτείται PIN μετά από κλείδωμα"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Απαιτείται κωδικός πρόσβασης μετά από κλείδωμα"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Απαιτείται μοτίβο μετά από κλείδωμα"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Η ενημέρωση θα εγκατασταθεί κατά τις ανενεργές ώρες"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Απαιτ. πρόσθ. ασφάλ. Το PIN έχει καιρό να χρησιμοπ."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Απαιτ. πρόσθ. ασφάλ. Ο κωδ. πρ. έχει καιρό να χρησ."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Απαιτ. πρόσθ. ασφάλ. Το μοτίβο έχει καιρό να χρησιμ."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Απαιτ. πρόσθ. ασφάλ. Η συσκ. έχει καιρό να ξεκλειδ."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Αδυναμία ξεκλ. με πρόσωπο Υπερβ. πολλές προσπάθειες."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Αδυν. ξεκ. με δακ. αποτ. Υπερβ. πολλές προσπάθειες."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Ο παράγοντας εμπιστοσύνης δεν είναι διαθέσιμος"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Υπερβολικά πολλές προσπάθειες με εσφαλμένο PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Υπερβολικά πολλές προσπάθειες με εσφαλμένο μοτίβο"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Υπερβολικά πολλές προσπάθειες με εσφαλ. κωδ. πρόσβ."</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Δοκιμάστε ξανά σε # δευτερόλεπτο.}other{Δοκιμάστε ξανά σε # δευτερόλεπτα.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Εισαγωγή αριθμού PIN κάρτας SIM"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Εισαγάγετε τον αριθμό PIN της κάρτας SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Αποτυχία λειτουργίας κωδικού PUK κάρτας SIM!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Εναλλαγή μεθόδου εισαγωγής"</string> <string name="airplane_mode" msgid="2528005343938497866">"Λειτουργία πτήσης"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Απαιτείται μοτίβο μετά την επανεκκίνηση της συσκευής"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Απαιτείται PIN μετά την επανεκκίνηση της συσκευής"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Απαιτείται κωδ. πρόσβ. μετά την επανεκ. της συσκευής"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Για πρόσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά μοτίβο"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Για πρόσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Για πρόσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά κωδικό πρόσβασης"</string> diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml index 389f94fcbc69..10b82a4808c9 100644 --- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Enter your PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Enter PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Enter your pattern"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Draw pattern"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Enter your password"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Enter password"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Invalid card."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Charged"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging wirelessly"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"The eSIM can’t be disabled due to an error."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Wrong pattern"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Wrong pattern. Try again."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Wrong password"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Wrong password. Try again."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Wrong PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Wrong PIN. Try again."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Or unlock with fingerprint"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Fingerprint not recognised"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Face not recognised"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Try again or enter PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Try again or enter password"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Try again or draw pattern"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN is required after too many attempts"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Password is required after too many attempts"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Pattern is required after too many attempts"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Unlock with PIN or fingerprint"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Unlock with password or fingerprint"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Unlock with pattern or fingerprint"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"For added security, device was locked by work policy"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN is required after lockdown"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Password is required after lockdown"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pattern is required after lockdown"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Update will be installed during inactive hours"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Added security required. PIN not used for a while."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Added security required. Password not used for a while."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Added security required. Pattern not used for a while."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Added security required. Device hasn\'t been unlocked for a while."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Can\'t unlock with face. Too many attempts."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Can\'t unlock with fingerprint. Too many attempts."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Trust agent is unavailable"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Too many attempts with incorrect PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Too many attempts with incorrect pattern"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Too many attempts with incorrect password"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Try again in # second.}other{Try again in # seconds.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Enter SIM PIN."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Enter SIM PIN for \'<xliff:g id="CARRIER">%1$s</xliff:g>\'."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK operation failed!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Switch input method"</string> <string name="airplane_mode" msgid="2528005343938497866">"Aeroplane mode"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Pattern is required after the device restarts"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN is required after the device restarts"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Password is required after the device restarts"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string> diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml index 389f94fcbc69..10b82a4808c9 100644 --- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Enter your PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Enter PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Enter your pattern"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Draw pattern"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Enter your password"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Enter password"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Invalid card."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Charged"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging wirelessly"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"The eSIM can’t be disabled due to an error."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Wrong pattern"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Wrong pattern. Try again."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Wrong password"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Wrong password. Try again."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Wrong PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Wrong PIN. Try again."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Or unlock with fingerprint"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Fingerprint not recognised"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Face not recognised"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Try again or enter PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Try again or enter password"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Try again or draw pattern"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN is required after too many attempts"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Password is required after too many attempts"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Pattern is required after too many attempts"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Unlock with PIN or fingerprint"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Unlock with password or fingerprint"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Unlock with pattern or fingerprint"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"For added security, device was locked by work policy"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN is required after lockdown"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Password is required after lockdown"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pattern is required after lockdown"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Update will be installed during inactive hours"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Added security required. PIN not used for a while."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Added security required. Password not used for a while."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Added security required. Pattern not used for a while."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Added security required. Device hasn\'t been unlocked for a while."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Can\'t unlock with face. Too many attempts."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Can\'t unlock with fingerprint. Too many attempts."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Trust agent is unavailable"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Too many attempts with incorrect PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Too many attempts with incorrect pattern"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Too many attempts with incorrect password"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Try again in # second.}other{Try again in # seconds.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Enter SIM PIN."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Enter SIM PIN for \'<xliff:g id="CARRIER">%1$s</xliff:g>\'."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK operation failed!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Switch input method"</string> <string name="airplane_mode" msgid="2528005343938497866">"Aeroplane mode"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Pattern is required after the device restarts"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN is required after the device restarts"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Password is required after the device restarts"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string> diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml index 389f94fcbc69..10b82a4808c9 100644 --- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Enter your PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Enter PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Enter your pattern"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Draw pattern"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Enter your password"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Enter password"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Invalid card."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Charged"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging wirelessly"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"The eSIM can’t be disabled due to an error."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Wrong pattern"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Wrong pattern. Try again."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Wrong password"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Wrong password. Try again."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Wrong PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Wrong PIN. Try again."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Or unlock with fingerprint"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Fingerprint not recognised"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Face not recognised"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Try again or enter PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Try again or enter password"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Try again or draw pattern"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN is required after too many attempts"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Password is required after too many attempts"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Pattern is required after too many attempts"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Unlock with PIN or fingerprint"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Unlock with password or fingerprint"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Unlock with pattern or fingerprint"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"For added security, device was locked by work policy"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN is required after lockdown"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Password is required after lockdown"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pattern is required after lockdown"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Update will be installed during inactive hours"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Added security required. PIN not used for a while."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Added security required. Password not used for a while."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Added security required. Pattern not used for a while."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Added security required. Device hasn\'t been unlocked for a while."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Can\'t unlock with face. Too many attempts."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Can\'t unlock with fingerprint. Too many attempts."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Trust agent is unavailable"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Too many attempts with incorrect PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Too many attempts with incorrect pattern"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Too many attempts with incorrect password"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Try again in # second.}other{Try again in # seconds.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Enter SIM PIN."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Enter SIM PIN for \'<xliff:g id="CARRIER">%1$s</xliff:g>\'."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK operation failed!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Switch input method"</string> <string name="airplane_mode" msgid="2528005343938497866">"Aeroplane mode"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Pattern is required after the device restarts"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN is required after the device restarts"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Password is required after the device restarts"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string> diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml index df37e61264f0..be1c44f046fb 100644 --- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Ingresa tu PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Ingresar PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Ingresa tu patrón"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Dibujar patrón"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Ingresa tu contraseña"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Ingresar contraseña"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Tarjeta no válida"</string> <string name="keyguard_charged" msgid="5478247181205188995">"Cargada"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando de manera inalámbrica"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"No se puede inhabilitar la eSIM debido a un error."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Intro"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Patrón incorrecto"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Incorrecto. Reintenta."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Contraseña incorrecta"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Incorrecto. Reintenta."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorrecto"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN incorrecto. Reintenta."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"O desbloquear con huella dactilar"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"No se reconoce la huella"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"No se reconoció el rostro"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Vuelve a intentarlo o ingresa el PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Vuelve a intentarlo o ingresa la contraseña"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Vuelve a intentarlo o dibuja el patrón"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Se requiere PIN luego de demasiados intentos"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Se requiere contraseña luego de demasiados intentos"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Se requiere patrón luego de demasiados intentos"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desbloq. PIN/huella"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Desbloq. contraseña/huella"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desbloq. patrón/huella"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Dispositivo bloqueado con la política del trabajo"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Se requiere el PIN después del bloqueo"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Se requiere la contraseña después del bloqueo"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Se requiere el patrón después del bloqueo"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"La actualización se instala en horas de inactividad"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Reforzar seguridad. PIN sin uso mucho tiempo."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Reforzar seguridad. Contraseña sin uso mucho tiempo."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Reforzar seguridad. Patrón sin uso mucho tiempo."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Reforzar seguridad. Mucho tiempo sin desbloquear."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Error de desbloqueo con rostro. Demasiados intentos."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Error de desbloqueo con huella. Demasiados intentos."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"El agente de confianza no está disponible"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Demasiados intentos con PIN incorrecto"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Demasiados intentos con patrón incorrecto"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Demasiados intentos con contraseña incorrecta"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}many{Vuelve a intentarlo en # segundos.}other{Vuelve a intentarlo en # segundos.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Ingresa el PIN de la tarjeta SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Ingresa el PIN de la tarjeta SIM de \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Se produjo un error al desbloquear la tarjeta SIM con el PUK."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambiar método de entrada"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo de avión"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Se requiere patrón tras reiniciar dispositivo"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Se requiere PIN tras reiniciar dispositivo"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Se requiere contraseña tras reiniciar dispositivo"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para seguridad adicional, usa un patrón"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para seguridad adicional, usa un PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para seguridad adicional, usa una contraseña"</string> diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml index 49a2b1f1af81..aa09cf96fb10 100644 --- a/packages/SystemUI/res-keyguard/values-es/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Introduce tu PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Introduce el PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Introduce tu patrón"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Dibuja el patrón"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduce tu contraseña"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Escribe la contraseña"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Tarjeta no válida."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Cargado"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando sin cables"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"No se puede mostrar la tarjeta eSIM debido a un error."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Intro"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Patrón incorrecto"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Patrón incorrecto. Inténtalo de nuevo."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Contraseña incorrecta"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Contraseña incorrecta. Inténtalo de nuevo."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorrecto"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN incorrecto. Inténtalo de nuevo."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"O desbloquea con la huella digital"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Huella digital no reconocida"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Cara no reconocida"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Vuelve a intentarlo o introduce el PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Vuelve a intentarlo o escribe la contraseña"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Vuelve a intentarlo o dibuja el patrón"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Demasiados intentos, se necesita el PIN"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Demasiados intentos, se necesita la contraseña"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Demasiados intentos, se necesita el patrón"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desbloquea con PIN o huella digital"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Desbloquea con contraseña o huella digital"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desbloquea con patrón o huella digital"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Por política del trabajo, se ha bloqueado el dispositivo para mayor seguridad"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Se necesita el PIN después del bloqueo"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Se necesita la contraseña después del bloqueo"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Se necesita el patrón después del bloqueo"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"La actualización se instalará en horas de inactividad"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Se debe reforzar la seguridad. PIN no usado en mucho tiempo."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Se debe reforzar la seguridad. Contraseña no usada en mucho tiempo."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Se debe reforzar la seguridad. Patrón no usado en mucho tiempo."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Se debe reforzar la seguridad. Dispositivo no desbloqueado en mucho tiempo."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Desbloqueo facial no disponible. Demasiados intentos."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Desbloqueo con huella digital no disponible. Demasiados intentos."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Agente de confianza no disponible"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Demasiados intentos con un PIN incorrecto"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Demasiados intentos con un patrón incorrecto"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Demasiados intentos con una contraseña incorrecta"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}many{Vuelve a intentarlo en # segundos.}other{Vuelve a intentarlo en # segundos.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduce el PIN de la tarjeta SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduce el PIN de la tarjeta SIM de <xliff:g id="CARRIER">%1$s</xliff:g>."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"No se ha podido desbloquear la tarjeta SIM con el código PUK."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambiar método de introducción"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo Avión"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Se necesita el patrón tras el reinicio"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Se necesita el PIN tras el reinicio"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Se necesita la contraseña tras el reinicio"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para mayor seguridad, usa el patrón"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para mayor seguridad, usa el PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para mayor seguridad, usa la contraseña"</string> diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml index d260c1368ba3..d6c7f3f9e6c5 100644 --- a/packages/SystemUI/res-keyguard/values-et/strings.xml +++ b/packages/SystemUI/res-keyguard/values-et/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Sisestage PIN-kood"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Sisestage PIN-kood"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Sisestage muster"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Joonistage muster"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Sisestage parool"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Sisestage parool"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Kehtetu kaart."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Laetud"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Juhtmeta laadimine"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Vea tõttu ei saa eSIM-kaarte keelata."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Sisesta"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Vale muster"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Vale muster. Proovige uuesti."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Vale parool"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Vale parool. Proovige uuesti."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Vale PIN-kood"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Vale PIN-kood. Proovige uuesti."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Või avage sõrmejäljega"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Sõrmejälge ei tuvastatud"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Nägu ei saanud tuvastada"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Proovige uuesti või sisestage PIN-kood"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Proovige uuesti või sisestage parool"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Proovige uuesti või joonistage muster"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN-koodi nõutakse pärast liiga paljusid katseid"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Parool on nõutav pärast liiga paljusid katseid"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Muster on nõutav pärast liiga paljusid katseid"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Avage PIN-koodi või sõrmejäljega"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Avage parooli või sõrmejäljega"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Avage mustri või sõrmejäljega"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Turvalisuse suurendamiseks lukustati seade töökoha eeskirjadega"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pärast lukustamist on PIN-kood nõutav"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Pärast lukustamist on parool nõutav"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pärast lukustamist on muster nõutav"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Värskendus installitakse mitteaktiivsete tundide ajal"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Turvalisuse suurendamine on nõutav. PIN-koodi ei ole mõnda aega kasutatud."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Turvalisuse suurendamine on nõutav. Parooli ei ole mõnda aega kasutatud."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Turvalisuse suurendamine on nõutav. Mustrit ei ole mõnda aega kasutatud."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Turvalisuse suurendamine on nõutav. Seadet ei ole mõnda aega avatud."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Näoga ei saa avada. Liiga palju katseid."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Sõrmejäljega ei saa avada. Liiga palju katseid."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Usaldusväärne agent pole saadaval"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Liiga palju vale PIN-koodiga katseid"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Liiga palju vale mustriga katseid"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Liiga palju vale parooliga katseid"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Proovige uuesti # sekundi pärast.}other{Proovige uuesti # sekundi pärast.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Sisestage SIM-kaardi PIN-kood."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Sisestage operaatori „<xliff:g id="CARRIER">%1$s</xliff:g>” SIM-kaardi PIN-kood."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-kaardi PUK-koodi toiming ebaõnnestus."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Vaheta sisestusmeetodit"</string> <string name="airplane_mode" msgid="2528005343938497866">"Lennukirežiim"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Pärast seadme taaskäivitamist on muster nõutav"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Pärast seadme taaskäivitamist on PIN-kood nõutav"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Pärast seadme taaskäivitamist on parool nõutav"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Kasutage tugevama turvalisuse huvides hoopis mustrit"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Kasutage tugevama turvalisuse huvides hoopis PIN-koodi"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Kasutage tugevama turvalisuse huvides hoopis parooli"</string> diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml index 7786ae6003c8..be03ec47859a 100644 --- a/packages/SystemUI/res-keyguard/values-eu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Idatzi PINa"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Idatzi PINa"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Marraztu eredua"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Marraztu eredua"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Idatzi pasahitza"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Idatzi pasahitza"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Txartelak ez du balio."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Kargatuta"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hari gabe kargatzen"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Errore bat gertatu da eta ezin da desgaitu eSIM txartela."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Sartu"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Eredua ez da zuzena"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Eredua ez da zuzena. Saiatu berriro."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Pasahitza ez da zuzena"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Pasahitza ez da zuzena. Saiatu berriro."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN hori ez da zuzena"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PINa ez da zuzena. Saiatu berriro."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Bestela, desblokeatu hatz-marka bidez"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Ez da ezagutu hatz-marka"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Ez da ezagutu aurpegia"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Saiatu berriro edo idatzi PINa"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Saiatu berriro edo idatzi pasahitza"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Saiatu berriro edo marraztu eredua"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PINa behar da saiakera gehiegi egin ostean"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Pasahitza behar da saiakera gehiegi egin ostean"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Eredua behar da saiakera gehiegi egin ostean"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desblokeatu PIN edo hatz-marka bidez"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Desblokeatu pasahitz edo hatz-marka bidez"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desblokeatu eredu edo hatz-marka bidez"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Segurtasuna bermatzeko, laneko gidalerroek gailua blokeatu dute"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PINa behar da blokeoa desgaitu ostean"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Pasahitza behar da blokeoa desgaitu ostean"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Eredua behar da blokeoa desgaitu ostean"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Inaktibo egon ohi den tarte batean instalatuko da eguneratzea"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Segurtasuna areagotu behar da. PINa ez da erabili aldi batez."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Segurtasuna areagotu behar da. Pasahitza ez da erabili aldi batez."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Segurtasuna areagotu behar da. Eredua ez da erabili aldi batez."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Segurtasuna areagotu behar da. Gailua ez da desblokeatu aldi batez."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Ezin da desblokeatu aurpegi bidez. Saiakera gehiegi egin dira."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Ezin da desblokeatu hatz-marka bidez. Saiakera gehiegi egin dira."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Fidagarritasun-agentea ez dago erabilgarri"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Saiakera gehiegi egin dira okerreko PINarekin"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Saiakera gehiegi egin dira okerreko ereduarekin"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Saiakera gehiegi egin dira okerreko pasahitzarekin"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Saiatu berriro # segundo barru.}other{Saiatu berriro # segundo barru.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Idatzi SIMaren PINa."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Idatzi \"<xliff:g id="CARRIER">%1$s</xliff:g>\" operadorearen SIM txartelaren PINa."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Huts egin du SIM txartelaren PUK kodearen eragiketak!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Aldatu idazketa-metodoa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Hegaldi modua"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Eredua behar da gailua berrabiarazi ostean"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PINa behar da gailua berrabiarazi ostean"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Pasahitza behar da gailua berrabiarazi ostean"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Babestuago egoteko, erabili eredua"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Babestuago egoteko, erabili PINa"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Babestuago egoteko, erabili pasahitza"</string> diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml index 1383bafe2f05..91a15a47883b 100644 --- a/packages/SystemUI/res-keyguard/values-fa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"پین را وارد کنید"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"پین را وارد کنید"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"الگویتان را وارد کنید"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"الگو را رسم کنید"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"گذرواژهتان را وارد کنید"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"گذرواژه را وارد کنید"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"کارت نامعتبر"</string> <string name="keyguard_charged" msgid="5478247181205188995">"شارژ کامل شد"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • درحال شارژ بیسیم"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"به دلیل بروز خطا، سیمکارت داخلی غیرفعال نشد."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"الگو اشتباه است"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"الگو اشتباه. تلاش مجدد."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"گذرواژه اشتباه است"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"گذرواژه اشتباه. تلاش مجدد."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"پین اشتباه"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"پین اشتباه. مجدد سعی کنید."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"یا با اثر انگشت باز کنید"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"اثر انگشت تشخیص داده نشد"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"چهره شناسایی نشد"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"دوباره امتحان کنید یا پین را وارد کنید"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"دوباره امتحان کنید یا گذرواژه را وارد کنید"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"دوباره امتحان کنید یا الگو را رسم کنید"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"بعداز دفعات زیادی تلاش ناموفق، پین لازم است"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"بعداز دفعات زیادی تلاش ناموفق، گذرواژه لازم است"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"بعداز دفعات زیادی تلاش ناموفق، الگو لازم است"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"قفلگشایی با پین یا اثر انگشت"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"قفلگشایی با گذرواژه یا اثر انگشت"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"قفلگشایی با الگو یا اثر انگشت"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"برای امنیت بیشتر، دستگاه با خطمشی کاری قفل شده است"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"بعداز قفل همه باید از پین استفاده کرد"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"بعداز قفل همه باید از گذرواژه استفاده کرد"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"بعداز قفل همه باید از الگو استفاده کرد"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"بهروزرسانی درطول ساعات غیرفعال نصب خواهد شد"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"امنیت بیشتر لازم است. مدتی از پین استفاده نشده است."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"امنیت بیشتر لازم است. گذرواژه مدتی استفاده نشده است."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"امنیت بیشتر لازم است. مدتی از الگو استفاده نشده است."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"امنیت بیشتر لازم است. قفل دستگاه مدتی باز نشده است."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"قفلگشایی با چهره ممکن نیست. دفعات زیادی تلاش ناموفق"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"قفل با اثرانگشت باز نمیشود. دفعات زیادی تلاش ناموفق"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"عامل معتبر دردسترس نیست"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"تلاشهای بسیار زیادی با پین اشتباه انجام شده است"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"تلاشهای بسیار زیادی با الگوی اشتباه انجام شده است"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"تلاشهای بسیار زیادی با گذرواژه اشتباه انجام شده است"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# ثانیه دیگر دوباره امتحان کنید.}one{# ثانیه دیگر دوباره امتحان کنید.}other{# ثانیه دیگر دوباره امتحان کنید.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"پین سیمکارت را وارد کنید."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"پین سیمکارت «<xliff:g id="CARRIER">%1$s</xliff:g>» را وارد کنید."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"عملیات PUK سیمکارت ناموفق بود!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"تغییر روش ورودی"</string> <string name="airplane_mode" msgid="2528005343938497866">"حالت هواپیما"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"بعداز بازراهاندازی دستگاه باید الگو رسم شود"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"بعداز بازراهاندازی دستگاه باید پین وارد شود"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"بعداز بازراهاندازی دستگاه باید گذرواژه وارد شود"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"برای امنیت بیشتر، بهجای آن از الگو استفاده کنید"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"برای امنیت بیشتر، بهجای آن از پین استفاده کنید"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"برای امنیت بیشتر، بهجای آن از گذرواژه استفاده کنید"</string> diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml index 4b4843c2a6a7..7db4fea86033 100644 --- a/packages/SystemUI/res-keyguard/values-fi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Syötä PIN-koodi"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Lisää PIN-koodi"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Piirrä kuvio"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Piirrä kuvio"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Kirjoita salasana"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Anna salasana"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Virheellinen kortti"</string> <string name="keyguard_charged" msgid="5478247181205188995">"Ladattu"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan langattomasti"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Tapahtui virhe, eikä eSIMiä voitu poistaa käytöstä."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Väärä kuvio"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Väärä kuvio. Yritä uud."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Väärä salasana"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Väärä salasana. Yritä uud."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Väärä PIN-koodi"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Väärä PIN. Yritä uud."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Voit avata lukituksen myös sormenjäljellä"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Tunnistamaton sormenjälki"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Kasvoja ei tunnistettu"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Yritä uudelleen tai lisää PIN-koodi"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Yritä uudelleen tai lisää salasana"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Yritä uudelleen tai piirrä kuvio"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN-koodia kysytään usean yrityksen jälkeen"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Salasanaa kysytään usean yrityksen jälkeen"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Kuviota kysytään usean yrityksen jälkeen"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Avaa: PIN/sormenjälki"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Avaa: salasana/sormenjälki"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Avaa: kuvio/sormenjälki"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Laite lukittiin työkäytännöllä sen suojaamiseksi"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN-koodi tarvitaan lukitustilan jälkeen"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Salasana tarvitaan lukitustilan jälkeen"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Kuvio tarvitaan lukitustilan jälkeen"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Päivitys asennetaan käyttöajan ulkopuolella"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Lisäsuojausta tarvitaan. PIN-koodia ei ole käytetty."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Lisäsuojausta tarvitaan. Salasanaa ei ole käytetty."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Lisäsuojausta tarvitaan. Kuviota ei ole käytetty."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Lisäsuojausta tarvitaan. Laitetta ei ole avattu."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Avaus kasvoilla ei onnistu. Liikaa yrityksiä."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Avaus sormenjäljellä ei onnistu. Liikaa yrityksiä."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Luotettava taho ei ole käytettävissä"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Liian monta yritystä väärällä PIN-koodilla"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Liian monta yritystä väärällä kuviolla"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Liian monta yritystä väärällä salasanalla"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Yritä uudelleen # sekunnin kuluttua.}other{Yritä uudelleen # sekunnin kuluttua.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Anna SIM-kortin PIN-koodi."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Anna operaattorin <xliff:g id="CARRIER">%1$s</xliff:g> SIM-kortin PIN-koodi."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-kortin PUK-toiminto epäonnistui."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Vaihda syöttötapaa."</string> <string name="airplane_mode" msgid="2528005343938497866">"Lentokonetila"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Kuvio tarvitaan uudelleenkäynnistyksen jälkeen"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN-koodi tarvitaan uudelleenkäynnistyksen jälkeen"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Salasana tarvitaan uudelleenkäynnistyksen jälkeen"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Lisäsuojaa saat, kun käytät sen sijaan kuviota"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Lisäsuojaa saat, kun käytät sen sijaan PIN-koodia"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Lisäsuojaa saat, kun käytät sen sijaan salasanaa"</string> diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml index 41037515e2fb..bef61050b4ce 100644 --- a/packages/SystemUI/res-keyguard/values-fr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Saisissez le code d\'accès"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Saisissez le code"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Tracez le schéma"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Dessinez un schéma"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Saisissez votre mot de passe"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Saisissez le mot de passe"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Carte non valide."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Chargé"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • En charge sans fil"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Impossible de désactiver la carte eSIM en raison d\'une erreur."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Entrée"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Schéma incorrect"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Schéma incorrect. Réessayez."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Mot de passe incorrect"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Mot de passe incorrect. Réessayez."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Code incorrect"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Code incorrect. Réessayez."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ou déverrouillez avec votre empreinte digitale"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Empreinte non reconnue"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Visage non reconnu"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Réessayez ou saisissez le code"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Réessayez ou saisissez votre mot de passe"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Réessayez ou dessinez un schéma"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Code requis après trop de tentatives"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Mot de passe requis après trop de tentatives"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Schéma requis après trop de tentatives"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Déverrouillez avec code ou empreinte"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Déverrouillez avec mot de passe ou empreinte"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Déverrouillez avec schéma ou empreinte"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Appareil verrouillé par règle pro pour plus de sécurité"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Code requis après un blocage"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Mot de passe requis après un blocage"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Schéma requis après un blocage"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"La mise à jour sera installée pendant les heures d\'inactivité"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Code inutilisé depuis un moment. Renforcez la sécurité."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Mot de passe inutilisé depuis un moment. Renforcez la sécurité."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Schéma inutilisé depuis un moment. Renforcez la sécurité."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Appareil non déverrouillé depuis un moment. Renforcez la sécurité."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Déverrouillage facial impossible. Trop de tentatives."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Déverrouillage digital impossible. Trop de tentatives."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Agent de confiance non disponible"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Trop de tentatives avec un code incorrect"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Trop de tentatives avec un schéma incorrect"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Trop de tentatives avec un mot de passe incorrect"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}many{Réessayez dans # secondes.}other{Réessayez dans # secondes.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Saisissez le code PIN de la carte SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Saisissez le code PIN de la carte SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Échec du déverrouillage à l\'aide de la clé PUK de la carte SIM."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Changer le mode de saisie"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mode Avion"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Schéma requis après redémarrage de l\'appareil"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Code requis après redémarrage de l\'appareil"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Mot de passe requis après redémarrage de l\'appareil"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Pour plus de sécurité, utilisez plutôt un schéma"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Pour plus de sécurité, utilisez plutôt un code"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Pour plus de sécurité, utilisez plutôt un mot de passe"</string> diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml index c66ba19100a5..5c2d09bf1d88 100644 --- a/packages/SystemUI/res-keyguard/values-gu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"તમારો પિન દાખલ કરો"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"પિન દાખલ કરો"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"તમારી પૅટર્ન દાખલ કરો"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"પૅટર્ન દોરો"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"તમારો પાસવર્ડ દાખલ કરો"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"પાસવર્ડ દાખલ કરો"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"અમાન્ય કાર્ડ."</string> <string name="keyguard_charged" msgid="5478247181205188995">"ચાર્જ થઈ ગયું"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • વાયરલેસથી ચાર્જિંગ"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"એક ભૂલને લીધે ઇ-સિમ બંધ કરી શકાતું નથી."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"દાખલ કરો"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"ખોટી પૅટર્ન"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ખોટી પૅટર્ન. ફરી પ્રયાસ કરો."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"ખોટો પાસવર્ડ"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"ખોટો પાસવર્ડ. ફરી પ્રયાસ કરો."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ખોટો પિન"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"ખોટો પિન. ફરી પ્રયાસ કરો."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"અથવા ફિંગરપ્રિન્ટ વડે અનલૉક કરો"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ફિંગરપ્રિન્ટ ઓળખી શકાઈ નથી"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ચહેરો ન ઓળખાયો"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ફરી પ્રયાસ કરો અથવા પિન દાખલ કરો"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ફરી પ્રયાસ કરો અથવા પાસવર્ડ દાખલ કરો"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ફરી પ્રયાસ કરો અથવા પૅટર્ન દોરો"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"અનેક પ્રયાસો પછી પિન આવશ્યક છે"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"અનેક પ્રયાસો પછી પાસવર્ડ આવશ્યક છે"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"અનેક પ્રયાસો પછી પૅટર્ન આવશ્યક છે"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"પિન અથવા ફિંગરપ્રિન્ટ વડે અનલૉક કરો"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"પાસવર્ડ અથવા ફિંગરપ્રિન્ટ વડે અનલૉક કરો"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"પૅટર્ન અથવા ફિંગરપ્રિન્ટ વડે અનલૉક કરો"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"વધારાની સુરક્ષા માટે, ઑફિસની પૉલિસી અનુસાર ડિવાઇસ લૉક કરવામાં આવ્યું"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"પિન પછી પાસવર્ડ આવશ્યક છે"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"લૉકડાઉન પછી પાસવર્ડ આવશ્યક છે"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"પૅટર્ન પછી પાસવર્ડ આવશ્યક છે"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"નિષ્ક્રિયતાના સમય દરમિયાન અપડેટ ઇન્સ્ટૉલ થશે"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"વધારાની સુરક્ષા આવશ્યક છે. થોડા સમય માટે પિનનો ઉપયોગ થયો નથી."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"વધારાની સુરક્ષા આવશ્યક છે. થોડા સમય માટે પાસવર્ડનો ઉપયોગ થયો નથી."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"વધારાની સુરક્ષા આવશ્યક છે. થોડા સમય માટે પૅટર્નનો ઉપયોગ થયો નથી."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"વધારાની સુરક્ષા આવશ્યક છે. થોડા સમય માટે ડિવાઇસ અનલૉક થયું નથી."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"ફેસ વડે અનલૉક કરી શકાતું નથી. ઘણા બધા પ્રયાસો કર્યા."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ફિંગરપ્રિન્ટ વડે અનલૉક કરી શકાતું નથી. ઘણા બધા પ્રયાસો કર્યા."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ટ્રસ્ટ એજન્ટ ઉપલબ્ધ નથી"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ખોટા પિન વડે ઘણા બધા પ્રયાસો કર્યા"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ખોટી પૅટર્ન વડે ઘણા બધા પ્રયાસો કર્યા"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ખોટા પાસવર્ડ વડે ઘણા બધા પ્રયાસો કર્યા"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# સેકન્ડમાં ફરી પ્રયાસ કરો.}one{# સેકન્ડમાં ફરી પ્રયાસ કરો.}other{# સેકન્ડમાં ફરી પ્રયાસ કરો.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"સિમ પિન દાખલ કરો"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" માટે સિમ પિન દાખલ કરો."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"સિમ PUK ઓપરેશન નિષ્ફળ થયું!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ઇનપુટ પદ્ધતિ સ્વિચ કરો"</string> <string name="airplane_mode" msgid="2528005343938497866">"એરપ્લેન મોડ"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ડિવાઇસ ફરી ચાલુ થયા પછી પૅટર્ન આવશ્યક છે"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ડિવાઇસ ફરી ચાલુ થયા પછી પિન આવશ્યક છે"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ડિવાઇસ ફરી ચાલુ થયા પછી પાસવર્ડ આવશ્યક છે"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"વધારાની સુરક્ષા માટે, તેના બદલે પૅટર્નનો ઉપયોગ કરો"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"વધારાની સુરક્ષા માટે, તેના બદલે પિનનો ઉપયોગ કરો"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"વધારાની સુરક્ષા માટે, તેના બદલે પાસવર્ડનો ઉપયોગ કરો"</string> diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml index acd49ddcf6cd..52b204f54e63 100644 --- a/packages/SystemUI/res-keyguard/values-hi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"अपना पिन डालें"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"पिन डालें"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"अपना पैटर्न डालें"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"पैटर्न ड्रॉ करें"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"अपना पासवर्ड डालें"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"पासवर्ड डालें"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"गलत कार्ड."</string> <string name="keyguard_charged" msgid="5478247181205188995">"चार्ज हो गई है"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • वायरलेस तरीके से चार्ज हो रहा है"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"किसी गड़बड़ी की वजह से ई-सिम बंद नहीं किया जा सकता."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"डाला गया पैटर्न गलत है"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"गलत पैटर्न. दोबारा डालें."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"डाला गया पासवर्ड गलत है"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"गलत पासवर्ड. दोबारा डालें."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"गलत पिन"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"गलत पिन. दोबारा डालें."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"फ़िंगरप्रिंट से अनलॉक करें"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"फ़िंगरप्रिंट गलत है"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"चेहरा नहीं पहचाना गया"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"फिर से कोशिश करें या पिन डालें"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"फिर से कोशिश करें या पासवर्ड डालें"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"फिर से कोशिश करें या पैटर्न ड्रा करें"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"कई बार कोशिश की जा चुकी है, इसलिए पिन डालें"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"कई बार कोशिश की जा चुकी है, इसलिए पासवर्ड डालें"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"कई बार कोशिश की जा चुकी है, इसलिए पैटर्न ड्रा करें"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"पिन/फ़िंगरप्रिंट से अनलॉक करें"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"पासवर्ड/फ़िंगरप्रिंट से अनलॉक करें"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"पैटर्न/फ़िंगरप्रिंट से अनलॉक करें"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"सुरक्षा के लिए, ऑफ़िस की नीति के तहत डिवाइस लॉक था"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"लॉकडाउन के बाद, पिन डालना ज़रूरी है"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"लॉकडाउन के बाद, पासवर्ड डालना ज़रूरी है"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"लॉकडाउन के बाद, पैटर्न ड्रॉ करना ज़रूरी है"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"इनऐक्टिव रहने के दौरान, अपडेट इंस्टॉल किया जाएगा"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"अतिरिक्त सुरक्षा ज़रूरी है. कुछ समय से पिन नहीं डाला गया."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"अतिरिक्त सुरक्षा ज़रूरी है. कुछ समय से पासवर्ड नहीं डाला गया."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"अतिरिक्त सुरक्षा ज़रूरी है. कुछ समय से पैटर्न ड्रॉ नहीं किया गया."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"अतिरिक्त सुरक्षा ज़रूरी है. कुछ समय से डिवाइस अनलॉक नहीं हुआ."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"चेहरे से अनलॉक नहीं हुआ. कई बार कोशिश की गई."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"फ़िंगरप्रिंट से अनलॉक नहीं हुआ. कई बार कोशिश की गई."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"भरोसेमंद एजेंट की सुविधा उपलब्ध नहीं है"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"कई बार गलत पिन डाला जा चुका है"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"कई बार गलत पैटर्न ड्रॉ किया जा चुका है"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"कई बार गलत पासवर्ड डाला जा चुका है"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# सेकंड बाद फिर से कोशिश करें.}one{# सेकंड बाद फिर से कोशिश करें.}other{# सेकंड बाद फिर से कोशिश करें.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"सिम पिन डालें."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" के लिए सिम पिन डालें"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK की कार्यवाही विफल रही!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"इनपुट का तरीका बदलें"</string> <string name="airplane_mode" msgid="2528005343938497866">"हवाई जहाज़ मोड"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"डिवाइस रीस्टार्ट करने पर, पैटर्न ड्रॉ करना ज़रूरी है"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"डिवाइस रीस्टार्ट करने पर, पिन डालना ज़रूरी है"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"डिवाइस रीस्टार्ट करने पर, पासवर्ड डालना ज़रूरी है"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ज़्यादा सुरक्षा के लिए, इसके बजाय पैटर्न का इस्तेमाल करें"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ज़्यादा सुरक्षा के लिए, इसके बजाय पिन का इस्तेमाल करें"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ज़्यादा सुरक्षा के लिए, इसके बजाय पासवर्ड का इस्तेमाल करें"</string> diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml index 8c712271ae80..b5034d8cb64c 100644 --- a/packages/SystemUI/res-keyguard/values-hr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Unesite PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Unesite PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Unesite uzorak"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Nacrtajte uzorak"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Unesite zaporku"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Unesite zaporku"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Nevažeća kartica."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Napunjeno"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • bežično punjenje"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Onemogućivanje eSIM-a nije uspjelo zbog pogreške."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Unos"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Pogrešan uzorak"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Pogrešan uzorak Pokušajte ponovo."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Pogrešna zaporka"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Pogrešna zaporka. Pokušajte ponovo."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Pogrešan PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Pogrešan PIN. Pokušajte ponovo."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ili otključajte otiskom prsta"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Otisak prsta nije prepoznat"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Lice nije prepoznato"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Pokušajte ponovno ili unesite PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Pokušajte ponovno ili unesite zaporku"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Pokušajte ponovno ili izradite uzorak"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN je obavezan nakon previše pokušaja"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Zaporka je obavezna nakon previše pokušaja"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Uzorak je obavezan nakon previše pokušaja"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Otključajte PIN-om ili otiskom prsta"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Otključajte zaporkom ili otiskom prsta"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Otključajte uzorkom ili otiskom prsta"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Za više sigurnosti uređaj je zaključan prema pravilima za poslovne uređaje"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN je obavezan nakon zaključavanja"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Zaporka je obavezna nakon zaključavanja"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Uzorak je obavezan nakon zaključavanja"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Ažuriranje će se instalirati tijekom neaktivnosti"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Potrebna je dodatna sigurnost. PIN nije upotrijebljen duže vrijeme."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Potrebna je dodatna sigurnost. Zaporka nije upotrijebljena duže vrijeme."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Potrebna je dodatna sigurnost. Uzorak nije upotrijebljen duže vrijeme."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Potrebna je dodatna sigurnost. Uređaj nije otključan duže vrijeme."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nije moguće otključati licem. Previše pokušaja."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nije moguće otključati otiskom prsta. Previše pokušaja."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Agent za pouzdanost nije pouzdan"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Previše pokušaja s netočnim PIN-om"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Previše pokušaja s netočnim uzorkom"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Previše pokušaja s netočnom zaporkom"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Pokušajte ponovo za # s.}one{Pokušajte ponovo za # s.}few{Pokušajte ponovo za # s.}other{Pokušajte ponovo za # s.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Unesite PIN za SIM"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Unesite PIN za SIM mobilnog operatera \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operacija PUK-a SIM kartice nije uspjela!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Promjena načina unosa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Način rada u zrakoplovu"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Uzorak je obavezan nakon ponovnog pokretanja uređaja"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN je obavezan nakon ponovnog pokretanja uređaja"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Zaporka je obavezna nakon ponovnog pokretanja uređaja"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatnu sigurnost upotrijebite uzorak"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatnu sigurnost upotrijebite PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatnu sigurnost upotrijebite zaporku"</string> diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml index c1ca1871ad1f..a98408cf3d70 100644 --- a/packages/SystemUI/res-keyguard/values-hu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Adja meg PIN-kódját"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Adja meg a PIN-kódot"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Adja meg a mintáját"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Rajzolja le a mintát"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Adja meg jelszavát"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Adja meg a jelszót"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Érvénytelen kártya."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Feltöltve"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Vezeték nélküli töltés"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Hiba történt, így az eSIM-et nem lehet letiltani."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Helytelen minta"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Hibás minta. Próbálja újra."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Helytelen jelszó"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Hibás jelszó. Próbálja újra."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Helytelen PIN-kód"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Hibás PIN. Próbálja újra."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Vagy feloldás ujjlenyomattal"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Ismeretlen ujjlenyomat"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Sikertelen arcfelismerés"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Próbálja újra, vagy adja meg a PIN-kódot"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Próbálja újra, vagy adja meg a jelszót"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Próbálja újra, vagy rajzolja le a mintát"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Túl sok próbálkozás után PIN-kód megadása szükséges"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Túl sok próbálkozás után jelszó megadása szükséges"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Túl sok próbálkozás után minta megadása szükséges"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Feloldás PIN-kóddal vagy ujjlenyomattal"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Feloldás jelszóval vagy ujjlenyomattal"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Feloldás mintával vagy ujjlenyomattal"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"A fokozott biztonságért zárolta az eszközt a munkahelyi házirend"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN-kód megadása szükséges a zárolás után"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Jelszó megadása szükséges a zárolás után"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Minta megadása szükséges a zárolás után"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"A frissítést inaktív időben telepíti a rendszer"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Fokozott biztonság szükséges. Régóta nem használta a PIN-t."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Fokozott biztonság szükséges. Régóta nem használta jelszavát."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Fokozott biztonság szükséges. Régóta nem használta a mintát."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Fokozott biztonság szükséges. Az eszköz régóta nem volt feloldva."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Sikertelen arccal való feloldás. Túl sok kísérlet."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Sikertelen feloldás ujjlenyomattal. Túl sok kísérlet."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"A trust agent komponens nem áll rendelkezésre"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Túl sok próbálkozás helytelen PIN-kóddal"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Túl sok próbálkozás helytelen mintával"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Túl sok próbálkozás helytelen jelszóval"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Próbálja újra # másodperc múlva.}other{Próbálja újra # másodperc múlva.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Adja meg a SIM-kártya PIN-kódját."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Adja meg a(z) „<xliff:g id="CARRIER">%1$s</xliff:g>” SIM-kártya PIN-kódját."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"A SIM-kártya PUK-művelete sikertelen!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Beviteli módszer váltása"</string> <string name="airplane_mode" msgid="2528005343938497866">"Repülős üzemmód"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Minta megadása szükséges az újraindítás után"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN-kód megadása szükséges az zújraindítás után"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Jelszó megadása szükséges az újraindítás után"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"A nagyobb biztonság érdekében használjon inkább mintát"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"A nagyobb biztonság érdekében használjon inkább PIN-kódot"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"A nagyobb biztonság érdekében használjon inkább jelszót"</string> diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml index c4936c5f0078..9aa47a79b351 100644 --- a/packages/SystemUI/res-keyguard/values-hy/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Մուտքագրեք PIN կոդը"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Մուտքագրեք PIN կոդը"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Մուտքագրեք նախշը"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Գծեք նախշը"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Մուտքագրեք գաղտնաբառը"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Մուտքագրեք գաղտնաբառը"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Սխալ քարտ"</string> <string name="keyguard_charged" msgid="5478247181205188995">"Լիցքավորված է"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Անլար լիցքավորում"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Սխալի պատճառով չհաջողվեց անջատել eSIM-ը։"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Մուտքի ստեղն"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Նախշը սխալ է"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Նախշը սխալ է։ Կրկնեք։"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Գաղտնաբառը սխալ է"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Գաղտնաբառը սխալ է։ Կրկնեք։"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN կոդը սխալ է"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN-ը սխալ է: Կրկնեք։"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Կամ ապակողպեք մատնահետքով"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Մատնահետքը չի ճանաչվել"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Դեմքը չի ճանաչվել"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Նորից փորձեք կամ մուտքագրեք PIN կոդը"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Նորից փորձեք կամ մուտքագրեք գաղտնաբառը"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Նորից փորձեք կամ գծեք նախշը"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Չափազանց շատ փորձեր են արվել․ մուտքագրեք PIN կոդը"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Չափազանց շատ փորձեր են արվել․ մուտքագրեք գաղտնաբառը"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Չափազանց շատ փորձեր են արվել․ գծեք նախշը"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Ապակողպեք PIN-ով/մատնահետքով"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Ապակողպեք գաղտնաբառով/մատնահետքով"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Ապակողպեք նախշով/մատնահետքով"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Լրացուցիչ պաշտպանության համար սարքը կողպվել է"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Արգելափակումից հետո հարկավոր է մուտքագրել PIN կոդը"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Արգելափակումից հետո հարկավոր է մուտքագրել գաղտնաբառը"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Արգելափակումից հետո հարկավոր է գծել նախշը"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Թարմացումը կտեղադրվի ոչ ակտիվ ժամերին"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"PIN կոդը որոշ ժամանակ չի օգտագործվել։"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Գաղտնաբառը որոշ ժամանակ չի օգտագործվել։"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Նախշը որոշ ժամանակ չի օգտագործվել։"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Սարքը որոշ ժամանակ չի ապակողպվել։"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Դեմքով ապակողպումը հասանելի չէ։ Շատ փորձեր են արվել։"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Մատնահետքով ապակողպման փորձերի սահմանաչափը լրացել է։"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Trust agent-ն անհասանելի է"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Չափից շատ փորձեր են արվել սխալ PIN կոդով"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Չափից շատ փորձեր են արվել սխալ նախշով"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Չափից շատ փորձեր են արվել սխալ գաղտնաբառով"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Նորից փորձեք # վայրկյանից։}one{Նորից փորձեք # վայրկյանից։}other{Նորից փորձեք # վայրկյանից։}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Մուտքագրեք SIM քարտի PIN կոդը։"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Մուտքագրեք SIM քարտի PIN կոդը «<xliff:g id="CARRIER">%1$s</xliff:g>»-ի համար:"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK կոդի գործողությունը ձախողվեց:"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Փոխել ներածման եղանակը"</string> <string name="airplane_mode" msgid="2528005343938497866">"Ավիառեժիմ"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Սարքը վերագործարկելուց հետո գծեք նախշը"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Սարքը վերագործարկելուց հետո մուտքագրեք PIN կոդը"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Սարքը վերագործարկելուց հետո մուտքագրեք գաղտնաբառը"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Լրացուցիչ անվտանգության համար օգտագործեք նախշ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Լրացուցիչ անվտանգության համար օգտագործեք PIN կոդ"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Լրացուցիչ անվտանգության համար օգտագործեք գաղտնաբառ"</string> diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index 5b2b98caf88d..7af5eacdb666 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Masukkan PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Masukkan PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Masukkan pola"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Gambar pola"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Masukkan sandi"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Masukkan sandi"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Kartu Tidak Valid"</string> <string name="keyguard_charged" msgid="5478247181205188995">"Terisi penuh"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya secara nirkabel"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM tidak dapat dinonaktifkan karena terjadi error."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Masukkan"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Pola salah"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Pola salah. Coba lagi."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Sandi salah"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Sandi salah. Coba lagi."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN Salah"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN salah. Coba lagi."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Atau buka kunci dengan sidik jari"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Sidik jari tidak dikenali"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Wajah tidak dikenali"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Coba lagi atau masukkan PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Coba lagi atau masukkan sandi"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Coba lagi atau gambar pola"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN diperlukan setelah terlalu banyak upaya gagal"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Sandi diperlukan setelah terlalu banyak upaya gagal"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Pola diperlukan setelah terlalu banyak upaya gagal"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Buka kunci dengan PIN atau sidik jari"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Buka kunci dengan sandi atau sidik jari"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Buka kunci dengan pola atau sidik jari"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Untuk keamanan tambahan, perangkat dikunci oleh kebijakan kantor"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN diperlukan setelah kunci total"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Sandi diperlukan setelah kunci total"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pola diperlukan setelah kunci total"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Update akan diinstal selama jam tidak aktif"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Perlu keamanan tambahan. PIN tidak digunakan selama beberapa waktu."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Perlu keamanan tambahan. Sandi tidak digunakan selama beberapa waktu."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Perlu keamanan tambahan. Pola tidak digunakan selama beberapa waktu."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Perlu keamanan tambahan. Kunci perangkat tidak dibuka selama beberapa waktu."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Tidak dapat membuka kunci dengan wajah. Terlalu banyak upaya gagal."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Tidak dapat membuka kunci dengan sidik jari. Terlalu banyak upaya gagal."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Perangkat dipercaya tidak tersedia"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Terlalu banyak upaya dengan PIN yang salah"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Terlalu banyak upaya dengan pola yang salah"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Terlalu banyak upaya dengan sandi yang salah"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Coba lagi dalam # detik.}other{Coba lagi dalam # detik.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Masukkan PIN SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Masukkan PIN SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operasi PUK SIM gagal!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Beralih metode input"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mode pesawat"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Pola diperlukan setelah perangkat dimulai ulang"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN diperlukan setelah perangkat dimulai ulang"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Sandi diperlukan setelah perangkat dimulai ulang"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Untuk keamanan tambahan, gunakan pola"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Untuk keamanan tambahan, gunakan PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Untuk keamanan tambahan, gunakan sandi"</string> diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml index 0428316b7a73..1f8687f1097c 100644 --- a/packages/SystemUI/res-keyguard/values-is/strings.xml +++ b/packages/SystemUI/res-keyguard/values-is/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Sláðu inn PIN-númer"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Sláðu inn PIN-númer"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Færðu inn mynstrið þitt"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Teiknaðu mynstur"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Sláðu inn aðgangsorðið þitt"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Sláðu inn aðgangsorð"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ógilt kort."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Fullhlaðin"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Í þráðlausri hleðslu"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Villa kom í veg fyrir að hægt væri að gera eSIM-kortið óvirkt."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Færa inn"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Rangt mynstur"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Rangt mynstur. Reyndu aftur."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Rangt aðgangsorð"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Rangt aðgangsorð. Reyndu aftur."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Rangt PIN-númer"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Rangt PIN-númer. Reyndu aftur."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Eða opnaðu með fingrafari"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Fingrafar þekkist ekki"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Andlit þekkist ekki"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Reyndu aftur eða sláðu inn PIN-númer"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Reyndu aftur eða sláðu inn aðgangsorð"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Reyndu aftur eða teiknaðu mynstur"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN-númers er krafist eftir of margar tilraunir"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Aðgangsorðs er krafist eftir of margar tilraunir"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Mynsturs er krafist eftir of margar tilraunir"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Opnaðu með PIN-númeri eða fingrafari"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Opnaðu með aðgangsorði eða fingrafari"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Opnaðu með mynstri eða fingrafari"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Tækinu var læst af vinnureglum til að auka öryggi"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN-númers er krafist eftir læsingu"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Aðgangsorðs er krafist eftir læsingu"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mynsturs er krafist eftir læsingu"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Uppfærslan verður sett upp í aðgerðaleysi"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Viðbótaröryggis krafist. PIN-númer var ekki notað um hríð."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Viðbótaröryggis krafist. Aðgangsorð var ekki notað um hríð."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Viðbótaröryggis krafist. Mynstur var ekki notað um hríð."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Viðbótaröryggis krafist. Tækið var ekki tekið úr lás um hríð."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Ekki tókst að opna með andliti. Of margar tilraunir."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Ekki tókst að opna með fingrafari. Of margar tilraunir."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Traustfulltrúi er ekki tiltækur"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Of margar tilraunir með röngu PIN-númeri"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Of margar tilraunir með röngu mynstri"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Of margar tilraunir með röngu aðgangsorði"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Reyndu aftur eftir # sekúndu.}one{Reyndu aftur eftir # sekúndu.}other{Reyndu aftur eftir # sekúndur.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Sláðu inn PIN-númer SIM-kortsins."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Sláðu inn PIN-númer SIM-korts fyrir „<xliff:g id="CARRIER">%1$s</xliff:g>“."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"PUK-aðgerð SIM-korts mistókst!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Skipta um innsláttaraðferð"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flugstilling"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Mynsturs er krafist eftir að tækið er endurræst"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN-númers er krafist eftir að tækið er endurræst"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Aðgangsorðs er krafist eftir að tækið er endurræst"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Fyrir aukið öryggi skaltu nota mynstur í staðinn"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Fyrir aukið öryggi skaltu nota PIN-númer í staðinn"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Fyrir aukið öryggi skaltu nota aðgangsorð í staðinn"</string> diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml index 848d095783b1..bdfeda7b4c98 100644 --- a/packages/SystemUI/res-keyguard/values-it/strings.xml +++ b/packages/SystemUI/res-keyguard/values-it/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Inserisci il PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Inserisci il PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Inserisci la sequenza"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Inserisci la sequenza"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Inserisci la password"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Inserisci la password"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Scheda non valida."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Carico"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • In carica wireless"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Impossibile disattivare la eSIM a causa di un errore."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Invio"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Sequenza errata"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Sequenza errata. Riprova."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Password errata"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Password errata. Riprova."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN errato"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN errato. Riprova."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"In alternativa, sblocca con l\'impronta"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Impronta non riconosciuta"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Volto non riconosciuto"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Riprova o inserisci il PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Riprova o inserisci la password"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Riprova o inserisci la sequenza"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN richiesto dopo troppi tentativi"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Password richiesta dopo troppi tentativi"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Sequenza richiesta dopo troppi tentativi"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Sblocca con PIN o impronta"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Sblocca con password o impronta"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Sblocca con sequenza o impronta"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Disposit. bloccato da norme di lavoro per sicurezza"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN richiesto dopo il blocco"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Password richiesta dopo il blocco"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Sequenza richiesta dopo il blocco"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Aggiornamento installato durante ore di inattività"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Occorre maggiore sicurezza. PIN non usato per un po\' di tempo."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Occorre maggiore sicurezza. Password non usata per un po\' di tempo."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Occorre maggiore sicurezza. Sequenza non usata per un po\' di tempo."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Occorre maggiore sicurezza. Dispositivo non sbloccato per un po\' di tempo."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Impossibile sbloccare con volto. Troppi tentativi."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Impossib. sbloccare con impronta. Troppi tentativi."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"L\'agente di attendibilità non è disponibile"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Troppi tentativi con il PIN errato"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Troppi tentativi con la sequenza errata"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Troppi tentativi con la password errata"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}many{Riprova fra # secondi.}other{Riprova fra # secondi.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Inserisci il PIN della SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Inserisci il PIN della SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operazione con PUK della SIM non riuscita."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambia metodo di immissione"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modalità aereo"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Sequenza richiesta dopo il riavvio del dispositivo"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN richiesto dopo il riavvio del dispositivo"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Password richiesta dopo il riavvio del dispositivo"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Per maggior sicurezza, usa invece la sequenza"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Per maggior sicurezza, usa invece il PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Per maggior sicurezza, usa invece la password"</string> diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml index 1307ff5e365c..08cdd791fbec 100644 --- a/packages/SystemUI/res-keyguard/values-iw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"צריך להזין קוד אימות"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"צריך להזין קוד אימות"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"יש להזין קו ביטול נעילה"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"צריך לצייר קו ביטול נעילה"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"יש להזין סיסמה"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"צריך להזין סיסמה"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"כרטיס לא חוקי."</string> <string name="keyguard_charged" msgid="5478247181205188995">"הסוללה טעונה"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה אלחוטית"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"לא ניתן להשבית את כרטיס ה-eSIM עקב שגיאה."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"קו ביטול נעילה שגוי"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"קו ביטול נעילה שגוי. יש לנסות שוב."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"סיסמה שגויה"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"סיסמה שגויה. יש לנסות שוב."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"קוד האימות שגוי"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"קוד אימות שגוי. יש לנסות שוב."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"אפשר לבטל נעילה באמצעות טביעת אצבע"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"טביעת האצבע לא זוהתה"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"הפנים לא זוהו"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"יש לנסות שוב או להזין קוד אימות"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"יש לנסות שוב או להזין סיסמה"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"יש לנסות שוב או לצייר קו ביטול נעילה"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"אחרי יותר מדי ניסיונות נדרש קוד אימות"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"אחרי יותר מדי ניסיונות נדרשת סיסמה"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"אחרי יותר מדי ניסיונות נדרש קו ביטול נעילה"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"פתיחה בקוד אימות או טביעת אצבע"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"פתיחה בסיסמה או טביעת אצבע"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"פתיחה בקו ביטול נעילה או טביעת אצבע"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"לאבטחה מוגברת, המכשיר ננעל כחלק ממדיניות מקום העבודה"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"נדרש קוד אימות לאחר הפעלת \'ללא \'ביטול נעילה בטביעת אצבע\'\'"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"נדרשת סיסמה לאחר הפעלת \'ללא \'ביטול נעילה בטביעת אצבע\'\'"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"נדרש קו ביטול נעילה לאחר הפעלת \'ללא \'ביטול נעילה בטביעת אצבע\'\'"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"העדכון יותקן במהלך השעות שבהן אתם לא משתמשים במכשיר"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"נדרשת אבטחה מוגברת. לא השתמשת בקוד אימות זמן מה."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"נדרשת אבטחה מוגברת. לא השתמשת בסיסמה זמן מה."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"נדרשת אבטחה מוגברת. לא השתמשת בקו ביטול נעילה זמן מה."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"נדרשת אבטחה מוגברת. המכשיר לא היה נעול לזמן מה."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"לא ניתן לפתוח בזיהוי פנים. בוצעו יותר מדי ניסיונות."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"לא ניתן לפתוח בטביעת אצבע. בוצעו יותר מדי ניסיונות."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"התכונה \'סביבה אמינה\' לא זמינה"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"בוצעו יותר מדי ניסיונות עם קוד אימות שגוי"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"בוצעו יותר מדי ניסיונות עם קו ביטול נעילה שגוי"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"בוצעו יותר מדי ניסיונות עם סיסמה שגויה"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{אפשר לנסות שוב בעוד שנייה אחת.}one{אפשר לנסות שוב בעוד # שניות.}two{אפשר לנסות שוב בעוד # שניות.}other{אפשר לנסות שוב בעוד # שניות.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"יש להזין את קוד האימות של כרטיס ה-SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"יש להזין את קוד האימות של כרטיס ה-SIM של <xliff:g id="CARRIER">%1$s</xliff:g>."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"הניסיון לביטול הנעילה של כרטיס ה-SIM באמצעות קוד PUK נכשל!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"החלפת שיטת קלט"</string> <string name="airplane_mode" msgid="2528005343938497866">"מצב טיסה"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"נדרש קו ביטול נעילה אחרי שהמכשיר מופעל מחדש"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"נדרש קוד אימות אחרי שהמכשיר מופעל מחדש"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"נדרשת סיסמה אחרי שהמכשיר מופעל מחדש"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"כדי להגביר את רמת האבטחה, כדאי להשתמש בקו ביטול נעילה במקום זאת"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"כדי להגביר את רמת האבטחה, כדאי להשתמש בקוד אימות במקום זאת"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"כדי להגביר את רמת האבטחה, כדאי להשתמש בסיסמה במקום זאת"</string> diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml index 6bc5055378a9..05bd2ba51440 100644 --- a/packages/SystemUI/res-keyguard/values-ja/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"PIN を入力してください"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN を入力"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"パターンを入力してください"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"パターンを入力"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"パスワードを入力してください"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"パスワードを入力"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"無効なカードです。"</string> <string name="keyguard_charged" msgid="5478247181205188995">"充電が完了しました"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ワイヤレス充電中"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"エラーのため、eSIM を無効にできません。"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"入力"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"パターンが正しくありません"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"パターンが違います。やり直してください。"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"パスワードが正しくありません"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"パスワードが違います。やり直してください。"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN が正しくありません"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN が違います。やり直してください。"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"指紋でも解除できます"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"指紋を認識できません"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"顔を認識できません"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"もう一度試すか、PIN を入力してください"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"もう一度試すか、パスワードを入力してください"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"もう一度試すか、パターンを入力してください"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"試行回数の上限を超えると PIN が必要になります"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"試行回数の上限を超えるとパスワードが必要になります"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"試行回数の上限を超えるとパターンが必要になります"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN か指紋で解除"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"パスワードか指紋で解除"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"パターンか指紋で解除"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"仕事用ポリシーに基づきデバイスがロックされました"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ロックダウン後は PIN の入力が必要になります"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ロックダウン後はパスワードの入力が必要になります"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ロックダウン後はパターンの入力が必要になります"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"アップデートはアクティブでない時間帯にインストールされます"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"セキュリティ強化が必要: PIN がしばらく未使用です。"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"セキュリティ強化が必要: パスワードがしばらく未使用です。"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"セキュリティ強化が必要: パターンがしばらく未使用です。"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"セキュリティ強化が必要: デバイスがしばらくロック解除されていません。"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"顔認証でロックを解除できません。何度もログインに失敗したためログインできません。"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"指紋でロックを解除できません。何度もログインに失敗したためログインできません。"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"信頼エージェントは利用できません"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"間違った PIN による試行回数が上限を超えました"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"間違ったパターンによる試行回数が上限を超えました"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"間違ったパスワードによる試行回数が上限を超えました"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# 秒後にもう一度お試しください。}other{# 秒後にもう一度お試しください。}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN を入力してください。"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"「<xliff:g id="CARRIER">%1$s</xliff:g>」の SIM PIN を入力してください。"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK 操作に失敗しました。"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"入力方法の切り替え"</string> <string name="airplane_mode" msgid="2528005343938497866">"機内モード"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"デバイスの再起動後はパターンの入力が必要になります"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"デバイスの再起動後は PIN の入力が必要になります"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"デバイスの再起動後はパスワードの入力が必要になります"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"セキュリティを強化するには代わりにパターンを使用してください"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"セキュリティを強化するには代わりに PIN を使用してください"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"セキュリティを強化するには代わりにパスワードを使用してください"</string> diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml index 4687606376cb..3060cb2e7c6e 100644 --- a/packages/SystemUI/res-keyguard/values-ka/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"შეიყვანეთ PIN-კოდი"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"შეიყვანეთ PIN-კოდი"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"შეიყვანეთ განმბლოკავი ნიმუში"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"დახატეთ ნიმუში"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"შეიყვანეთ პაროლი"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"შეიყვანეთ პაროლი"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ბარათი არასწორია."</string> <string name="keyguard_charged" msgid="5478247181205188995">"დატენილია"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • იტენება უსადენოდ"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM-ის გათიშვა ვერ ხერხდება წარმოქმნილი შეცდომის გამო."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"შეყვანა"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"ნიმუში არასწორია"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ნიმ. არასწ. ცადეთ ხელახლა."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"პაროლი არასწორია"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"პარ. არასწ. ცადეთ ხელახლა."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN-კოდი არასწორია"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN არასწ. ცადეთ ხელახლა."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"ან თითის ანაბეჭდით განბლოკვა"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ანაბ. ამოცნ. ვერ მოხერხდა"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"სახის ამოცნ. ვერ მოხერხდა"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ცადეთ ხელახლა ან შეიყვანეთ PIN-კოდი"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ცადეთ ხელახლა ან შეიყვანეთ პაროლი"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ცადეთ ხელახლა ან დახატეთ ნიმუში"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"ძალიან ბევრი მცდელობის შემდეგ საჭიროა PIN-კოდი"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"ძალიან ბევრი მცდელობის შემდეგ საჭიროა პაროლი"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"ძალიან ბევრი მცდელობის შემდეგ საჭიროა ნიმუში"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN-კოდ. ან თითის ან. გან."</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"პაროლ. ან თითის ან. განბლ."</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ნიმუშით ან თითის ან. განბ."</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"დამატ. უსაფრთხ. მოწყობ. დაიბლ. სამსახ. წეს. თანახმად"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"დაბლოკვის შემდეგ საჭიროა PIN-კოდი"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"დაბლოკვის შემდეგ საჭიროა პაროლი"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"დაბლოკვის შემდეგ საჭიროა ნიმუში"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"განახლება დაყენდება არასამუშაო საათებში"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"საჭიროა დამ. უსაფრთ. PIN-კოდი ერთხანს არ გამოიყენ."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"საჭ. დამ. უსაფრთ. პაროლი ერთხანს არ გამოიყენება."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"საჭიროა დამ. უსაფრთ. ნიმუში ერთხანს არ გამოიყენება."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"საჭიროა დამ. უსაფრთ. მოწყობ. ერთხანს არ განიბლოკება."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"სახით განბლ. ვერ მოხ. მეტისმეტად ბევრი მცდელობა იყო."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ანაბ. განბლ. ვერ მოხ. მეტისმეტად ბევრი მცდელობა იყო."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ნდობის აგენტი მიუწვდომელია"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ძალიან ბევრი მცდელობა არასწორი PIN-კოდით"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ძალიან ბევრი მცდელობა არასწორი ნიმუშით"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ძალიან ბევრი მცდელობა არასწორი პაროლით"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# წამში ისევ ცადეთ.}other{# წამში ისევ ცადეთ.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"შეიყვანეთ SIM ბარათის PIN-კოდი."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"შეიყვანეთ SIM ბარათის PIN-კოდი „<xliff:g id="CARRIER">%1$s</xliff:g>“-ისთვის."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM ბარათის PUK-კოდით განბლოკვა ვერ მოხერხდა!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"შეყვანის მეთოდის გადართვა"</string> <string name="airplane_mode" msgid="2528005343938497866">"თვითმფრინავის რეჟიმი"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა ნიმუში"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა PIN-კოდი"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა პაროლი"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"დამატებითი უსაფრთხოებისთვის გამოიყენეთ ნიმუში"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"დამატებითი უსაფრთხოებისთვის გამოიყენეთ PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"დამატებითი უსაფრთხოებისთვის გამოიყენეთ პაროლი"</string> diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml index 79e28ef4bcbd..ecf8350d9bb7 100644 --- a/packages/SystemUI/res-keyguard/values-kk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"PIN кодын енгізіңіз"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN кодын енгізіңіз."</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Өрнекті енгізіңіз"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Өрнекті салыңыз."</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Құпия сөзді енгізіңіз"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Құпия сөзді енгізіңіз."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Жарамсыз карта."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Зарядталды"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Сымсыз зарядталуда"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Қатеге байланысты eSIM картасы өшірілмеді."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Енгізу"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Өрнек дұрыс емес"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Өрнек қате. Қайталап көріңіз."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Құпия сөз дұрыс емес"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Құпия сөз қате. Қайталап көріңіз."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN коды қате"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN коды қате. Қайталап көріңіз."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Не болмаса құлыпты саусақ ізімен ашыңыз."</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Саусақ ізі танылмады."</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Бет танылмады."</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Қайталап көріңіз не PIN кодын енгізіңіз."</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Қайталап көріңіз не құпия сөзді енгізіңіз."</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Қайталап көріңіз не өрнекті салыңыз."</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Тым көп әрекет жасалған соң, PIN коды сұралады."</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Тым көп әрекет жасалған соң, құпия сөз сұралады."</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Тым көп әрекет жасалған соң, өрнек сұралады."</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Құлыпты PIN кодымен не саусақ ізімен ашыңыз."</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Құлыпты құпия сөзбен не саусақ ізімен ашыңыз."</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Құлыпты өрнекпен не саусақ ізімен ашыңыз."</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Қауіпсіздікті күшейту үшін құрылғы жұмыс саясатына сай құлыпталды."</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Құлыпталғаннан кейін PIN кодын енгізу қажет."</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Құлыпталғаннан кейін құпия сөз енгізу қажет."</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Құлыпталғаннан кейін өрнек енгізу қажет."</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Пайдаланылмаған кезде жаңартылады."</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Қауіпсіздікті күшейту қажет. PIN коды біраз уақыт қолданылмаған."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Қауіпсіздікті күшейту қажет. Құпия сөз біраз уақыт қолданылмаған."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Қауіпсіздікті күшейту қажет. Өрнек біраз уақыт қолданылмаған."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Қауіпсіздікті күшейту қажет. Құрылғы құлпы біраз уақыт ашылмаған."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Құлып бетпен ашылмайды. Тым көп әрекет жасалды."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Құлып саусақ ізімен ашылмайды. Тым көп әрекет жасалды."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Сенімді агент функциясы істемейді."</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"PIN коды тым көп рет қате енгізілді."</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Өрнек тым көп рет қате енгізілді."</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Құпия сөз тым көп рет қате енгізілді."</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# секундтан соң қайталап көріңіз.}other{# секундтан соң қайталап көріңіз.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN кодын енгізіңіз."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" үшін SIM PIN кодын енгізіңіз."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK кодымен құлпы ашылмады!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Енгізу әдісін ауыстыру"</string> <string name="airplane_mode" msgid="2528005343938497866">"Ұшақ режимі"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Құрылғы өшіп қосылған соң, өрнек енгізу қажет."</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Құрылғы өшіп қосылған соң, PIN кодын енгізу қажет."</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Құрылғы өшіп қосылған соң, құпия сөз енгізу қажет."</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Қосымша қауіпсіздік үшін өрнекті пайдаланыңыз."</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Қосымша қауіпсіздік үшін PIN кодын пайдаланыңыз."</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Қосымша қауіпсіздік үшін құпия сөзді пайдаланыңыз."</string> diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml index 8936c2a954a8..4aa479815ce7 100644 --- a/packages/SystemUI/res-keyguard/values-km/strings.xml +++ b/packages/SystemUI/res-keyguard/values-km/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"បញ្ចូលកូដ PIN របស់អ្នក"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"បញ្ចូលកូដ PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"បញ្ចូលលំនាំរបស់អ្នក"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"គូរលំនាំ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"បញ្ចូលពាក្យសម្ងាត់របស់អ្នក"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"បញ្ចូលពាក្យសម្ងាត់"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"បណ្ណមិនត្រឹមត្រូវទេ។"</string> <string name="keyguard_charged" msgid="5478247181205188995">"បានសាកថ្មពេញ"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុងសាកថ្មឥតខ្សែ"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"មិនអាចបិទ eSIM បានទេ ដោយសារមានបញ្ហា។"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"លំនាំមិនត្រឹមត្រូវ"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"លំនាំខុស។ ព្យាយាមម្ដងទៀត។"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"ពាក្យសម្ងាត់មិនត្រឹមត្រូវ"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"ពាក្យសម្ងាត់ខុស។ ព្យាយាមម្ដងទៀត។"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"កូដ PIN មិនត្រឹមត្រូវទេ"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"កូដ PIN ខុស។ ព្យាយាមម្ដងទៀត។"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"ឬដោះសោដោយប្រើស្នាមម្រាមដៃ"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"មិនស្គាល់ស្នាមម្រាមដៃទេ"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"មិនស្គាល់មុខ"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ព្យាយាមម្ដងទៀត ឬបញ្ចូលកូដ PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ព្យាយាមម្ដងទៀត ឬបញ្ចូលពាក្យសម្ងាត់"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ព្យាយាមម្ដងទៀត ឬគូរលំនាំ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"ត្រូវការកូដ PIN បន្ទាប់ពីព្យាយាមច្រើនដងពេក"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"ត្រូវការពាក្យសម្ងាត់ បន្ទាប់ពីព្យាយាមច្រើនដងពេក"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"ត្រូវការលំនាំ បន្ទាប់ពីព្យាយាមច្រើនដងពេក"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"ដោះសោដោយប្រើកូដ PIN ឬស្នាមម្រាមដៃ"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"ដោះសោដោយប្រើពាក្យសម្ងាត់ ឬស្នាមម្រាមដៃ"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ដោះសោដោយប្រើលំនាំ ឬស្នាមម្រាមដៃ"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"ដើម្បីសុវត្ថិភាពបន្ថែម ឧបករណ៍ត្រូវបានចាក់សោដោយគោលការណ៍ការងារ"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ត្រូវការកូដ PIN បន្ទាប់ពីការចាក់សោ"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ត្រូវការពាក្យសម្ងាត់បន្ទាប់ពីការចាក់សោ"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ត្រូវការលំនាំបន្ទាប់ពីការចាក់សោ"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"នឹងដំឡើងកំណែថ្មីអំឡុងម៉ោងអសកម្ម"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ត្រូវការសុវត្ថិភាពបន្ថែម។ មិនបានប្រើកូដ PIN មួយរយៈ។"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ត្រូវការសុវត្ថិភាពបន្ថែម។ មិនបានប្រើពាក្យសម្ងាត់មួយរយៈ។"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ត្រូវការសុវត្ថិភាពបន្ថែម។ មិនបានប្រើលំនាំមួយរយៈ។"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"ត្រូវការសុវត្ថិភាពបន្ថែម។ មិនបានដោះសោឧបករណ៍មួយរយៈ។"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"មិនអាចដោះសោដោយប្រើមុខទេ។ ព្យាយាមច្រើនដងពេក។"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"មិនអាចដោះសោដោយប្រើស្នាមម្រាមដៃទេ។ ព្យាយាមច្រើនដងពេក។"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ភ្នាក់ងារទុកចិត្តមិនទំនេរទេ"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ព្យាយាមច្រើនដងពេកដោយប្រើកូដ PIN មិនត្រឹមត្រូវ"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ព្យាយាមច្រើនដងពេកដោយប្រើលំនាំមិនត្រឹមត្រូវ"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ព្យាយាមច្រើនដងពេកដោយប្រើពាក្យសម្ងាត់មិនត្រឹមត្រូវ"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{ព្យាយាមម្តងទៀតក្នុងរយៈពេល # វិនាទីទៀត។}other{ព្យាយាមម្តងទៀតក្នុងរយៈពេល # វិនាទីទៀត។}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"បញ្ចូលកូដ PIN របស់ស៊ីម។"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"បញ្ចូលកូដ PIN របស់ស៊ីមសម្រាប់ \"<xliff:g id="CARRIER">%1$s</xliff:g>\"។"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"មិនអាចដោះសោដោយប្រើកូដ PUK របស់ស៊ីមបានទេ!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ប្ដូរវិធីបញ្ចូល"</string> <string name="airplane_mode" msgid="2528005343938497866">"ពេលជិះយន្តហោះ"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ត្រូវការលំនាំក្រោយពេលឧបករណ៍ចាប់ផ្ដើមឡើងវិញ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ត្រូវការកូដ PIN ក្រោយពេលឧបករណ៍ចាប់ផ្ដើមឡើងវិញ"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ត្រូវការពាក្យសម្ងាត់ក្រោយពេលឧបករណ៍ចាប់ផ្ដើមឡើងវិញ"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ដើម្បីសុវត្ថិភាពបន្ថែម សូមប្រើលំនាំជំនួសវិញ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ដើម្បីសុវត្ថិភាពបន្ថែម សូមប្រើកូដ PIN ជំនួសវិញ"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ដើម្បីសុវត្ថិភាពបន្ថែម សូមប្រើពាក្យសម្ងាត់ជំនួសវិញ"</string> diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml index cb6cdcce0fc8..86a85abf83e3 100644 --- a/packages/SystemUI/res-keyguard/values-kn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"ನಿಮ್ಮ ಪಿನ್ ನಮೂದಿಸಿ"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"ಪಿನ್ ನಮೂದಿಸಿ"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"ನಿಮ್ಮ ಪ್ಯಾಟರ್ನ್ ನಮೂದಿಸಿ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಬಿಡಿಸಿ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ನಮೂದಿಸಿ"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"ಪಾಸ್ವರ್ಡ್ ನಮೂದಿಸಿ"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ಅಮಾನ್ಯ ಕಾರ್ಡ್."</string> <string name="keyguard_charged" msgid="5478247181205188995">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ವೈರ್ಲೆಸ್ ಆಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"ದೋಷದ ಕಾರಣದಿಂದಾಗಿ eSIM ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"ನಮೂದಿಸಿ"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"ಪ್ಯಾಟರ್ನ್ ತಪ್ಪಾಗಿದೆ"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ಪ್ಯಾಟರ್ನ್ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"ತಪ್ಪು ಪಾಸ್ವರ್ಡ್"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"ಪಾಸ್ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ಪಿನ್ ತಪ್ಪಾಗಿದೆ"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"ಪಿನ್ ತಪ್ಪಾಗಿದೆ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"ಅಥವಾ ಫಿಂಗರ್ಪ್ರಿಂಟ್ನೊಂದಿಗೆ ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಅನ್ನು ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ಮುಖವನ್ನು ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ ಅಥವಾ ಪಿನ್ ಅನ್ನು ನಮೂದಿಸಿ"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ ಅಥವಾ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸಿ"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ ಅಥವಾ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಬಿಡಿಸಿ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"ಹಲವಾರು ಪ್ರಯತ್ನಗಳ ನಂತರ ಪಿನ್ನ ಅಗತ್ಯವಿದೆ"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"ಹಲವಾರು ಪ್ರಯತ್ನಗಳ ನಂತರ ಪಾಸ್ವರ್ಡ್ನ ಅಗತ್ಯವಿದೆ"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"ಹಲವಾರು ಪ್ರಯತ್ನಗಳ ನಂತರ ಪ್ಯಾಟರ್ನ್ನ ಅಗತ್ಯವಿದೆ"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"ಪಿನ್ ಅಥವಾ ಫಿಂಗರ್ಪ್ರಿಂಟ್ನೊಂದಿಗೆ ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"ಪಾಸ್ವರ್ಡ್ ಅಥವಾ ಫಿಂಗರ್ ಪ್ರಿಂಟ್ನೊಂದಿಗೆ ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ಪ್ಯಾಟರ್ನ್ ಅಥವಾ ಫಿಂಗರ್ಪ್ರಿಂಟ್ನೊಂದಿಗೆ ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಗಾಗಿ, ಉದ್ಯೋಗ ನೀತಿಯ ಮೂಲಕ ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ಲಾಕ್ಡೌನ್ ಮಾಡಿದ ನಂತರ ಪಿನ್ ಬಳಸುವ ಅಗತ್ಯವಿದೆ"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ಲಾಕ್ಡೌನ್ನ ನಂತರ ಪಾಸ್ವರ್ಡ್ನ ಅಗತ್ಯವಿದೆ"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ಲಾಕ್ಡೌನ್ ಮಾಡಿದ ನಂತರ ಪ್ಯಾಟರ್ನ್ ಬಳಸುವ ಅಗತ್ಯವಿದೆ"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"ನಿಷ್ಕ್ರಿಯ ಸಮಯದಲ್ಲಿ ಅಪ್ಡೇಟ್ ಇನ್ಸ್ಟಾಲ್ ಆಗುತ್ತದೆ"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯ ಅಗತ್ಯವಿದೆ. ಪಿನ್ ಅನ್ನು ಸ್ವಲ್ಪ ಕಾಲದಿಂದ ಬಳಸಿಲ್ಲ."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯ ಅಗತ್ಯವಿದೆ. ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ಸ್ವಲ್ಪ ಕಾಲದಿಂದ ಬಳಸಿಲ್ಲ."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯ ಅಗತ್ಯವಿದೆ. ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಸ್ವಲ್ಪ ಕಾಲದಿಂದ ಬಳಸಿಲ್ಲ."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"ಹೆಚ್ಚುವರಿ ಸುರಕ್ಷತೆಯ ಅಗತ್ಯವಿದೆ. ಸ್ವಲ್ಪ ಕಾಲದಿಂದ ಸಾಧನವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿಲ್ಲ."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"ಮುಖದೊಂದಿಗೆ ಅನ್ಲಾಕ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ನೊಂದಿಗೆ ಅನ್ಲಾಕ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ವಿಶ್ವಾಸಾರ್ಹ ಏಜೆಂಟ್ ಲಭ್ಯವಿಲ್ಲ"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ತಪ್ಪಾದ ಪಿನ್ನೊಂದಿಗೆ ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ತಪ್ಪಾದ ಪ್ಯಾಟರ್ನ್ನೊಂದಿಗೆ ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ತಪ್ಪಾದ ಪಾಸ್ವರ್ಡ್ನೊಂದಿಗೆ ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# ಸೆಕೆಂಡಿನಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ.}one{# ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ.}other{# ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"ಸಿಮ್ ಪಿನ್ ನಮೂದಿಸಿ."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" ಗಾಗಿ ಸಿಮ್ ಪಿನ್ ನಮೂದಿಸಿ."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"ಸಿಮ್ PUK ಕಾರ್ಯಾಚರಣೆ ವಿಫಲಗೊಂಡಿದೆ!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ಇನ್ಪುಟ್ ವಿಧಾನ ಬದಲಿಸಿ"</string> <string name="airplane_mode" msgid="2528005343938497866">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿದ ನಂತರ ಪ್ಯಾಟರ್ನ್ ಬಳಸುವ ಅಗತ್ಯವಿದೆ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿದ ನಂತರ ಪಿನ್ ಬಳಸುವ ಅಗತ್ಯವಿದೆ"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿದ ನಂತರ ಪಾಸ್ವರ್ಡ್ ಬಳಸುವ ಅಗತ್ಯವಿದೆ"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ, ಬದಲಿಗೆ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಬಳಸಿ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ, ಬದಲಿಗೆ ಪಿನ್ ಬಳಸಿ"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ, ಬದಲಿಗೆ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ಬಳಸಿ"</string> diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml index 953773de7bec..0dec961e8415 100644 --- a/packages/SystemUI/res-keyguard/values-ko/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"PIN을 입력해 주세요."</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN 입력"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"패턴 입력"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"패턴 그리기"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"비밀번호 입력"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"비밀번호 입력"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"유효하지 않은 카드"</string> <string name="keyguard_charged" msgid="5478247181205188995">"충전됨"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 무선 충전 중"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"오류로 인해 eSIM을 사용 중지할 수 없습니다."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter 키"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"잘못된 패턴"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"잘못된 패턴입니다. 다시 시도해 주세요."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"잘못된 비밀번호"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"잘못된 비밀번호입니다. 다시 시도해 주세요."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN 오류"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"잘못된 PIN입니다. 다시 시도해 주세요."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"또는 지문으로 잠금 해제하세요."</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"지문이 인식되지 않았습니다."</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"얼굴을 인식할 수 없습니다."</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"다시 시도하거나 PIN을 입력하세요."</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"다시 시도하거나 비밀번호를 입력하세요."</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"다시 시도하거나 패턴을 그리세요."</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"시도 횟수가 너무 많아 PIN을 입력해야 합니다."</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"시도 횟수가 너무 많아 비밀번호를 입력해야 합니다."</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"시도 횟수가 너무 많아 패턴을 입력해야 합니다."</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN 또는 지문으로 잠금 해제"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"비밀번호 또는 지문으로 잠금 해제"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"패턴 또는 지문으로 잠금 해제"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"보안 강화를 위해 업무 정책에 따라 기기가 잠겼습니다."</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"기기가 잠겨 PIN을 입력해야 합니다."</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"기기가 잠겨 비밀번호를 입력해야 합니다."</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"기기가 잠겨 패턴을 입력해야 합니다."</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"미사용 시간에 업데이트가 설치됩니다."</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"보안을 강화해야 합니다. 한동안 PIN이 사용되지 않았습니다."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"보안을 강화해야 합니다. 한동안 비밀번호가 사용되지 않았습니다."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"보안을 강화해야 합니다. 한동안 패턴이 사용되지 않았습니다."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"보안을 강화해야 합니다. 한동안 기기가 잠금 해제되지 않았습니다."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"얼굴로 잠금 해제할 수 없습니다. 시도 횟수가 너무 많습니다."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"지문으로 잠금 해제할 수 없습니다. 시도 횟수가 너무 많습니다."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Trust Agent를 사용할 수 없습니다."</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"잘못된 PIN을 사용한 시도 횟수가 너무 많습니다."</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"잘못된 패턴을 사용한 시도 횟수가 너무 많습니다."</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"잘못된 비밀번호를 사용한 시도 횟수가 너무 많습니다."</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{#초 후에 다시 시도하세요.}other{#초 후에 다시 시도하세요.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN을 입력하세요."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\'<xliff:g id="CARRIER">%1$s</xliff:g>\'의 SIM PIN을 입력하세요."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK 작업이 실패했습니다."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"입력 방법 전환"</string> <string name="airplane_mode" msgid="2528005343938497866">"비행기 모드"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"기기가 다시 시작되어 패턴을 입력해야 합니다."</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"기기가 다시 시작되어 PIN을 입력해야 합니다."</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"기기가 다시 시작되어 비밀번호를 입력해야 합니다."</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"보안 강화를 위해 대신 패턴 사용"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"보안 강화를 위해 대신 PIN 사용"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"보안 강화를 위해 대신 비밀번호 사용"</string> diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index 7e095deab94b..8a4e00b5c096 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"PIN кодуңузду киргизиңиз"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN кодду киргизиңиз"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Графикалык ачкычты киргизиңиз"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Графикалык ачкчты тартңыз"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Сырсөзүңүздү киргизиңиз"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Сырсөздү киргизиңиз"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"SIM-карта жараксыз."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Кубатталды"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зымсыз кубатталууда"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Катадан улам eSIM-картаны өчүрүүгө болбойт."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Киргизүү"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Графикалык ачкыч туура эмес"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Графклк ачкч тура эмс. Кайтлап крүңз."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Сырсөз туура эмес"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Сырсөз туура эмес. Кайтлап крүңз."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN-код туура эмес"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN кд тура эмс. Кайтлап крүңз."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Болбосо манжа изи менен кулпусун ачыңыз"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Манжа изи таанылган жок"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Жүзү таанылбайт"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Кайталап көрүңүз же PIN кодду киргизиңиз"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Кайра аракет кылыңыз же сырсөздү киргизиңиз"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Кайра аракет кылыңыз же графикалык ачкычты тартыңыз"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Өтө көп аракеттен кийин PIN код талап кылынат"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Өтө көп аракеттен кийин сырсөз талап кылынат"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Өтө көп аракеттен кийин графикалык ачкыч талап клынт"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN кд же мнжа изи мнен клпусн ачңыз"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Срсөз же мнжа изи мнен клпусн ачңз"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Грфиклык ачкч же мнжа изи менн клпусн ачңз"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Кошумча коопсуздук үчүн түзмөк жумуш саясатына ылайык кулпуланган"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Бекем кулпулангандан кийин PIN код талап кылынат"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Бекем кулпулангандан кийин сырсөз талап кылынат"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Бекем кулпулангандан кийн грфикалык ачкыч талп клынт"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Жигердүү эмес сааттарда жаңыртылат"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Кошмча кпсуздук тлап клнат. PIN код бир нче убкыт бою клднулгн эмeс."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Кошмча кпсуздук тлап клнат. Сырсз бир нче убкыт бою клднулгн эмeс."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Кошмча кпсуздук тлап клнат. Грфиклык ачкч бир нче убкыт бою клднулгн эмeс."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Кошмча кпсуздук тлап клнат. Түзмктн клпсу бир нче убкт бю ачлгн эмс."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Жүз менен кулпусу ачылбай жатат. Өтө көп жолу аракет кылдыңыз."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Манжа изи менен кулпусу ачылбай жатат. Өтө көп жолу аракет кылдыңыз."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Ишеним агенти жеткиликсиз"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Туура эмес PIN код менен өтө көп аракет"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Туура эмес графикалык ачкыч менен өтө көп аракет"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Туура эмес сырсөз менен өтө көп аракет"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# секунддан кийин кайталаңыз.}other{# секунддан кийин кайталаңыз.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM-картанын PIN-кодун киргизиңиз."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" SIM-картасынын PIN-кодун киргизиңиз."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-картанын PUK-кодун ачуу кыйрады!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Киргизүү ыкмасын өзгөртүү"</string> <string name="airplane_mode" msgid="2528005343938497866">"Учак режими"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Түзмк өчрүп кйгүзлгндн кйин графклык ачкч талп клнат"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Түзмөк өчүрүп күйгүзлгндн кийин PIN код талап кылнат"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Түзмөк өчүрүп күйгүзүлгөндөн кийин срсөз талп кылынт"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Кошумча коопсуздук үчүн анын ордуна графикалык ачкычты колдонуңуз"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Кошумча коопсуздук үчүн анын ордуна PIN кодду колдонуңуз"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Кошумча коопсуздук үчүн анын ордуна сырсөздү колдонуңуз"</string> diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml index f5e438b7781f..4b8bbf04e8ba 100644 --- a/packages/SystemUI/res-keyguard/values-lo/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"ໃສ່ລະຫັດ PIN ຂອງທ່ານ"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"ໃສ່ລະຫັດ PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"ໃສ່ຮູບແບບປົດລັອກຂອງທ່ານ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ແຕ້ມຮູບແບບ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"ປ້ອນລະຫັດຜ່ານຂອງທ່ານ"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"ໃສ່ລະຫັດຜ່ານ"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ບັດບໍ່ຖືກຕ້ອງ."</string> <string name="keyguard_charged" msgid="5478247181205188995">"ສາກເຕັມແລ້ວ."</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກໄຟໄຮ້ສາຍ"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"ບໍ່ສາມາດປິດການນຳໃຊ້ eSIM ໄດ້ເນື່ອງຈາກມີຂໍ້ຜິດພາດ."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"ປ້ອນເຂົ້າ"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"ຮູບແບບບໍ່ຖືກຕ້ອງ"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ຮູບແບບບໍ່ຖືກຕ້ອງ. ກະລຸນາລອງໃໝ່."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"ລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"ລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ. ກະລຸນາລອງໃໝ່."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN ບໍ່ຖືກຕ້ອງ. ກະລຸນາລອງໃໝ່."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"ຫຼື ປົດລັອກດ້ວຍລາຍນິ້ວມື"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ບໍ່ສາມາດຈຳແນກລາຍນິ້ວມືໄດ້"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ລອງໃໝ່ ຫຼື ໃສ່ PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ລອງໃໝ່ ຫຼື ໃສ່ລະຫັດຜ່ານ"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ລອງໃໝ່ ຫຼື ແຕ້ມຮູບແບບ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"ຕ້ອງໃສ່ PIN ຫຼັງຈາກທີ່ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"ຕ້ອງໃສ່ລະຫັດຜ່ານຫຼັງຈາກທີ່ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"ຕ້ອງແຕ້ມຮູບແບບຫຼັງຈາກທີ່ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"ປົດລັອກດ້ວຍ PIN ຫຼື ລາຍນິ້ວມື"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"ປົດລັອກດ້ວຍລະຫັດຜ່ານ ຫຼື ລາຍນິ້ວມື"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ປົດລັອກດ້ວຍຮູບແບບ ຫຼື ລາຍນິ້ວມື"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"ເພື່ອເພີ່ມຄວາມປອດໄພ, ອຸປະກອນໄດ້ຖືກລັອກໂດຍນະໂຍບາຍບ່ອນເຮັດວຽກ"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ຕ້ອງໃສ່ PIN ຫຼັງຈາກທີ່ລັອກໄວ້"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ຕ້ອງໃສ່ລະຫັດຜ່ານຫຼັງຈາກທີ່ລັອກໄວ້"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ຕ້ອງແຕ້ມຮູບແບບຫຼັງຈາກທີ່ລັອກໄວ້"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"ການອັບເດດຈະຕິດຕັ້ງໃນລະຫວ່າງຊົ່ວໂມງທີ່ບໍ່ມີການນຳໃຊ້"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ຕ້ອງເພີ່ມຄວາມປອດໄພ. ບໍ່ໄດ້ໃຊ້ PIN ມາໄລຍະໜຶ່ງແລ້ວ."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ຕ້ອງເພີ່ມຄວາມປອດໄພ. ບໍ່ໄດ້ໃຊ້ລະຫັດຜ່ານມາໄລຍະໜຶ່ງແລ້ວ."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ຕ້ອງເພີ່ມຄວາມປອດໄພ. ບໍ່ໄດ້ໃຊ້ຮູບແບບມາໄລຍະໜຶ່ງແລ້ວ."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"ຕ້ອງເພີ່ມຄວາມປອດໄພ. ບໍ່ໄດ້ປົດລັອກອຸປະກອນມາໄລຍະໜຶ່ງແລ້ວ."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"ບໍ່ສາມາດປົດລັອກດ້ວຍໃບໜ້າໄດ້. ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ບໍ່ສາມາດປົດລັອກດ້ວຍລາຍນິ້ວມືໄດ້. ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ຕົວແທນທີ່ເຊື່ອຖືໄດ້ບໍ່ພ້ອມໃຫ້ບໍລິການ"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປດ້ວຍ PIN ທີ່ບໍ່ຖືກຕ້ອງ"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປດ້ວຍຮູບແບບທີ່ບໍ່ຖືກຕ້ອງ"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປດ້ວຍລະຫັດຜ່ານທີ່ບໍ່ຖືກຕ້ອງ"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{ກະລຸນາລອງໃໝ່ໃນ # ວິນາທີ.}other{ກະລຸນາລອງໃໝ່ໃນ # ວິນາທີ.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"ໃສ່ລະຫັດ PIN ຂອງຊິມ."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"ໃສ່ລະຫັດ PIN ຂອງຊິມສຳລັບ \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"PUK ຂອງ SIM ເຮັດວຽກລົ້ມເຫຼວ!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ"</string> <string name="airplane_mode" msgid="2528005343938497866">"ໂໝດໃນຍົນ"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ຕ້ອງແຕ້ມຮູບແບບຫຼັງຈາກຣີສະຕາດອຸປະກອນ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ຕ້ອງໃສ່ PIN ຫຼັງຈາກຣີສະຕາດອຸປະກອນ"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ຕ້ອງໃສ່ລະຫັດຜ່ານຫຼັງຈາກຣີສະຕາດອຸປະກອນ"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ, ໃຫ້ໃຊ້ຮູບແບບແທນ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ, ໃຫ້ໃຊ້ PIN ແທນ"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ, ໃຫ້ໃຊ້ລະຫັດຜ່ານແທນ"</string> diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml index c173905ce2e0..d2f7f087cd03 100644 --- a/packages/SystemUI/res-keyguard/values-lt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Įveskite PIN kodą"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Įveskite PIN kodą"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Nubrėžkite atrakinimo piešinį"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Nupieškite atrakinimo piešinį"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Įveskite slaptažodį"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Įveskite slaptažodį"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Netinkama kortelė."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Įkrauta"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kraunama be laidų"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Dėl klaidos nepavyko išjungti „eSIM“ kortelės."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Netinkamas atrakinimo piešinys"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Netinkamas atrakinimo piešinys. Bandykite dar kartą."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Netinkamas slaptažodis"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Netinkamas slaptažodis. Bandykite dar kartą."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Netinkamas PIN kodas"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Netinkamas PIN kodas. Bandykite dar kartą."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Arba atrakinkite piršto atspaudu"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Piršto atspaudas neatpažintas"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Veidas neatpažintas"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Bandykite dar kartą arba įveskite PIN kodą"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Bandykite dar kartą arba įveskite slaptažodį"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Bandykite dar kartą arba nupieškite atrakinimo piešinį"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Po per daug bandymų reikia įvesti PIN kodą"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Po per daug bandymų reikia įvesti slaptažodį"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Po per daug bandymų reikia nupiešti atrakinimo piešinį"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Atrakinkite PIN kodu arba piršto atspaudu"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Atrakinkite slaptažodžiu arba piršto atspaudu"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Atrakinkite atrakinimo piešiniu arba piršto atspaudu"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Norint apsaugoti įrenginys užrakintas pagal darbo politiką"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po užrakinimo reikalingas PIN kodas"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po užrakinimo reikalingas slaptažodis"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po užrakinimo reikalingas atrakinimo piešinys"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Naujinys bus įdiegtas neaktyvumo valandomis"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Reikalinga papildoma sauga. PIN kodas nebuvo naudojamas kurį laiką."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Reikalinga papildoma sauga. Slaptažodis nebuvo naudojamas kurį laiką."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Reikalinga papildoma sauga. Atrakinimo piešinys nebuvo naudojamas kurį laiką."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Reikalinga papildoma sauga. Įrenginys nebuvo užrakintas kurį laiką."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nepavyko atrakinti pagal veidą. Per daug bandymų."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nepavyko atrakinti piršto atspaudu. Per daug bandymų."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Patikima priemonė nepasiekiama"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Per daug bandymų naudojant netinkamą PIN kodą"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Per daug bandymų naudojant netinkamą atrakinimo piešinį"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Per daug bandymų naudojant netinkamą slaptažodį"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Bandykite dar kartą po # sekundės.}one{Bandykite dar kartą po # sekundės.}few{Bandykite dar kartą po # sekundžių.}many{Bandykite dar kartą po # sekundės.}other{Bandykite dar kartą po # sekundžių.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Įveskite SIM kortelės PIN kodą."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Įveskite „<xliff:g id="CARRIER">%1$s</xliff:g>“ SIM kortelės PIN kodą"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Nepavyko atlikti SIM kortelės PUK kodo operacijos."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Perjungti įvesties metodą"</string> <string name="airplane_mode" msgid="2528005343938497866">"Lėktuvo režimas"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Iš naujo paleidus įrenginį reikalingas atrakinimo piešinys"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Iš naujo paleidus įrenginį reikalingas PIN kodas"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Iš naujo paleidus įrenginį reikalingas slaptažodis"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Papildomai saugai užtikrinti geriau naudokite atrakinimo piešinį"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Papildomai saugai užtikrinti geriau naudokite PIN kodą"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Papildomai saugai užtikrinti geriau naudokite slaptažodį"</string> diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml index 40b6b3f73cb1..5d992f8444ef 100644 --- a/packages/SystemUI/res-keyguard/values-lv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Ievadiet savu PIN kodu"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Ievadiet PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Ievadiet savu kombināciju"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Uzzīmējiet kombināciju"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Ievadiet paroli"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Ievadiet paroli"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Nederīga karte."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Akumulators uzlādēts"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek bezvadu uzlāde"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Kļūdas dēļ nevar atspējot eSIM karti."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Ievadīšanas taustiņš"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Nepareiza kombinācija"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Nepareiza kombinācija. Mēģiniet vēlreiz."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Nepareiza parole"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Nepareiza parole. Mēģiniet vēlreiz."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Nepareizs PIN kods."</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Nepareizs PIN. Mēģiniet vēlreiz."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Vai atbloķējiet, izmantojot pirksta nospiedumu"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Pirksta nospiedums netika atpazīts"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Seja netika atpazīta"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Mēģiniet vēlreiz vai ievadiet PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Mēģiniet vēlreiz vai ievadiet paroli"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Mēģiniet vēlreiz vai uzzīmējiet kombināciju"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Pārsniedzot mēģinājumu skaitu, jāievada PIN"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Pārsniedzot mēģinājumu skaitu, jāievada parole"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Pārsniedzot mēģinājumu skaitu, jāzīmē kombinācija"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Atbloķējiet ar PIN vai pirksta nospiedumu"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Atbloķējiet ar paroli vai pirksta nospiedumu"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Atbloķējiet ar kombināciju vai pirksta nospiedumu"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Saskaņā ar darbavietas politiku papildu drošībai ierīce ir bloķēta"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pēc bloķēšanas ir jāievada PIN"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Pēc bloķēšanas ir jāievada parole"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pēc bloķēšanas ir jāzīmē kombinācija"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Atjauninājums tiks instalēts neaktīvajā laikā"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Jāveic papildu drošības darbība. PIN ilgu laiku nav lietots."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Jāveic papildu drošības darbība. Parole ilgu laiku nav lietota."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Jāveic papildu drošības darbība. Kombinācija ilgu laiku nav lietota."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Jāveic papildu drošības darbība. Ierīce ilgu laiku netika atbloķēta."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nevar autorizēt pēc sejas. Pārāk daudz mēģinājumu."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nevar autorizēt ar pirksta nospiedumu. Pārāk daudz mēģinājumu."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Uzticamības pārbaudes programma nav pieejama"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Pārāk daudz mēģinājumu ar nepareizu PIN."</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Pārāk daudz mēģinājumu ar nepareizu kombināciju."</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Pārāk daudz mēģinājumu ar nepareizu paroli."</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Mēģiniet vēlreiz pēc # sekundes.}zero{Mēģiniet vēlreiz pēc # sekundēm.}one{Mēģiniet vēlreiz pēc # sekundes.}other{Mēģiniet vēlreiz pēc # sekundēm.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Ievadiet SIM kartes PIN kodu."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Ievadiet SIM kartes “<xliff:g id="CARRIER">%1$s</xliff:g>” PIN kodu."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM kartes PUK koda ievadīšana neizdevās!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Pārslēgt ievades metodi"</string> <string name="airplane_mode" msgid="2528005343938497866">"Lidojuma režīms"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Pēc ierīces restartēšanas ir jāuzzīmē kombinācija"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Pēc ierīces restartēšanas ir jāievada PIN"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Pēc ierīces restartēšanas ir jāievada parole"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Papildu drošībai izmantojiet kombināciju"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Papildu drošībai izmantojiet PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Papildu drošībai izmantojiet paroli"</string> diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml index 1a2513c78a4c..99e35f9936b5 100644 --- a/packages/SystemUI/res-keyguard/values-mk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Внесете го PIN-кодот"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Внесете PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Внесете ја шемата"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Нацртај шема"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Внесете ја лозинката"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Внесете лозинка"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Неважечка картичка."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Полна"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Се полни безжично"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM-картичката не може да се оневозможи поради грешка."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Внеси"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Погрешна шема"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Погрешна шема. Обидете се повторно."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Погрешна лозинка"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Погрешна лозинка. Обидете се повторно."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Погрешен PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Погрешен PIN-код. Обидете се повторно."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Или отклучете со отпечаток"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Отпечатокот не е препознаен"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Ликот не е препознаен"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Обидете се повторно или внесете PIN-код"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Обидете се повторно или внесете лозинка"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Обидете се повторно или нацртајте шема"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Потребен е PIN-код по премногу обиди"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Потребна е лозинка по премногу обиди"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Потребна е шема по премногу обиди"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Отклучете со PIN-код или отпечаток"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Отклучете со лозинка или отпечаток"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Отклучете со шема или отпечаток"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"За дополнителна безбедност, уредот беше заклучен со работно правило"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Потребен е PIN-код по заклучување"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Потребна е лозинка по заклучување"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Потребна е шема по заклучување"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Ажурирањето ќе се инсталира за време на неактивни часови"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Потребна е дополнителна безбедност. PIN-кодот не бил користен некое време."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Потребна е дополнителна безбедност. Лозинката не била користена некое време."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Потребна е дополнителна безбедност. Шемата не била користена некое време."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Потребна е дополнителна безбедност. Уредот не бил отклучен некое време."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Не може да се отклучи со лик. Премногу обиди."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Не може да се отклучи со отпечаток. Премногу обиди."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Не е достапен aгент од доверба"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Премногу обиди со погрешен PIN-код"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Премногу обиди со погрешна шема"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Премногу обиди со погрешна лозинка"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Обидете се повторно по # секунда.}one{Обидете се повторно по # секунда.}other{Обидете се повторно по # секунди.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Внесете PIN на SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Внесете PIN на SIM за „<xliff:g id="CARRIER">%1$s</xliff:g>“."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-картичката не се отклучи со PUK-кодот!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Префрли метод за внесување"</string> <string name="airplane_mode" msgid="2528005343938497866">"Авионски режим"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Потребна е шема по рестартирање на уредот"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Потребен е PIN-код по рестартирање на уредот"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Потребна е лозинка по рестартирање на уредот"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"За дополнителна безбедност, користете шема"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"За дополнителна безбедност, користете PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"За дополнителна безбедност, користете лозинка"</string> diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml index a223fd10e684..81813576b51f 100644 --- a/packages/SystemUI/res-keyguard/values-ml/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"പിൻ നൽകുക"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"പിൻ നൽകുക"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"നിങ്ങളുടെ പാറ്റേൺ നൽകുക"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"പാറ്റേൺ വരയ്ക്കുക"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"നിങ്ങളുടെ പാസ്വേഡ് നല്കുക"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"പാസ്വേഡ് നൽകുക"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"അസാധുവായ കാർഡ്."</string> <string name="keyguard_charged" msgid="5478247181205188995">"ചാർജായി"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • വയർലെസ്സ് ആയി ചാർജ് ചെയ്യുന്നു"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"പിശക് കാരണം ഇ-സിം പ്രവർത്തനരഹിതമാക്കാനാകുന്നില്ല"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"എന്റർ"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"പാറ്റേൺ തെറ്റാണ്"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"പാറ്റേൺ തെറ്റ്. വീണ്ടും ശ്രമിക്കൂ."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"പാസ്വേഡ് തെറ്റാണ്"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"പാസ്വേഡ് തെറ്റ്. വീണ്ടും ശ്രമിക്കൂ."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"പിൻ തെറ്റാണ്"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"പിൻ തെറ്റ്. വീണ്ടും ശ്രമിക്കൂ."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"അല്ലെങ്കിൽ വിരലടയാളം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്യൂ"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"വിരലടയാളം തിരിച്ചറിഞ്ഞില്ല"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"മുഖം തിരിച്ചറിഞ്ഞിട്ടില്ല"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"വീണ്ടും ശ്രമിക്കുക അല്ലെങ്കിൽ പിൻ നൽകുക"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"വീണ്ടും ശ്രമിക്കുക അല്ലെങ്കിൽ പാസ്വേഡ് നൽകുക"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"വീണ്ടും ശ്രമിക്കുക അല്ലെങ്കിൽ പാറ്റേൺ വരയ്ക്കുക"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"നിരവധി ശ്രമങ്ങൾ നടത്തിയാൽ പിൻ നൽകേണ്ടതുണ്ട്"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"നിരവധി ശ്രമങ്ങൾ നടത്തിയാൽ പാസ്വേഡ് നൽകേണ്ടതുണ്ട്"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"നിരവധി ശ്രമങ്ങൾ നടത്തിയാൽ പാറ്റേൺ വരയ്ക്കേണ്ടതുണ്ട്"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"പിൻ/വിരലടയാളം കൊണ്ട് അൺലോക്ക് ചെയ്യൂ"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"പാസ്വേഡ്/വിരലടയാളം കൊണ്ട് അൺലോക്ക് ചെയ്യൂ"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"പാറ്റേൺ/വിരലടയാളം കൊണ്ട് അൺലോക്ക് ചെയ്യൂ"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"അധിക സുരക്ഷയ്ക്ക്, ഔദ്യോഗിക നയം ഉപകരണം ലോക്ക് ചെയ്തു"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ലോക്ക്ഡൗണിന് ശേഷം പിൻ നൽകേണ്ടതുണ്ട്"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ലോക്ക്ഡൗണിന് ശേഷം പാസ്വേഡ് നൽകേണ്ടതുണ്ട്"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ലോക്ക്ഡൗണിന് ശേഷം പാറ്റേൺ വരയ്ക്കേണ്ടതുണ്ട്"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"സജീവമല്ലാത്ത സമയത്ത് അപ്ഡേറ്റ് ഇൻസ്റ്റാൾ ചെയ്യും"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"അധിക സുരക്ഷ വേണം. അൽപകാലം പിൻ ഉപയോഗിച്ചില്ല."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"അധിക സുരക്ഷ വേണം. അൽപകാലം പാസ്വേഡ് ഉപയോഗിച്ചില്ല."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"അധിക സുരക്ഷ വേണം. അൽപകാലം പാറ്റേൺ ഉപയോഗിച്ചില്ല."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"അധിക സുരക്ഷ വേണം. ഡിവൈസ് അൽപകാലം അൺലോക്ക് ചെയ്തില്ല."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് സാധ്യമല്ല. നിരവധി ശ്രമങ്ങൾ."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ഫിംഗർപ്രിന്റ് അൺലോക്ക് സാധ്യമല്ല. നിരവധി ശ്രമങ്ങൾ."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"വിശ്വസ്ത ഏജന്റ് ലഭ്യമല്ല"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"തെറ്റായ പിൻ ഉപയോഗിച്ച് നിരവധി ശ്രമങ്ങൾ"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"തെറ്റായ പാറ്റേൺ ഉപയോഗിച്ച് നിരവധി ശ്രമങ്ങൾ"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"തെറ്റായ പാസ്വേഡ് ഉപയോഗിച്ച് നിരവധി ശ്രമങ്ങൾ"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക.}other{# സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"സിം പിൻ നൽകുക."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" എന്ന കാരിയർക്കുള്ള സിം പിൻ നൽകുക."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"PUK ഉപയോഗിച്ച് സിം അൺലോക്കുചെയ്യാനുള്ള ശ്രമം പരാജയപ്പെട്ടു!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ഇൻപുട്ട് രീതി മാറുക"</string> <string name="airplane_mode" msgid="2528005343938497866">"ഫ്ലൈറ്റ് മോഡ്"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ഉപകരണം റീസ്റ്റാർട്ട് ചെയ്ത ശേഷം പാറ്റേൺ വരയ്ക്കണം"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ഉപകരണം റീസ്റ്റാർട്ട് ചെയ്ത ശേഷം പിൻ നൽകണം"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ഉപകരണം റീസ്റ്റാർട്ട് ചെയ്ത ശേഷം പാസ്വേഡ് നൽകണം"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"അധിക സുരക്ഷയ്ക്കായി, പകരം പാറ്റേൺ ഉപയോഗിക്കുക"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"അധിക സുരക്ഷയ്ക്കായി, പകരം പിൻ ഉപയോഗിക്കുക"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"അധിക സുരക്ഷയ്ക്കായി, പകരം പാസ്വേഡ് ഉപയോഗിക്കുക"</string> diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml index d4d84b0acd2e..eefc4919420e 100644 --- a/packages/SystemUI/res-keyguard/values-mn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"ПИН-ээ оруулна уу"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"ПИН оруулах"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Хээгээ оруулна уу"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Хээ зурах"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Нууц үгээ оруулна уу"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Нууц үг оруулах"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Карт хүчингүй байна."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Цэнэглэсэн"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Утасгүй цэнэглэж байна"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Алдаа гарсан тул eSIM-г идэвхгүй болгох боломжгүй байна."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Оруулах"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Хээ буруу байна"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Хээ буруу. Ахин оролд."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Нууц үг буруу байна"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Нууц үг буруу. Ахин оролд."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ПИН код буруу байна"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"ПИН буруу. Ахин оролд."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Эсвэл хурууны хээгээр түгжээг тайл"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Хурууны хээг таньсангүй"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Царайг таньсангүй"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Дахин оролдох эсвэл ПИН оруулна уу"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Дахин оролдох эсвэл нууц үг оруулна уу"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Дахин оролдох эсвэл хээ зурна уу"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Хэт олон оролдлогын дараа ПИН шаардлагатай"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Хэт олон оролдлогын дараа нууц үг шаардлагатай"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Хэт олон оролдлогын дараа хээ шаардлагатай"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"ПИН эсвэл хурууны хээгээр түгжээ тайл"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Нууц үг эсвэл хурууны хээгээр түгжээ тайл"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Хээ эсвэл хурууны хээгээр түгжээ тайл"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Нэмэлт аюулгүй байдлын үүднээс төхөөрөмжийг ажлын бодлогын дагуу түгжсэн"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Түгжсэний дараа ПИН шаардлагатай"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Түгжсэний дараа нууц үг шаардлагатай"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Түгжсэний дараа хээ шаардлагатай"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Шинэчлэлтийг идэвхгүй цагуудаар суулгана"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Нэмэлт аюулгүй байдал шаардлагатай. ПИН-г хэсэг хугацаанд ашиглаагүй."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Нэмэлт аюулгүй байдал шаардлагатай. Нууц үгийг хэсэг хугацаанд ашиглаагүй."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Нэмэлт аюулгүй байдал шаардлагатай. Хээг хэсэг хугацаанд ашиглаагүй."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Нэмэлт аюулгүй байдал шаардлагатай. Төхөөрөмжийн түгжээг хэсэг хугацаанд тайлаагүй."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Царайгаар түгжээг тайлах боломжгүй. Хэт олон оролдлоо"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Хурууны хээгээр түгжээг тайлах боломжгүй. Хэт олон оролдлоо"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Итгэмжлэгдсэн агент боломжгүй байна"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Буруу ПИН-ээр хэт олон удаа оролдсон"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Буруу хээгээр хэт олон удаа оролдсон"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Буруу нууц үгээр хэт олон удаа оролдсон"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# секундийн дараа дахин оролдоно уу.}other{# секундийн дараа дахин оролдоно уу.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM-н ПИН-г оруулна уу."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\"-н SIM-н ПИН-г оруулна уу."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-н PUK-г буруу орууллаа!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Оруулах аргыг сэлгэх"</string> <string name="airplane_mode" msgid="2528005343938497866">"Нислэгийн горим"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Төхөөрөмжийг дахин эхлүүлсний дараа хээ шаардлагатай"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Төхөөрөмжийг дахин эхлүүлсний дараа ПИН шаардлагатай"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Төхөөрөмжийг дахин эхлүүлсний дараа нууц үг шаардлагатай"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Нэмэлт аюулгүй байдлын үүднээс оронд нь хээ ашиглана уу"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Нэмэлт аюулгүй байдлын үүднээс оронд нь ПИН ашиглана уу"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Нэмэлт аюулгүй байдлын үүднээс оронд нь нууц үг ашиглана уу"</string> diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml index 8f9d4a04add3..76494f008d7b 100644 --- a/packages/SystemUI/res-keyguard/values-mr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"तुमचा पिन एंटर करा"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"पिन एंटर करा"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"तुमचा पॅटर्न एंटर करा"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"पॅटर्न ड्रॉ करा"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"तुमचा पासवर्ड एंटर करा"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"पासवर्ड एंटर करा"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"अवैध कार्ड."</string> <string name="keyguard_charged" msgid="5478247181205188995">"चार्ज झाली"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • वायरलेस पद्धतीने चार्ज करत आहे"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"एका एररमुळे eSIM बंद होऊ शकत नाही."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"एंटर करा"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"चुकीचा पॅटर्न"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"पॅटर्न चुकीचा आहे. पुन्हा प्रयत्न करा."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"चुकीचा पासवर्ड"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"पासवर्ड चुकीचा आहे. पुन्हा प्रयत्न करा."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"चुकीचा पिन"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"पिन चुकीचा आहे. पुन्हा प्रयत्न करा."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"किंवा फिंगरप्रिंट वापरून अनलॉक करा"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"फिंगरप्रिंट ओळखले नाही"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"चेहरा ओळखता आला नाही"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"पुन्हा प्रयत्न करा किंवा पिन एंटर करा"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"पुन्हा प्रयत्न करा किंवा पासवर्ड एंटर करा"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"पुन्हा प्रयत्न करा किंवा पॅटर्न ड्रॉ करा"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"अनेक वेळा प्रयत्न केल्यानंतर पिन आवश्यक आहे"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"अनेक वेळा प्रयत्न केल्यानंतर पासवर्ड आवश्यक आहे"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"अनेक वेळा प्रयत्न केल्यानंतर पॅटर्न आवश्यक आहे"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"पिन किंवा फिंगरप्रिंट वापरून अनलॉक करा"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"पासवर्ड किंवा फिंगरप्रिंट वापरून अनलॉक करा"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"पॅटर्न किंवा फिंगरप्रिंट वापरून अनलॉक करा"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"अतिरिक्त सुरक्षेसाठी, कामाशी संबंधित धोरणाद्वारे डिव्हाइस लॉक केला होता"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"लॉकडाउननंतर पिन आवश्यक आहे"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"लॉकडाउननंतर पासवर्ड आवश्यक आहे"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"लॉकडाउननंतर पॅटर्न आवश्यक आहे"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"अपडेट हे इनॅक्टिव्ह तासांदरम्यान इंस्टॉल होईल"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"अतिरिक्त सुरक्षा आवश्यक आहे. काही वेळेसाठी पिन अनलॉक केला गेला नव्हता."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"अतिरिक्त सुरक्षा आवश्यक आहे. काही वेळेसाठी पासवर्ड अनलॉक केला गेला नव्हता."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"अतिरिक्त सुरक्षा आवश्यक आहे. काही वेळेसाठी पॅटर्न अनलॉक केला गेला नव्हता."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"अतिरिक्त सुरक्षा आवश्यक आहे. काही वेळेसाठी डिव्हाइस अनलॉक केले गेले नव्हते."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"चेहरा वापरून अनलॉक करू शकत नाही. खूप जास्त प्रयत्न."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"फिंगरप्रिंट वापरून अनलॉक करू शकत नाही. खूप जास्त प्रयत्न."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"विश्वसनीय एजंट उपलब्ध नाही"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"चुकीचा पिन वापरून खूप जास्त प्रयत्न केले"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"चुकीचा पॅटर्न वापरून खूप जास्त प्रयत्न केले"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"चुकीचा पासवर्ड वापरून खूप जास्त प्रयत्न केले"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# सेकंदामध्ये पुन्हा प्रयत्न करा.}other{# सेकंदांमध्ये पुन्हा प्रयत्न करा.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"सिम पिन एंटर करा"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" साठी सिम पिन एंटर करा"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"सिम PUK कार्य अयशस्वी झाले!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"इनपुट पद्धत स्विच करा"</string> <string name="airplane_mode" msgid="2528005343938497866">"विमान मोड"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"डिव्हाइस रीस्टार्ट झाल्यानंतर पॅटर्न आवश्यक आहे"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"डिव्हाइस रीस्टार्ट झाल्यानंतर पिन आवश्यक आहे"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"डिव्हाइस रीस्टार्ट झाल्यानंतर पासवर्ड आवश्यक आहे"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"अतिरिक्त सुरक्षेसाठी, त्याऐवजी पॅटर्न वापरा"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"अतिरिक्त सुरक्षेसाठी, त्याऐवजी पिन वापरा"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"अतिरिक्त सुरक्षेसाठी, त्याऐवजी पासवर्ड वापरा"</string> diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml index c0ebce28b4e8..b063471ef28f 100644 --- a/packages/SystemUI/res-keyguard/values-ms/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Masukkan PIN anda"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Masukkan PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Masukkan corak anda"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Lukis corak"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Masukkan kata laluan anda"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Masukkan kata laluan"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Kad Tidak Sah."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Sudah dicas"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas secara wayarles"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM tidak dapat dilumpuhkan kerana ralat."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Kekunci Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Corak salah"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Corak salah. Cuba lagi."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Kata laluan salah"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Kata laluan salah. Cuba lagi."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN salah"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN salah. Cuba lagi."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Atau buka kunci dengan cap jari"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Cap jari tidak dikenali"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Wajah tidak dikenali"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Cuba lagi atau masukkan PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Cuba lagi atau masukkan kata laluan"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Cuba lagi atau lukis corak"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN diperlukan selepas terlalu banyak percubaan"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Kata laluan diperlukan selepas terlalu banyak percubaan"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Corak diperlukan selepas terlalu banyak percubaan"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Buka kunci dengan PIN/cap jari"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Buka kunci dengan kata laluan atau cap jari"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Buka kunci dengan corak/cap jari"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Untuk keselamatan, peranti dikunci oleh dasar kerja"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN diperlukan selepas kunci semua"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Kata laluan diperlukan selepas kunci semua"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Corak diperlukan selepas kunci semua"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Kemaskinian akan dipasang semasa waktu tidak aktif"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Keselamatan tambahan diperlukan. PIN tidak digunakan."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Keselamatan tambahan diperlukan. Kata laluan tidak digunakan."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Keselamatan tambahan diperlukan. Corak tidak digunakan."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Keselamatan tambahan diperlukan. Peranti berkunci untuk seketika."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Gagal membuka dengan wajah. Terlalu banyak percubaan."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Gagal membuka dengan cap jari. Terlalu banyak percubaan."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Ejen amanah tidak tersedia"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Terlalu banyak percubaan dengan PIN yang salah"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Terlalu banyak percubaan dengan corak yang salah"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Terlalu banyak percubaan dengan kata laluan yang salah"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Cuba lagi dalam # saat.}other{Cuba lagi dalam # saat.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Masukkan PIN SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Masukkan PIN SIM untuk \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Pengendalian PUK SIM gagal!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Tukar kaedah masukan"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mod Pesawat"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Corak diperlukan selepas peranti mula semula"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN diperlukan selepas peranti mula semula"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Kata laluan diperlukan selepas peranti mula semula"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Untuk keselamatan tambahan, gunakan corak"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Untuk keselamatan tambahan, gunakan PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Untuk keselamatan tambahan, gunakan kata laluan"</string> diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml index 53035a4a4939..de1da843c4cc 100644 --- a/packages/SystemUI/res-keyguard/values-my/strings.xml +++ b/packages/SystemUI/res-keyguard/values-my/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"သင့်ပင်နံပါတ် ထည့်ပါ"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"ပင်နံပါတ်ထည့်ပါ"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"သင့်လော့ခ်ဖွင့်ပုံစံ ထည့်ပါ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ပုံစံဆွဲပါ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"သင့်စကားဝှက် ထည့်ပါ"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"စကားဝှက် ထည့်ပါ"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ကတ် မမှန်ကန်ပါ။"</string> <string name="keyguard_charged" msgid="5478247181205188995">"အားသွင်းပြီးပါပြီ"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ကြိုးမဲ့ အားသွင်းနေသည်"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"အမှားအယွင်းရှိနေသောကြောင့် eSIM ကို ပိတ်၍မရပါ။"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter ခလုတ်"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"လော့ခ်ဖွင့်ပုံစံ မှားနေသည်"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ပုံစံအမှား။ ထပ်စမ်းပါ။"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"စကားဝှက် မှားနေသည်"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"စကားဝှက်အမှား။ ထပ်စမ်းပါ။"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ပင်နံပါတ် မမှန်ကန်ပါ"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"ပင်နံပါတ်အမှား။ ထပ်စမ်းပါ။"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"သို့မဟုတ် လက်ဗွေဖြင့် ဖွင့်ပါ"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"လက်ဗွေကို မသိရှိပါ"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"မျက်နှာကို မသိရှိပါ"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ထပ်စမ်းကြည့်ပါ (သို့) ပင်နံပါတ်ထည့်ပါ"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ထပ်စမ်းကြည့်ပါ (သို့) စကားဝှက်ထည့်ပါ"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ထပ်စမ်းကြည့်ပါ (သို့) ပုံစံဆွဲပါ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"ကြိုးပမ်းမှုအကြိမ်ရေ များလွန်း၍ ပင်နံပါတ်လိုအပ်သည်"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"ကြိုးပမ်းမှုအကြိမ်ရေ များလွန်း၍ စကားဝှက်လိုအပ်သည်"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"ကြိုးပမ်းမှုအကြိမ်ရေ များလွန်း၍ ပုံဖော်ခြင်းလိုအပ်သည်"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"ပင်နံပါတ် (သို့) လက်ဗွေဖြင့် ဖွင့်ပါ"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"စကားဝှက် (သို့) လက်ဗွေဖြင့် ဖွင့်ပါ"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ပုံဖော်ခြင်း (သို့) လက်ဗွေဖြင့် ဖွင့်ပါ"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"ထပ်ဆောင်းလုံခြုံရေးအတွက် စက်ကို အလုပ်ခွင်မူဝါဒက ပိတ်လိုက်သည်"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"လော့ခ်ဒေါင်းလုပ်ပြီးနောက် ပင်နံပါတ်လိုအပ်သည်"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"လော့ခ်ဒေါင်းလုပ်ပြီးနောက် စကားဝှက်လိုအပ်သည်"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"လော့ခ်ဒေါင်းလုပ်ပြီးနောက် ပုံဖော်ခြင်းလိုအပ်သည်"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"မသုံးသည့်အချိန်အတွင်း အပ်ဒိတ်ထည့်သွင်းမည်"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ထပ်ဆောင်းလုံခြုံရေး လိုအပ်သည်။ ပင်နံပါတ်မသုံးသည်မှာ အနည်းငယ်ကြာပြီ။"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ထပ်ဆောင်းလုံခြုံရေး လိုအပ်သည်။ စကားဝှက်မသုံးသည်မှာ အနည်းငယ်ကြာပြီ။"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ထပ်ဆောင်းလုံခြုံရေး လိုအပ်သည်။ ပုံဖော်ခြင်းမသုံးသည်မှာ အနည်းငယ်ကြာပြီ။"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"ထပ်ဆောင်းလုံခြုံရေး လိုအပ်သည်။ စက်မဖွင့်သည်မှာ အနည်းငယ်ကြာပြီ။"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"မျက်နှာဖြင့် ဖွင့်၍မရပါ။ ကြိုးပမ်းမှုအကြိမ်ရေ များလွန်းသည်။"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"လက်ဗွေဖြင့် ဖွင့်၍မရပါ။ ကြိုးပမ်းမှုအကြိမ်ရေ များလွန်းသည်။"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ယုံကြည်မှု အေးဂျင့်ကို မရနိုင်ပါ"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ပင်နံပါတ် မှားသည့်အကြိမ်ရေ များလွန်းသည်"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ပုံဖော်ခြင်း မှားသည့်အကြိမ်ရေ များလွန်းသည်"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"စကားဝှက် မှားသည့်အကြိမ်ရေ များလွန်းသည်"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်နိုင်သည်။}other{# စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်နိုင်သည်။}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"ဆင်းမ်ကတ် ပင်နံပါတ်ကို ထည့်ပါ။"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" အတွက် ဆင်းမ်ကဒ်ပင်နံပါတ်ကို ထည့်ပါ။"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"ဆင်းမ်ကတ် ပင်နံပါတ် ပြန်ဖွင့်သည့်ကုဒ် လုပ်ဆောင်ချက် မအောင်မြင်ပါ။"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"စာရိုက်စနစ်ပြောင်းရန်"</string> <string name="airplane_mode" msgid="2528005343938497866">"လေယာဉ်ပျံမုဒ်"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"စက်ကို ပြန်စပြီးနောက် ပုံဖော်ခြင်းလိုအပ်သည်"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"စက်ကို ပြန်စပြီးနောက် ပင်နံပါတ်လိုအပ်သည်"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"စက်ကို ပြန်စပြီးနောက် စကားဝှက်လိုအပ်သည်"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား ပုံစံသုံးပါ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား ပင်နံပါတ်သုံးပါ"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား စကားဝှက်သုံးပါ"</string> diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml index 13e5ffaf5d74..501d83637bc8 100644 --- a/packages/SystemUI/res-keyguard/values-nb/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Skriv inn PIN-koden din"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Skriv inn PIN-koden"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Legg inn mønsteret ditt"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Tegn mønsteret"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Skriv inn passordet ditt"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Skriv inn passordet"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ugyldig kort."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Oppladet"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lader trådløst"</string> @@ -58,68 +55,38 @@ <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> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Feil mønster. Prøv igjen."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Feil passord"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Feil passord. Prøv igjen."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Feil PIN-kode"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Feil PIN-kode. Prøv igjen."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Eller lås opp med fingeravtrykk"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Gjenkjenner ikke avtrykket"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Gjenkjenner ikke ansiktet"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Prøv på nytt eller skriv inn PIN-koden"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Prøv på nytt eller skriv inn passordet"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Prøv på nytt eller tegn mønsteret"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN-koden kreves etter for mange forsøk"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Passordet kreves etter for mange forsøk"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Mønsteret kreves etter for mange forsøk"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Lås opp med PIN-kode eller fingeravtrykk"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Lås opp med passord eller fingeravtrykk"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Lås opp med mønster eller fingeravtrykk"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"For økt sikkerhet ble enheten låst med jobbregler"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN-koden kreves etter låsing"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Passordet kreves etter låsing"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mønsteret kreves etter låsing"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Oppdateringen installeres når enheten er inaktiv"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Økt sikkerhet kreves. Har ikke brukt PIN-koden nylig"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Økt sikkerhet kreves. Har ikke brukt passordet nylig"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Økt sikkerhet kreves. Har ikke brukt mønsteret nylig"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Økt sikkerhet kreves. Har ikke låst opp enhet nylig."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Kan ikke låse opp med ansiktet. For mange forsøk."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Kan ikke låse opp med fingeravtrykk For mange forsøk"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Den pålitelige agenten er utilgjengelig"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"For mange forsøk med feil PIN-kode"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"For mange forsøk med feil mønster"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"For mange forsøk med feil passord"</string> <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> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"PUK-koden for SIM-kortet ble avvist."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Bytt inndatametode"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flymodus"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Mønsteret kreves etter at enheten startes på nytt"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN-koden kreves etter at enheten startes på nytt"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Passordet kreves etter at enheten startes på nytt"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Bruk mønster i stedet, for å øke sikkerheten"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Bruk PIN-kode i stedet, for å øke sikkerheten"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Bruk passord i stedet, for å øke sikkerheten"</string> diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index 8dc8ff0422a4..4b215ae4aaf1 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"आफ्नो PIN प्रविष्टि गर्नुहोस्"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN हाल्नुहोस्"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"आफ्नो ढाँचा प्रविष्टि गर्नुहोस्"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"प्याटर्न कोर्नुहोस्"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"आफ्नो पासवर्ड प्रविष्ट गर्नु…"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"पासवर्ड हाल्नुहोस्"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"अमान्य कार्ड।"</string> <string name="keyguard_charged" msgid="5478247181205188995">"चार्ज भयो"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • तारविनै चार्ज गर्दै"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"कुनै त्रुटिका कारण यो eSIM लाई असक्षम पार्न सकिएन।"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"प्रविष्टि गर्नुहोस्"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"प्याटर्न मिलेन"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"प्याटर्न मिलेन। फेरि प्रयास गर्नुहोस्।"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"गलत पासवर्ड"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"पासवर्ड मिलेन। फेरि प्रयास गर्नुहोस्।"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"गलत PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN मिलेन। फेरि प्रयास गर्नुहोस्।"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"वा फिंगरप्रिन्ट प्रयोग गरी अनलक गर्नुहोस्"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"फिंगरप्रिन्ट पहिचान गर्न सकिएन"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"अनुहार पहिचान गर्न सकिएन"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"फेरि प्रयास गर्नुहोस् वा PIN हाल्नुहोस्"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"फेरि प्रयास गर्नुहोस् वा पासवर्ड हाल्नुहोस्"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"फेरि प्रयास गर्नुहोस् वा प्याटर्न कोर्नुहोस्"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"अत्यन्तै धेरै पटक प्रयास गरिसकेपछि PIN हाल्नु पर्ने हुन्छ"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"अत्यन्तै धेरै पटक प्रयास गरिसकेपछि पासवर्ड हाल्नु पर्ने हुन्छ"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"अत्यन्तै धेरै पटक प्रयास गरिसकेपछि प्याटर्न कोर्नु पर्ने हुन्छ"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN वा फिंगरप्रिन्ट प्रयोग गरी अनलक गर्नुहोस्"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"पासवर्ड वा फिंगरप्रिन्ट प्रयोग गरी अनलक गर्नुहोस्"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"प्याटर्न वा फिंगरप्रिन्ट प्रयोग गरी अनलक गर्नुहोस्"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"थप सुरक्षाका लागि कामसम्बन्धी नीतिका अनुसार डिभाइस लक गरियो"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"लकडाउन गरेपछि PIN हाल्नु पर्ने हुन्छ"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"लकडाउन गरेपछि पासवर्ड हाल्नु पर्ने हुन्छ"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"लकडाउन गरेपछि प्याटर्न कोर्नु पर्ने हुन्छ"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"डिभाइस प्रयोग नभएका बेला अपडेट इन्स्टल हुने छ"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"थप सुरक्षित बनाउनु पर्ने हुन्छ। केही समयदेखि PIN प्रयोग गरिएको छैन।"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"थप सुरक्षित बनाउनु पर्ने हुन्छ। केही समयदेखि पासवर्ड प्रयोग गरिएको छैन।"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"थप सुरक्षित बनाउनु पर्ने हुन्छ। केही समयदेखि प्याटर्न प्रयोग गरिएको छैन।"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"थप सुरक्षित बनाउनु पर्ने हुन्छ। केही समयदेखि डिभाइस अनलक गरिएको छैन।"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"अनुहार प्रयोग गरी अनलक गर्न सकिएन। अत्यन्तै धेरै पटक प्रयास गरिसकियो।"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"फिंगरप्रिन्ट प्रयोग गरी अनलक गर्न सकिएन। अत्यन्तै धेरै पटक प्रयास गरिसकियो।"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ट्रस्ट एजेन्ट उपलब्ध छैन"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"अत्यन्तै धेरै पटक गलत PIN हालियो"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"अत्यन्तै धेरै पटक गलत प्याटर्न कोरियो"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"अत्यन्तै धेरै पटक गलत पासवर्ड हालियो"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# सेकेन्डपछि फेरि प्रयास गर्नुहोस्।}other{# सेकेन्डपछि फेरि प्रयास गर्नुहोस्।}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM को PIN प्रविष्टि गर्नुहोस्।"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" को SIM को PIN प्रविष्टि गर्नुहोस्।"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM को PUK कोड राखेर अनलक गर्ने कार्य असफल भयो!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"इनपुट विधिलाई स्विच गर्नुहोस्"</string> <string name="airplane_mode" msgid="2528005343938497866">"हवाइजहाज मोड"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"डिभाइस रिस्टार्ट भएपछि प्याटर्न कोर्नु पर्ने हुन्छ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"डिभाइस रिस्टार्ट भएपछि PIN हाल्नु पर्ने हुन्छ"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"डिभाइस रिस्टार्ट भएपछि पासवर्ड हाल्नु पर्ने हुन्छ"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो प्याटर्न प्रयोग गर्नुहोस्"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो पिन प्रयोग गर्नुहोस्"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो पासवर्ड प्रयोग गर्नुहोस्"</string> diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml index af6d4773854d..9b8b72d3367a 100644 --- a/packages/SystemUI/res-keyguard/values-nl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Geef je pincode op"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Geef de pincode op"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Geef je patroon op"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Teken het patroon"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Geef je wachtwoord op"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Geef het wachtwoord op"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ongeldige kaart."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Opgeladen"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Draadloos opladen"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"De e-simkaart kan niet worden uitgezet vanwege een fout."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Onjuist patroon"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Onjuist patroon. Probeer het opnieuw."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Onjuist wachtwoord"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Onjuist wachtwoord. Probeer het opnieuw."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Onjuiste pincode"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Onjuiste pincode. Probeer het opnieuw."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Of ontgrendel met vingerafdruk"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Vingerafdruk niet herkend"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Gezicht niet herkend"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Probeer het opnieuw of geef de pincode op"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Probeer het opnieuw of geef het wachtwoord op"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Probeer het opnieuw of teken het patroon"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Na te veel pogingen is de pincode vereist"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Na te veel pogingen is het wachtwoord vereist"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Na te veel pogingen is het patroon vereist"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Ontgrendel met pincode/vingerafdruk"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Ontgrendel met wachtwoord/vingerafdruk"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Ontgrendel met patroon/vingerafdruk"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Vergrendeld door werkbeleid voor extra beveiliging"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Na lockdown is de pincode vereist"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Na lockdown is het wachtwoord vereist"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Na lockdown is het patroon vereist"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Update wordt geïnstalleerd tijdens inactieve uren"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Extra beveiliging. Pincode is lang niet gebruikt."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Extra beveiliging. Wachtwoord is lang niet gebruikt."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Extra beveiliging. Patroon is lang niet gebruikt."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Extra beveiliging vereist. Apparaat is lang niet ontgrendeld."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Kan niet ontgrendelen met gezicht. Te veel pogingen."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Niet ontgrendeld met vingerafdruk. Te veel pogingen."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Trust agent is niet beschikbaar"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Te veel pogingen met onjuiste pincode"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Te veel pogingen met onjuist patroon"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Te veel pogingen met onjuist wachtwoord"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Probeer het over # seconde opnieuw.}other{Probeer het over # seconden opnieuw.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Geef de pincode van de simkaart op."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Geef de pincode voor de simkaart van \'<xliff:g id="CARRIER">%1$s</xliff:g>\' op."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Bewerking met pukcode voor simkaart is mislukt."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Invoermethode wijzigen"</string> <string name="airplane_mode" msgid="2528005343938497866">"Vliegtuigmodus"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Patroon is vereist na opnieuw opstarten apparaat"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Pincode is vereist na opnieuw opstarten apparaat"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Wachtwoord is vereist na opnieuw opstarten apparaat"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik in plaats daarvan het patroon voor extra beveiliging"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik in plaats daarvan de pincode voor extra beveiliging"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik in plaats daarvan het wachtwoord voor extra beveiliging"</string> diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml index a1a6ab2d6981..83dabae7bf00 100644 --- a/packages/SystemUI/res-keyguard/values-or/strings.xml +++ b/packages/SystemUI/res-keyguard/values-or/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"ନିଜର PIN ଲେଖନ୍ତୁ"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN ଲେଖନ୍ତୁ"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"ନିଜର ପାଟର୍ନ ଆଙ୍କନ୍ତୁ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ପାଟର୍ନ ଡ୍ର କରନ୍ତୁ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"ନିଜ ପାସ୍ୱର୍ଡ ଲେଖନ୍ତୁ"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"ପାସୱାର୍ଡ ଲେଖନ୍ତୁ"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ଅମାନ୍ୟ କାର୍ଡ।"</string> <string name="keyguard_charged" msgid="5478247181205188995">"ଚାର୍ଜ ହୋଇଗଲା"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"ୱାୟାର୍ଲେସ୍ଭାବରେ <xliff:g id="PERCENTAGE">%s</xliff:g> • ଚାର୍ଜ ହୋଇଛି"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"ଗୋଟିଏ ତ୍ରୁଟି କାରଣରୁ eSIMକୁ ଅକ୍ଷମ କରାଯାଇପାରିବ ନାହିଁ।"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"ଏଣ୍ଟର୍"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"ଭୁଲ ପାଟର୍ନ"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ଭୁଲ ପାଟର୍ନ। ପୁଣିଚେଷ୍ଟା କର।"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"ଭୁଲ ପାସ୍ୱର୍ଡ"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"ଭୁଲ ପାସୱାର୍ଡ। ପୁଣି ଚେଷ୍ଟା କର।"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ଭୁଲ PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"ଭୁଲ PIN। ପୁଣି ଚେଷ୍ଟା କର।"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"କିମ୍ବା ଟିପଚିହ୍ନ ମାଧ୍ୟମରେ ଅନଲକ କରନ୍ତୁ"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ଟିପଚିହ୍ନ ଚିହ୍ନଟ ହେଲା ନାହିଁ"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ଫେସ ଚିହ୍ନଟ କରାଯାଇନାହିଁ"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ କିମ୍ବା PIN ଲେଖନ୍ତୁ"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ କିମ୍ବା ପାସୱାର୍ଡ ଲେଖନ୍ତୁ"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ କିମ୍ବା ପାଟର୍ନ ଡ୍ର କରନ୍ତୁ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା ପରେ PIN ଆବଶ୍ୟକ"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା ପରେ ପାସୱାର୍ଡ ଆବଶ୍ୟକ"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା ପରେ ପାଟର୍ନ ଆବଶ୍ୟକ"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN ବା ଟିପଚିହ୍ନ ଜରିଆରେ ଅନଲକ କର"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"ପାସୱାର୍ଡ ବା ଟିପଚିହ୍ନ ଜରିଆରେ ଅନଲକ କର"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ପାଟର୍ନ ବା ଟିପଚିହ୍ନ ଜରିଆରେ ଅନଲକ କର"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"ସୁରକ୍ଷା ପାଇଁ କାର୍ଯ୍ୟ ନୀତି ଅନୁସାରେ ଡିଭାଇସ ଲକ ହୋଇଛି"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ଲକଡାଉନ ହେବା ପରେ PIN ଆବଶ୍ୟକ"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ଲକଡାଉନ ହେବା ପରେ ପାସୱାର୍ଡ ଆବଶ୍ୟକ"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ଲକଡାଉନ ହେବା ପରେ ପାଟର୍ନ ଆବଶ୍ୟକ"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"ନିଷ୍କ୍ରିୟ ସମୟରେ ଅପଡେଟ ଇନଷ୍ଟଲ ହେବ"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ଆବଶ୍ୟକ। କିଛି ସମୟ ପାଇଁ PIN ବ୍ୟବହାର କରାଯାଇନାହିଁ।"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ଆବଶ୍ୟକ। କିଛି ସମୟ ପାଇଁ ପାସୱାର୍ଡ ବ୍ୟବହାର କରାଯାଇନାହିଁ।"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ଆବଶ୍ୟକ। କିଛି ସମୟ ପାଇଁ ପାଟର୍ନ ବ୍ୟବହାର କରାଯାଇନାହିଁ।"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ଆବଶ୍ୟକ। କିଛି ସମୟ ପାଇଁ ଡିଭାଇସ ଅନଲକ କରାଯାଇନାହିଁ।"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"ଫେସ ଜରିଆରେ ଅନଲକ କରିହେବ ନାହିଁ। ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା।"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ଟିପଚିହ୍ନ ସହ ଅନଲକ କରିହେବ ନାହିଁ। ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା।"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ଟ୍ରଷ୍ଟ ଏଜେଣ୍ଟ ଉପଲବ୍ଧ ନାହିଁ"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ଭୁଲ PIN ସହ ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା କରାଯାଇଛି"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ଭୁଲ ପାଟର୍ନ ସହ ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା କରାଯାଇଛି"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ଭୁଲ ପାସୱାର୍ଡ ସହ ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା କରାଯାଇଛି"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।}other{# ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIMର PIN ଲେଖନ୍ତୁ।"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" ପାଇଁ SIMର PIN ଲେଖନ୍ତୁ।"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUKର କାମ ବିଫଳ ହେଲା!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ଇନପୁଟ୍ ପଦ୍ଧତି ବଦଳାନ୍ତୁ"</string> <string name="airplane_mode" msgid="2528005343938497866">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ଡିଭାଇସ ରିଷ୍ଟାର୍ଟ ହେବା ପରେ ପାଟର୍ନ ଆବଶ୍ୟକ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ଡିଭାଇସ ରିଷ୍ଟାର୍ଟ ହେବା ପରେ PIN ଆବଶ୍ୟକ"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ଡିଭାଇସ ରିଷ୍ଟାର୍ଟ ହେବା ପରେ ପାସୱାର୍ଡ ଆବଶ୍ୟକ"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ, ଏହା ପରିବର୍ତ୍ତେ ପାଟର୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ, ଏହା ପରିବର୍ତ୍ତେ PIN ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ, ଏହା ପରିବର୍ତ୍ତେ ପାସୱାର୍ଡ ବ୍ୟବହାର କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml index 61eeb49602d5..67ba3ef1e7b2 100644 --- a/packages/SystemUI/res-keyguard/values-pa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"ਆਪਣਾ ਪਿੰਨ ਦਾਖਲ ਕਰੋ"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"ਪਿੰਨ ਦਾਖਲ ਕਰੋ"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"ਆਪਣਾ ਪੈਟਰਨ ਦਾਖਲ ਕਰੋ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ਪੈਟਰਨ ਬਣਾਓ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"ਆਪਣਾ ਪਾਸਵਰਡ ਦਾਖਲ ਕਰੋ"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"ਪਾਸਵਰਡ ਦਾਖਲ ਕਰੋ"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ਅਵੈਧ ਕਾਰਡ।"</string> <string name="keyguard_charged" msgid="5478247181205188995">"ਚਾਰਜ ਹੋ ਗਿਆ"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਬਿਨਾਂ ਤਾਰ ਤੋਂ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"ਕੋਈ ਗੜਬੜ ਹੋਣ ਕਰਕੇ ਈ-ਸਿਮ ਬੰਦ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"ਦਾਖਲ ਕਰੋ"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"ਗਲਤ ਪੈਟਰਨ"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ਗਲਤ ਪੈਟਰਨ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"ਗਲਤ ਪਾਸਵਰਡ"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"ਗਲਤ ਪਾਸਵਰਡ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"ਗਲਤ ਪਿੰਨ"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"ਗਲਤ ਪਿੰਨ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"ਜਾਂ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਣਲਾਕ ਕਰੋ"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜਾਂ ਪਿੰਨ ਦਾਖਲ ਕਰੋ"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜਾਂ ਪਾਸਵਰਡ ਦਾਖਲ ਕਰੋ"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜਾਂ ਪੈਟਰਨ ਬਣਾਓ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਅਦ ਪਿੰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਅਦ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਅਦ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"ਪਿੰਨ ਜਾਂ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਣਲਾਕ ਕਰੋ"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"ਪਾਸਵਰਡ ਜਾਂ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਣਲਾਕ ਕਰੋ"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ਪੈਟਰਨ ਜਾਂ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਣਲਾਕ ਕਰੋ"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਲਈ, ਡੀਵਾਈਸ ਕਾਰਜ ਨੀਤੀ ਵੱਲੋਂ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ਲਾਕਡਾਊਨ ਤੋਂ ਬਾਅਦ ਪਿੰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ਲਾਕਡਾਊਨ ਤੋਂ ਬਾਅਦ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ਲਾਕਡਾਊਨ ਤੋਂ ਬਾਅਦ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"ਅੱਪਡੇਟ ਅਕਿਰਿਆਸ਼ੀਲ ਘੰਟਿਆਂ ਦੌਰਾਨ ਸਥਾਪਤ ਹੋਵੇਗਾ"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਦੀ ਲੋੜ ਹੈ। ਪਿੰਨ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਵਰਤਿਆ ਨਹੀਂ ਗਿਆ।"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਦੀ ਲੋੜ ਹੈ। ਪਾਸਵਰਡ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਵਰਤਿਆ ਨਹੀਂ ਗਿਆ।"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਦੀ ਲੋੜ ਹੈ। ਪੈਟਰਨ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਵਰਤਿਆ ਨਹੀਂ ਗਿਆ।"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਦੀ ਲੋੜ ਹੈ। ਡੀਵਾਈਸ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਅਣਲਾਕ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਸੀ।"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"ਚਿਹਰੇ ਨਾਲ ਅਣਲਾਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ।"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਣਲਾਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ।"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ਭਰੋਸੇਯੋਗ ਏਜੰਟ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ਗਲਤ ਪਿੰਨ ਨਾਲ ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ਗਲਤ ਪੈਟਰਨ ਨਾਲ ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ਗਲਤ ਪਾਸਵਰਡ ਨਾਲ ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# ਸਕਿੰਟ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।}one{# ਸਕਿੰਟ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।}other{# ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"ਸਿਮ ਪਿੰਨ ਦਾਖਲ ਕਰੋ।"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" ਲਈ ਸਿਮ ਪਿੰਨ ਦਾਖਲ ਕਰੋ।"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK ਕਾਰਵਾਈ ਅਸਫਲ ਰਹੀ!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ਇਨਪੁੱਟ ਵਿਧੀ ਸਵਿੱਚ ਕਰੋ"</string> <string name="airplane_mode" msgid="2528005343938497866">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ਡੀਵਾਈਸ ਮੁੜ-ਸ਼ੁਰੂ ਹੋਣ ਤੋਂ ਬਾਅਦ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ਡੀਵਾਈਸ ਮੁੜ-ਸ਼ੁਰੂ ਹੋਣ ਤੋਂ ਬਾਅਦ ਪਿੰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ਡੀਵਾਈਸ ਮੁੜ-ਸ਼ੁਰੂ ਹੋਣ ਤੋਂ ਬਾਅਦ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ, ਇਸਦੀ ਬਜਾਏ ਪੈਟਰਨ ਵਰਤੋ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ, ਇਸਦੀ ਬਜਾਏ ਪਿੰਨ ਵਰਤੋ"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ, ਇਸਦੀ ਬਜਾਏ ਪਾਸਵਰਡ ਵਰਤੋ"</string> diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml index 6ebc80985a02..1fcde869e124 100644 --- a/packages/SystemUI/res-keyguard/values-pl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Wpisz kod PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Wpisz kod PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Narysuj wzór"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Narysuj wzór"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Wpisz hasło"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Wpisz hasło"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Nieprawidłowa karta."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Naładowana"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ładowanie bezprzewodowe"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Nie można wyłączyć karty eSIM z powodu błędu."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Nieprawidłowy wzór"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Błędny wzór. Spróbuj ponownie."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Nieprawidłowe hasło"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Błędne hasło. Spróbuj ponownie."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Nieprawidłowy kod PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Błędny kod PIN. Spróbuj ponownie."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Lub odblokuj odciskiem palca"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Nie rozpoznano odcisku palca"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Nie rozpoznano twarzy"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Spróbuj ponownie lub wpisz kod PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Spróbuj ponownie lub wpisz hasło"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Spróbuj ponownie lub narysuj wzór"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Po zbyt wielu próbach wymagany jest kod PIN"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Po zbyt wielu próbach wymagane jest hasło"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Po zbyt wielu próbach wymagany jest wzór"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Odblokuj kodem PIN lub odciskiem palca"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Odblokuj hasłem lub odciskiem palca"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Odblokuj wzorem lub odciskiem palca"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Dla bezpieczeństwa zablokowano urządzenie z powodu zasad obowiązujących w firmie"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po zablokowaniu wymagany jest kod PIN"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po zablokowaniu wymagane jest hasło"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po zablokowaniu wymagany jest wzór"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Aktualizacja zainstaluje się w czasie bezczynności"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Wzmocnij ochronę. Od dawna nie używano kodu PIN."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Wzmocnij ochronę. Od dawna nie używano hasła."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Wzmocnij ochronę. Od dawna nie używano wzoru."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Wzmocnij ochronę. Urządzenie było długo nie używane."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nie można odblokować twarzą. Zbyt wiele prób."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nie można odblokować odciskiem palca. Zbyt wiele prób."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Agent zaufania jest niedostępny"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Zbyt wiele nieudanych prób wpisania kodu PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Zbyt wiele nieudanych prób narysowania wzoru"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Zbyt wiele nieudanych prób wpisania hasła"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Spróbuj ponownie za # sekundę.}few{Spróbuj ponownie za # sekundy.}many{Spróbuj ponownie za # sekund.}other{Spróbuj ponownie za # sekundy.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Wpisz kod PIN karty SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Wpisz kod PIN karty SIM „<xliff:g id="CARRIER">%1$s</xliff:g>”."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operacja z kodem PUK karty SIM nie udała się."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Przełączanie metody wprowadzania"</string> <string name="airplane_mode" msgid="2528005343938497866">"Tryb samolotowy"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Po ponownym uruchomieniu wymagany jest wzór"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Po ponownym uruchomieniu wymagany jest kod PIN"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Po ponownym uruchomieniu wymagane jest hasło"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ze względów bezpieczeństwa użyj wzoru"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ze względów bezpieczeństwa użyj kodu PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ze względów bezpieczeństwa użyj hasła"</string> diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml index a958741499ce..15b3fc00019d 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Digite seu PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Insira o PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Digite seu padrão"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Desenhe o padrão"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Digite sua senha"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Digite a senha"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Carregado"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando sem fio"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Não é possível desativar o eSIM devido a um erro."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Inserir"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Padrão errado."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Senha incorreta"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Senha errada."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN errado. Tente de novo."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ou desbloqueie com a impressão digital"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Impr. dig. não reconhecida"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Rosto não reconhecido"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Tente de novo ou insira o PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Tente de novo ou digite a senha"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Tente de novo ou desenhe o padrão"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"O PIN é obrigatório depois de muitas tentativas"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"A senha é obrigatória depois de muitas tentativas"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"O padrão é obrigatório depois de muitas tentativas"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desbloq. c/ PIN ou digital"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Dsblq. c/ senha ou digital"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desbloq. c/ padrão/digital"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Bloqueado por segurança pela política de trabalho"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"O PIN é obrigatório após o Bloqueio total"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"A senha é obrigatória após o Bloqueio total"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"O padrão é obrigatório após o Bloqueio total"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"A atualização será feita no período de inatividade"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Segurança necessária. PIN não usado há um tempo."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Segurança necessária. Senha não usada há um tempo."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Segurança necessária. Padrão não usado há um tempo."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Segurança necessária. Disp. não desbloq. faz tempo."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"O desbloqueio com o rosto falhou. Muitas tentativas."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Desbloq. c/ impr. digital falhou. Muitas tentativas."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"O agente de confiança não está disponível"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Muitas tentativas com o PIN incorreto"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Muitas tentativas com o padrão incorreto"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Muitas tentativas com a senha incorreta"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}many{Tente novamente em # segundos.}other{Tente novamente em # segundos.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Informe o PIN do chip."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Informe o PIN do chip para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha na operação de PUK do chip."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alterar o método de entrada"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo avião"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"O padrão é necessário após reiniciar o dispositivo"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"O PIN é necessário após reiniciar o dispositivo"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"A senha é necessária após reiniciar o dispositivo"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para ter mais segurança, use o padrão"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para ter mais segurança, use o PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para ter mais segurança, use a senha"</string> diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml index 77db3f72b7b9..ae0c284ce5c9 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Introduza o PIN."</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Introduza o PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Introduza o padrão."</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Desenhe o padrão"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduza a palavra-passe."</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Introduza a palavra-passe"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Carregada"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar sem fios"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Não é possível desativar o eSIM devido a um erro."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Tecla Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto."</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Padrão errado. Repita."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Palavra-passe incorreta."</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Pal.-passe errada. Repita."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN errado. Tente de novo."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ou desbloqueie com a impressão digital"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Impr. dig. não reconhecida"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Rosto não reconhecido"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Tente novamente ou introduza o PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Tente novamente ou introduza a palavra-passe"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Tente novamente ou desenhe o padrão"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN necessário após demasiadas tentativas"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Palavra-passe necessária após demasiadas tentativas"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Padrão necessário após demasiadas tentativas"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desbl. com PIN ou imp. digital"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Desbl. c/ palavra-passe/impr. dig."</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desbl. c/ padrão/impressão digital"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Dispositivo bloqueado pela Política de Trabalho"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"O PIN é necessário após o bloqueio"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"A palavra-passe é necessária após o bloqueio"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"O padrão é necessário após o bloqueio"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"A atualização vai ser instalada nas horas inativas"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Mais segurança necessária. PIN não usado há muito."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Mais segurança necessária. Não usada há muito."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"+ segurança necessária. Padrão não usado há muito."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Mais segurança necessária. Não desbloqueia há muito."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Imposs. desbloquear c/ rosto. Demasiadas tentativas."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Imposs. desbl. c/ impr. digital. Muitas tentativas."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"O agente fidedigno está indisponível"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Demasiadas tentativas com um PIN incorreto"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Demasiadas tentativas com um padrão incorreto"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Demasiadas tentativas com palavra-passe incorreta"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}many{Tente novamente dentro de # segundos.}other{Tente novamente dentro de # segundos.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduza o PIN do cartão SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduza o PIN do cartão SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha ao introduzir o PUK do cartão SIM!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alternar o método de introdução"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo de avião"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Padrão necessário após reiniciar o dispositivo"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN necessário após reiniciar o dispositivo"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Palavra-passe necessária após reiniciar dispositivo"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para uma segurança adicional, use antes o padrão"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para uma segurança adicional, use antes o PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para uma segurança adicional, use antes a palavra-passe"</string> diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml index a958741499ce..15b3fc00019d 100644 --- a/packages/SystemUI/res-keyguard/values-pt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Digite seu PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Insira o PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Digite seu padrão"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Desenhe o padrão"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Digite sua senha"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Digite a senha"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Carregado"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando sem fio"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Não é possível desativar o eSIM devido a um erro."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Inserir"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Padrão errado."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Senha incorreta"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Senha errada."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN errado. Tente de novo."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ou desbloqueie com a impressão digital"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Impr. dig. não reconhecida"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Rosto não reconhecido"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Tente de novo ou insira o PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Tente de novo ou digite a senha"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Tente de novo ou desenhe o padrão"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"O PIN é obrigatório depois de muitas tentativas"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"A senha é obrigatória depois de muitas tentativas"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"O padrão é obrigatório depois de muitas tentativas"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Desbloq. c/ PIN ou digital"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Dsblq. c/ senha ou digital"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desbloq. c/ padrão/digital"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Bloqueado por segurança pela política de trabalho"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"O PIN é obrigatório após o Bloqueio total"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"A senha é obrigatória após o Bloqueio total"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"O padrão é obrigatório após o Bloqueio total"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"A atualização será feita no período de inatividade"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Segurança necessária. PIN não usado há um tempo."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Segurança necessária. Senha não usada há um tempo."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Segurança necessária. Padrão não usado há um tempo."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Segurança necessária. Disp. não desbloq. faz tempo."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"O desbloqueio com o rosto falhou. Muitas tentativas."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Desbloq. c/ impr. digital falhou. Muitas tentativas."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"O agente de confiança não está disponível"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Muitas tentativas com o PIN incorreto"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Muitas tentativas com o padrão incorreto"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Muitas tentativas com a senha incorreta"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}many{Tente novamente em # segundos.}other{Tente novamente em # segundos.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Informe o PIN do chip."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Informe o PIN do chip para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha na operação de PUK do chip."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alterar o método de entrada"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modo avião"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"O padrão é necessário após reiniciar o dispositivo"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"O PIN é necessário após reiniciar o dispositivo"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"A senha é necessária após reiniciar o dispositivo"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para ter mais segurança, use o padrão"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para ter mais segurança, use o PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para ter mais segurança, use a senha"</string> diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml index 683901f794bb..9f568cc79936 100644 --- a/packages/SystemUI/res-keyguard/values-ro/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Introdu codul PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Introdu codul PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Introdu modelul"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Desenează modelul"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introdu parola"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Introdu parola"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Card nevalid"</string> <string name="keyguard_charged" msgid="5478247181205188995">"Încărcată"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se încarcă wireless"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Cardul eSIM nu poate fi dezactivat din cauza unei erori."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Introdu"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Model greșit"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Model greșit. Reîncearcă."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Parolă greșită"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Parolă greșită. Reîncearcă"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Cod PIN greșit"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN greșit. Reîncearcă."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Sau deblochează folosind amprenta"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Amprentă nerecunoscută"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Fața nu a fost recunoscută"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Încearcă din nou sau introdu codul PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Încearcă din nou sau introdu parola"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Încearcă din nou sau desenează modelul"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Codul PIN este solicitat după prea multe încercări"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Parola este solicitată după prea multe încercări"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Modelul este solicitat după prea multe încercări"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Deblochează cu PIN-ul sau amprenta"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Deblochează cu parola sau amprenta"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Deblochează cu modelul sau amprenta"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Pentru securitate, dispozitivul a fost blocat conform politicii privind activitatea"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Codul PIN este solicitat după blocarea strictă"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Parola este solicitată după blocarea strictă"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Modelul este solicitat după blocarea strictă"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Actualizarea se va instala în perioada de inactivitate"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Mai multă securitate necesară. PIN-ul nu a fost folosit de ceva timp."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Mai multă securitate necesară. Parola nu a fost folosită de ceva timp."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Mai multă securitate necesară. Modelul nu a fost folosit de ceva timp."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Mai multă securitate necesară. Dispozitivul nu a fost deblocat de ceva timp."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nu se poate debloca folosind fața. Prea multe încercări."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nu se poate debloca folosind amprenta. Prea multe încercări."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Agentul de încredere nu este disponibil"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Prea multe încercări cu un cod PIN incorect"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Prea multe încercări cu un model incorect"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Prea multe încercări cu o parolă incorectă"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Reîncearcă peste o secundă.}few{Reîncearcă peste # secunde.}other{Reîncearcă peste # de secunde.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introdu codul PIN al cardului SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introdu codul PIN al cardului SIM pentru „<xliff:g id="CARRIER">%1$s</xliff:g>”."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Deblocarea cu ajutorul codului PUK pentru cardul SIM nu a reușit!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Schimbă metoda de introducere"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mod Avion"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Modelul e solicitat după repornirea dispozitivului"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN-ul e solicitat după repornirea dispozitivului"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Parola e solicitată după repornirea dispozitivului"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Pentru mai multă securitate, folosește modelul"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Pentru mai multă securitate, folosește codul PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Pentru mai multă securitate, folosește parola"</string> diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml index 01499c82cefb..bae52556b4c9 100644 --- a/packages/SystemUI/res-keyguard/values-ru/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Введите PIN-код"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Введите PIN-код"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Введите графический ключ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Введите графический ключ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Введите пароль"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Введите пароль"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ошибка SIM-карты."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Батарея заряжена"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Беспроводная зарядка"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Не удалось отключить eSIM."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Клавиша ввода"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Неверный графический ключ"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Неверный графический ключ."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Неверный пароль"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Неверный пароль."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Неверный PIN-код"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Неверный PIN-код."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Повторите попытку или используйте отпечаток пальца."</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Отпечаток не распознан."</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Лицо не распознано."</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Повторите попытку или введите PIN-код."</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Повторите попытку или введите пароль."</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Повторите попытку или введите графический ключ."</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Слишком много попыток. Необходимо ввести PIN-код."</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Слишком много попыток. Необходимо ввести пароль."</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Слишком много попыток. Необходимо ввести граф. ключ."</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Используйте PIN-код или отпечаток пальца"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Используйте пароль или отпечаток пальца"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Используйте граф. ключ или отпечаток пальца"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Устройство заблокировано правилами организации."</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"После блокировки необходимо ввести PIN-код."</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"После блокировки необходимо ввести пароль."</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"После блокировки необходимо ввести графический ключ."</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Обновление установится, когда устройство неактивно."</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"PIN-код давно не использовался. Усильте защиту."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Пароль давно не использовался. Усильте защиту."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Граф. ключ давно не использовался. Усильте защиту."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Устройство давно не использовалось. Усильте защиту."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Превышен лимит попыток разблокировки фейсконтролем."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Превышен лимит попыток разблокировки отпечатком."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Агент доверия недоступен."</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Слишком много неудачных попыток ввести PIN-код."</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Слишком много неудачных попыток ввести граф. ключ."</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Слишком много неудачных попыток ввести пароль."</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Повторите попытку через # секунду.}one{Повторите попытку через # секунду.}few{Повторите попытку через # секунды.}many{Повторите попытку через # секунд.}other{Повторите попытку через # секунды.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Введите PIN-код SIM-карты."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Введите PIN-код SIM-карты \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Не удалось разблокировать SIM-карту"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Сменить способ ввода"</string> <string name="airplane_mode" msgid="2528005343938497866">"Режим полета"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"После перезапуска необходимо ввести графический ключ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"После перезапуска необходимо ввести PIN-код"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"После перезапуска необходимо ввести пароль"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"В целях дополнительной безопасности используйте графический ключ"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"В целях дополнительной безопасности используйте PIN-код"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"В целях дополнительной безопасности используйте пароль"</string> diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml index 6cacbf226a4a..4bb8aeb499fb 100644 --- a/packages/SystemUI/res-keyguard/values-si/strings.xml +++ b/packages/SystemUI/res-keyguard/values-si/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"ඔබේ PIN ඇතුළු කරන්න"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN ඇතුළු කරන්න"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"ඔබගේ රටාව ඇතුළු කරන්න"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"රටාව අඳින්න"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"ඔබේ මුරපදය ඇතුළු කරන්න"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"මුරපදය ඇතුළු කරන්න"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"වලංගු නොවන කාඩ්පත."</string> <string name="keyguard_charged" msgid="5478247181205188995">"අරෝපිතයි"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • නොරැහැන්ව ආරෝපණ කෙරේ"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"දෝෂයක් හේතුවෙන් eSIM අබල කළ නොහැකිය."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"ඇතුල් කරන්න"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"වැරදි රටාවකි"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"වැරදි රටාවකි. නැවත උත්සාහ කරන්න."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"වැරදි මුරපදයකි"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"මුරපදය වැරදියි. නැවත උත්සාහ කරන්න."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN එක වැරදියි"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN වැරදියි. නැවත උත්සාහ කරන්න."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"නැතහොත් ඇඟිලි සලකුණ සමග අගුළු හරින්න"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ඇඟිලි සලකුණ හඳුනා නොගැනිණි"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"මුහුණ හඳුනා නොගන්නා ලදි"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"නැවත උත්සාහ කරන්න හෝ PIN ඇතුළු කරන්න"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"නැවත උත්සාහ කරන්න හෝ මුරපදය ඇතුළු කරන්න"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"නැවත උත්සාහ කරන්න හෝ රටාව අඳින්න"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"බොහෝ උත්සාහයන්ට පසුව PIN අවශ්ය වේ"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"බොහෝ උත්සාහයන්ගෙන් පසුව මුරපදය අවශ්ය වේ"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"බොහෝ උත්සාහයන්ගෙන් පසුව රටාව අවශ්ය වේ"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN හෝ ඇඟිලි සලකුණ සමග අගුළු හරින්න"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"මුරපදය හෝ ඇඟිලි සලකුණ සමග අගුළු හරින්න"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"රටාව හෝ ඇඟිලි සලකුණ සමග අගුළු හරින්න"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"අමතර ආරක්ෂාව සඳහා, වැඩ ප්රතිපත්තියෙන් උපාංගය අගුළු දමා ඇත"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"අගුළු දැමීමෙන් පසු PIN අවශ්ය වේ"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"අගුළු දැමීමෙන් පසු මුරපදය අවශ්ය වේ"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"අගුළු දැමීමෙන් පසු රටාව අවශ්ය වේ"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"යාවත්කාලීනය අක්රිය පැය තුළ ස්ථාපනය වනු ඇත"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"අමතර ආරක්ෂාවක් අවශ්යයි. PIN ටික කලකට භාවිතා කර නැත."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"අමතර ආරක්ෂාවක් අවශ්යයි. මුරපදය ටික කලකට භාවිතා කර නැත."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"අමතර ආරක්ෂාවක් අවශ්යයි. රටාව ටික කලකට භාවිතා කර නැත."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"අමතර ආරක්ෂාවක් අවශ්යයි. උපාංගය ටික කලකට අගුළු හරිනු ලැබුවේ නැත."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"මුහුණ සමග අගුළු හැරිය නොහැක. උත්සාහ ගණන ඉතා වැඩියි."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ඇඟිලි සලකුණ සමග අගුළු හැරිය නොහැක. උත්සාහ ගණන ඉතා වැඩියි."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"විශ්වාස නියෝජිතයා නොමැත"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"වැරදි PIN එකක් සමග බොහෝ උත්සාහයන් ගණනකි"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"වැරදි රටාවක් සමග බොහෝ උත්සාහයන් ගණනකි"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"වැරදි මුරපදයක් සමග බොහෝ උත්සාහයන් ගණනකි"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{තත්පර #කින් නැවත උත්සාහ කරන්න.}one{තත්පර #කින් නැවත උත්සාහ කරන්න.}other{තත්පර #කින් නැවත උත්සාහ කරන්න.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN ඇතුළු කරන්න"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" සඳහා SIM PIN ඇතුළු කරන්න"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK මෙහෙයුම අසාර්ථක විය!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ආදාන ක්රමය මාරු කිරීම"</string> <string name="airplane_mode" msgid="2528005343938497866">"ගුවන් යානා ප්රකාරය"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"උපාංගය යළි ඇරඹීමෙන් පසු රටාව අවශ්ය වේ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"උපාංගය යළි ඇරඹීමෙන් පසු PIN අවශ්ය වේ"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"උපාංගය යළි ඇරඹීමෙන් පසු මුරපදය අවශ්ය වේ"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"අතිරේක ආරක්ෂාව සඳහා, ඒ වෙනුවට රටාව භාවිතා කරන්න"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"අතිරේක ආරක්ෂාව සඳහා, ඒ වෙනුවට PIN භාවිතා කරන්න"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"අතිරේක ආරක්ෂාව සඳහා, ඒ වෙනුවට මුරපදය භාවිතා කරන්න"</string> diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml index f2f92cb7c8e0..b12c9d30da12 100644 --- a/packages/SystemUI/res-keyguard/values-sk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Zadajte PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Zadajte PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Zadajte vzor"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Nakreslite vzor"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Zadajte heslo"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Zadajte heslo"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Neplatná karta."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Nabité"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíja sa bezdrôtovo"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM karta sa nedá deaktivovať, pretože sa vyskytla chyba."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Nesprávny vzor"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Nesprávny vzor. Zopakujte."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Nesprávne heslo"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Chybné heslo. Zopakujte."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Nesprávny kód PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Nesprávny kód PIN. Zopakujte."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Alebo odomknite odtlačkom prsta"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Nerozpoz. odtlačok prsta"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Tvár nebola rozpoznaná"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Skúste to znova alebo zadajte PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Skúste to znova alebo zadajte heslo"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Skúste to znova alebo nakreslite vzor"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Príliš veľký počet pokusov. Vyžaduje sa PIN."</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Príliš veľký počet pokusov. Vyžaduje sa heslo."</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Príliš veľký počet pokusov. Vyžaduje sa vzor."</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Odomknúť kódom PIN/odtlačkom"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Odomknúť heslom/odtlačkom"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Odomknúť vzorom/odtlačkom"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Zar. bolo uzamk. prac. pravid. na zvýš. zabezpečenia"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po silnej zámke sa vyžaduje PIN"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po silnej zámke sa vyžaduje heslo"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po silnej zámke sa vyžaduje vzor"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Aktualizácia sa nainštaluje počas nečinnosti"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Treba lepšie zabezp. Kód PIN nebol dlhšie použitý."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Treba lepšie zabezp. Heslo nebolo dlhšie použité."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Treba lepšie zabezp. Vzor nebol dlhšie použitý."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Treba lepšie zabezpeč. Zar. nebolo dlhšie odomknuté."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nedá sa odomknúť tvárou. Priveľa pokusov."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nedá sa odomknúť odtlačkom prsta. Priveľa pokusov."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Agent dôvery nie je k dispozícii"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Priveľa pokusov s nesprávnym kódom PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Priveľa pokusov s nesprávnym vzorom"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Priveľa pokusov s nesprávnym heslom"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Skúste to znova o # sekundu.}few{Skúste to znova o # sekundy.}many{Skúste to znova o # sekundy.}other{Skúste to znova o # sekúnd.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Zadajte PIN pre SIM kartu"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Zadajte kód PIN pre SIM kartu operátora <xliff:g id="CARRIER">%1$s</xliff:g>."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operácia kódu PUK SIM karty zlyhala!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Prepnúť metódu vstupu"</string> <string name="airplane_mode" msgid="2528005343938497866">"Režim v lietadle"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Po reštarte zariadenia sa vyžaduje vzor"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Po reštarte zariadenia sa vyžaduje kód PIN"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Po reštarte zariadenia sa vyžaduje heslo"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"V rámci zvýšenia zabezpečenia použite radšej vzor"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"V rámci zvýšenia zabezpečenia použite radšej PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"V rámci zvýšenia zabezpečenia použite radšej heslo"</string> diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml index 8b14411b80f1..3f2968886989 100644 --- a/packages/SystemUI/res-keyguard/values-sl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Vnesite kodo PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Vnesite kodo PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Vnesite vzorec"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Narišite vzorec"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Vnesite geslo"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Vnesite geslo"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Neveljavna kartica"</string> <string name="keyguard_charged" msgid="5478247181205188995">"Baterija napolnjena"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • brezžično polnjenje"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Digitalne kartice e-SIM zaradi napake ni mogoče onemogočiti."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Tipka Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Napačen vzorec"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Napačen vzorec. Poskusite znova."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Napačno geslo"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Napačno geslo. Poskusite znova."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Napačna koda PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Napačna koda PIN. Poskusite znova."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ali odklenite s prstnim odtisom"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Prstni odtis ni prepoznan"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Obraz ni prepoznan"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Poskusite znova ali vnesite kodo PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Poskusite znova ali vnesite geslo"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Poskusite znova ali narišite vzorec"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Po preveč poskusih se zahteva vnos kode PIN"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Po preveč poskusih se zahteva vnos gesla"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Po preveč poskusih se zahteva vnos vzorca"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Odklenite s kodo PIN ali prstnim odtisom"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Odklenite z geslom ali prstnim odtisom"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Odklenite z vzorcem ali prstnim odtisom"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Za dodatno varnost je bila naprava zaklenjena s službenim pravilnikom"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Po zaklepu se zahteva vnos kode PIN"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Po zaklepu se zahteva vnos gesla"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Po zaklepu se zahteva vnos vzorca"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Posodobitev bo nameščena v času nedejavnosti"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Zahtevana je dodatna varnost. Koda PIN nekaj časa ni bila uporabljena."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Zahtevana je dodatna varnost. Geslo nekaj časa ni bilo uporabljeno."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Zahtevana je dodatna varnost. Vzorec nekaj časa ni bil uporabljen."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Zahtevana je dodatna varnost. Naprava nekaj časa ni bila odklenjena."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Ni mogoče odkleniti z obrazom. Preveč poskusov."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Ni mogoče odkleniti s prstnim odtisom. Preveč poskusov."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Posrednik zaupanja ni na voljo"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Preveč poskusov z nepravilno kodo PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Preveč poskusov z nepravilnim vzorcem"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Preveč poskusov z nepravilnim geslom"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Poskusite znova čez # sekundo.}one{Poskusite znova čez # sekundo.}two{Poskusite znova čez # sekundi.}few{Poskusite znova čez # sekunde.}other{Poskusite znova čez # sekund.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Vnesite kodo PIN kartice SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Vnesite kodo PIN kartice SIM operaterja »<xliff:g id="CARRIER">%1$s</xliff:g>«."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Postopek za odklepanje s kodo PUK kartice SIM ni uspel."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Preklop načina vnosa"</string> <string name="airplane_mode" msgid="2528005343938497866">"Način za letalo"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Po vnovičnem zagonu naprave se zahteva vnos vzorca"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Po vnovičnem zagonu naprave se zahteva vnos kode PIN"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Po vnovičnem zagonu naprave se zahteva vnos gesla"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatno varnost raje uporabite vzorec."</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatno varnost raje uporabite kodo PIN."</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatno varnost raje uporabite geslo."</string> diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml index 646d6609e9dc..149207c49bce 100644 --- a/packages/SystemUI/res-keyguard/values-sq/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Fut kodin PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Fut PIN-in"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Fut motivin"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Vizato motivin"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Fut fjalëkalimin"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Fut fjalëkalimin"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Karta e pavlefshme."</string> <string name="keyguard_charged" msgid="5478247181205188995">"I karikuar"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me valë"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Karta eSIM nuk mund të çaktivizohet për shkak të një gabimi."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Dërgo"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Motiv i gabuar"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Motiv i gabuar. Provo përsëri."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Fjalëkalim i gabuar"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Fjalëkalim i gabuar. Provo përsëri."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Kod PIN i gabuar"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Kod PIN i gabuar. Provo përsëri."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ose shkyçe me gjurmën e gishtit"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Gjurma e gishtit nuk njihet"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Fytyra nuk njihet"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Provo përsëri ose fut kodin PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Provo përsëri ose fut fjalëkalimin"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Provo përsëri ose vizato motivin"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Pas shumë përpjekjeve kërkohet kodi PIN"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Pas shumë përpjekjeve kërkohet fjalëkalimi"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Pas shumë përpjekjeve kërkohet motivi"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Shkyçe me kodin PIN ose me gjurmën e gishtit"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Shkyçe me fjalëkalimin ose gjurmën e gishtit"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Shkyçe me motivin ose gjurmën e gishtit"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Për më shumë siguri, pajisja është kyçur nga politika e punës"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pas bllokimit kërkohet kodi PIN"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Pas bllokimit kërkohet fjalëkalimi"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Pas bllokimit kërkohet motivi"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Përditësimi do të instalohet gjatë kohës joaktive"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Kërkohet një siguri më e lartë. Kodi PIN nuk është përdorur për njëfarë kohe."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Kërkohet një siguri më e lartë. Fjalëkalimi nuk është përdorur për njëfarë kohe."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Kërkohet një siguri më e lartë. Motivi nuk është përdorur për njëfarë kohe."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Kërkohet një siguri më e lartë. Pajisja nuk është shkyçur për njëfarë kohe."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Nuk mund të shkyçet me fytyrën. Shumë përpjekje."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Nuk mund të shkyçet me gjurmën e gishtit. Shumë përpjekje."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Agjenti i besimit nuk ofrohet"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Shumë përpjekje me kod PIN të pasaktë"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Shumë përpjekje me motiv të pasaktë"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Shumë përpjekje me fjalëkalim të pasaktë"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Provo sërish pas # sekonde.}other{Provo sërish pas # sekondash.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Fut kodin PIN të kartës SIM"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Fut kodin PIN të kartës SIM për \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operacioni i kodit PUK të kartës SIM dështoi!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Ndërro metodën e hyrjes"</string> <string name="airplane_mode" msgid="2528005343938497866">"Modaliteti i aeroplanit"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Pas rinisjes së pajisjes kërkohet motivi"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Pas rinisjes së pajisjes kërkohet kodi PIN"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Pas rinisjes së pajisjes kërkohet fjalëkalimi"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Për më shumë siguri, përdor motivin më mirë"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Për më shumë siguri, përdor kodin PIN më mirë"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Për më shumë siguri, përdor fjalëkalimin më mirë"</string> diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml index 1fcd4c3f84d4..bded34a69b82 100644 --- a/packages/SystemUI/res-keyguard/values-sr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Унесите PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Унесите PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Унесите шаблон"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Нацртајте шаблон"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Унесите лозинку"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Унесите лозинку"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Неважећа картица."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Напуњена је"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Бежично пуњење"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM не може да се онемогући због грешке."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Погрешан шаблон"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Погрешан шаблон. Пробајте поново."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Погрешна лозинка"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Погрешна лозинка. Пробајте поново."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Погрешан PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Погрешан PIN. Пробајте поново."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Или откључајте отиском прста"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Отисак прста непрепознат"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Лице није препознато"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Пробајте поново или унесите PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Пробајте поново или унесите лозинку"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Пробајте поново или нацртајте шаблон"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN је обавезан после превише покушаја"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Лозинка је обавезна после превише покушаја"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Шаблон је обавезан после превише покушаја"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Откључајте PIN-ом или отиском прста"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Откључајте лозинком или отиском прста"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Откључајте шаблоном или отиском прста"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Ради безбедности смернице за посао су закључ. уређај"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN је обавезан после закључавања"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Лозинка је обавезна после закључавања"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Шаблон је обавезан после закључавања"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Ажурирање се инсталира током неактивности"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Потребна је додатна заштита. PIN дуго није коришћен."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Потребна је додатна заштита. Лозинка дуго није коришћена."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Потребна је додатна заштита. Шаблон дуго није коришћен."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Потребна је додатна заштита. Уређај дуго није откључан."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Откључавање лицем није успело. Превише покушаја."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Откључавање отиском није успело. Превише покушаја."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Поуздани агент је недоступан"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Превише покушаја са нетачним PIN-ом"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Превише покушаја са нетачним шаблоном"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Превише покушаја са нетачном лозинком"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Пробајте поново за # секунду.}one{Пробајте поново за # секунду.}few{Пробајте поново за # секунде.}other{Пробајте поново за # секунди.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Унесите PIN за SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Унесите PIN за SIM „<xliff:g id="CARRIER">%1$s</xliff:g>“."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Радња са PUK кодом за SIM није успела!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Промени метод уноса"</string> <string name="airplane_mode" msgid="2528005343938497866">"Режим рада у авиону"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Шаблон је обавезан после рестарта уређаја"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN је обавезан после рестарта уређаја"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Лозинка је обавезна после рестарта уређаја"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"За додатну безбедност користите шаблон"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"За додатну безбедност користите PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"За додатну безбедност користите лозинку"</string> diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml index 69553d9e3257..c11e0f1e657d 100644 --- a/packages/SystemUI/res-keyguard/values-sv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Ange pinkoden"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Ange PIN-kod"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Ange mönstret"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Rita mönster"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Ange ditt lösenord"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Ange lösenord"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ogiltigt kort."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Laddat"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas trådlöst"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Det gick inte att inaktivera eSIM-kortet på grund av ett fel."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Retur"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Fel mönster"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Fel mönster Försök igen."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Fel lösenord"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Fel lösenord. Försök igen."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Fel pinkod"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Fel pinkod. Försök igen."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Eller lås upp med fingeravtryck"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Fingeravtrycket känns inte igen"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Ansiktet känns inte igen"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Försök igen eller ange pinkoden"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Försök igen eller ange lösenordet"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Försök igen eller rita mönstret"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Pinkoden krävs efter för många försök"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Lösenordet krävs efter för många försök"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Mönstret krävs efter för många försök"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Lås upp med pinkod eller fingeravtryck"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Lås upp med lösenord eller fingeravtryck"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Lås upp med mönster eller fingeravtryck"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"För ökad säkerhet låstes enheten av jobbprincipen"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Pinkod krävs efter låsning"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Lösenord krävs efter låsning"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mönster krävs efter låsning"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Uppdateringen installeras under inaktiva timmar"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Ökad säkerhet krävs. Pinkoden har inte använts på länge."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Ökad säkerhet krävs. Lösenordet har inte använts på länge."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Ökad säkerhet krävs. Mönstret har inte använts på länge."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Ökad säkerhet krävs. Enheten var inte olåst ett tag."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Ansiktet kunde inte låsa upp. För många försök."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Fingeravtrycket kunde inte låsa upp. För många försök."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Betrodd agent är inte tillgänglig"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"För många försök med fel pinkod"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"För många försök med fel mönster"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"För många försök med fel lösenord"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Försök igen om # sekund.}other{Försök igen om # sekunder.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Ange pinkod för SIM-kortet."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Ange pinkod för SIM-kortet för <xliff:g id="CARRIER">%1$s</xliff:g>."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Det gick inte att låsa upp med PUK-koden för SIM-kortet."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Byt inmatningsmetod"</string> <string name="airplane_mode" msgid="2528005343938497866">"Flygplansläge"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Mönstret krävs efter att enheten omstartas"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Pinkoden krävs efter att enheten omstartas"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Lösenordet krävs efter att enheten omstartas"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"För ytterligare säkerhet använder du mönstret i stället"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"För ytterligare säkerhet använder du pinkoden i stället"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"För ytterligare säkerhet använder du lösenordet i stället"</string> diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml index be383eb33966..943c76b79c02 100644 --- a/packages/SystemUI/res-keyguard/values-sw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Weka PIN yako"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Weka PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Weka mchoro wako"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Chora mchoro"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Weka nenosiri lako"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Weka nenosiri"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Kadi si Sahihi."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Betri imejaa"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji bila kutumia waya"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Hitilafu imetokea wakati wa kuzima eSIM."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Weka"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Mchoro si sahihi"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Mchoro si sahihi. Jaribu tena."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Nenosiri si sahihi"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Nenosiri si sahihi. Jaribu tena."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Nambari ya PIN si sahihi"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN si sahihi. Jaribu tena."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Au fungua kwa alama ya kidole"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Alama ya kidole haijatambuliwa"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Sura haikutambulika"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Jaribu tena au uweke PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Jaribu tena au uweke nenosiri"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Jaribu tena au uchore mchoro"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN inahitajika baada ya majaribio mengi mno"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Nenosiri linahitajika baada ya majaribio mengi mno"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Mchoro unahitajika baada ya majaribio mengi mno"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Fungua kwa PIN au alama ya kidole"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Fungua kwa nenosiri au alama ya kidole"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Fungua kwa mchoro au alama ya kidole"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Kwa usalama zaidi, kifaa kilifungwa kwa sera ya kazi"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"PIN inahitajika baada ya kufunga"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Nenosiri linahitajika baada ya kufunga"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Mchoro unahitajika baada ya kufunga"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Sasisho litasakinishwa wakati kifaa hakitumiki"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Usalama wa ziada unahitajika. PIN haikutumika kwa muda."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Usalama wa ziada unahitajika. Nenosiri halikutumika kwa muda."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Usalama wa ziada unahitajika. Mchoro haukutumika kwa muda."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Usalama wa ziada unahitajika. Kifaa hakikufunguliwa kwa muda."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Huwezi kufungua kwa uso. Umejaribu mara nyingi mno."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Huwezi kufungua kwa alama ya kidole. Umejaribu mara nyingi mno."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Kipengele cha kutathmini hali ya kuaminika hakipatikani"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Umejaribu mara nyingi mno kwa PIN isiyo sahihi"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Umejaribu mara nyingi mno kwa mchoro usio sahihi"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Umejaribu mara nyingi mno kwa nenosiri lisilo sahihi"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Jaribu tena baada ya sekunde #.}other{Jaribu tena baada ya sekunde #.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Weka PIN ya SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Weka PIN ya SIM ya \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Utendakazi wa PUK ya SIM haujafanikiwa!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Kubadili mbinu ya kuingiza data"</string> <string name="airplane_mode" msgid="2528005343938497866">"Hali ya ndegeni"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Mchoro unahitajika kifaa kikizimwa kisha kiwashwe"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN inahitajika kifaa kikizimwa kisha kiwashwe"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Nenosiri linahitajika kifaa kikizimwa kisha kiwashwe"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Kwa usalama wa ziada, tumia mchoro badala yake"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Kwa usalama wa ziada, tumia PIN badala yake"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Kwa usalama wa ziada, tumia nenosiri badala yake"</string> diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml index 798a89a8ae01..f1bcf9c1092f 100644 --- a/packages/SystemUI/res-keyguard/values-te/strings.xml +++ b/packages/SystemUI/res-keyguard/values-te/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"మీ పిన్ని నమోదు చేయండి"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PINను ఎంటర్ చేయండి"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"మీ నమూనాను నమోదు చేయండి"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ఆకృతిని గీయండి"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"మీ పాస్వర్డ్ను ఎంటర్ చేయండి"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"పాస్వర్డ్ను ఎంటర్ చేయండి"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"చెల్లని కార్డ్."</string> <string name="keyguard_charged" msgid="5478247181205188995">"ఛార్జ్ చేయబడింది"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • వైర్ లేకుండా ఛార్జ్ అవుతోంది"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"ఎర్రర్ కారణంగా eSIMని నిలపడం సాధ్యపడదు."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"నమూనా తప్పు"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"ఆకృతి తప్పు. మళ్లీ గీయండి."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"పాస్వర్డ్ తప్పు"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"పాస్వర్డ్ తప్పు. రీట్రై."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"పిన్ తప్పు"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN తప్పు. రీట్రై చేయండి."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"లేదా వేలిముద్రతో అన్లాక్ చేయండి"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"వేలిముద్ర గుర్తించబడలేదు"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ముఖం గుర్తించబడలేదు"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"మళ్లీ ట్రై చేయండి లేదా PINని ఎంటర్ చేయండి"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"మళ్లీ ట్రై చేయండి లేదా పాస్వర్డ్ను ఎంటర్ చేయండి"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"మళ్లీ ట్రై చేయండి లేదా ఆకృతిని గీయండి"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"చాలా సార్లు ట్రై చేసిన తర్వాత PIN అవసరం అవుతుంది"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"చాలా సార్లు ట్రై చేసిన తర్వాత పాస్వర్డ్ అవసరం"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"చాలా సార్లు ట్రై చేసిన తర్వాత ఆకృతి అవసరం అవుతుంది"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN/వేలిముద్రతో తెరవండి"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"పాస్వర్డ్/వేలిముద్రతో తెరవండి"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ఆకృతి/వేలిముద్రతో తెరవండి"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"మరింత సెక్యూరిటీకై, వర్క్ పాలసీతో డివైజ్ లాక్ చేశారు"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"లాక్డౌన్ తర్వాత PIN అవసరం"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"లాక్డౌన్ తర్వాత పాస్వర్డ్ అవసరం"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"లాక్డౌన్ తర్వాత ఆకృతి అవసరం"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"ఇన్యాక్టివ్ వేళల్లో అప్డేట్ ఇన్స్టాల్ చేయబడుతుంది"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"మరింత సెక్యూరిటీ యాడ్ చెయ్యాలి. PINని ఈమధ్య వాడలేదు."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"యాడెడ్ సెక్యూరిటీ కావాలి. పాస్వర్డ్ ఈ మధ్య వాడలేదు."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"మరింత సెక్యూరిటీ కావాలి. ఆకృతిని ఈ మధ్య వాడలేదు."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"మరింత సెక్యూరిటీ కావాలి. పరికరాన్ని ఈమధ్య తెరవలేదు."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"ఫేస్తో అన్లాక్ అవ్వదు. ఎక్కువ సార్లు ట్రై చేశారు."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"వేలిముద్రతో అన్లాకవదు. మరీ ఎక్కువ ట్రైలు చేశారు."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"విశ్వసనీయ ఏజెంట్ అందుబాటులో లేదు"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"తప్పు PINతో చాలా ఎక్కువ సార్లు ట్రై చేయడం జరిగింది"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"తప్పు ఆకృతితో చాలా ఎక్కువ సార్లు ట్రై చేయడం జరిగింది"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"తప్పు పాస్వర్డ్తో చాలా ఎక్కువ సార్లు ట్రై చేశారు"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# సెకనులో మళ్లీ ట్రై చేయండి.}other{# సెకన్లలో మళ్లీ ట్రై చేయండి.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM పిన్ని నమోదు చేయండి."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" కోసం SIM పిన్ని నమోదు చేయండి."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK చర్య విఫలమైంది!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ఇన్పుట్ పద్ధతిని మార్చు"</string> <string name="airplane_mode" msgid="2528005343938497866">"విమానం మోడ్"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"పరికరాన్ని రీస్టార్ట్ చేశాక ఆకృతి అవసరం"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"పరికరాన్ని రీస్టార్ట్ చేశాక PIN అవసరం"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"పరికరాన్ని రీస్టార్ట్ చేశాక పాస్వర్డ్ అవసరం"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"అదనపు సెక్యూరిటీ కోసం, బదులుగా ఆకృతిని ఉపయోగించండి"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"అదనపు సెక్యూరిటీ కోసం, బదులుగా PINను ఉపయోగించండి"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"అదనపు సెక్యూరిటీ కోసం, బదులుగా పాస్వర్డ్ను ఉపయోగించండి"</string> diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml index dc16bb6468da..e8c7ef9c33cc 100644 --- a/packages/SystemUI/res-keyguard/values-th/strings.xml +++ b/packages/SystemUI/res-keyguard/values-th/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"ป้อน PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"ป้อน PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"ป้อนรูปแบบ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"วาดรูปแบบ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"ป้อนรหัสผ่าน"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"ป้อนรหัสผ่าน"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"การ์ดไม่ถูกต้อง"</string> <string name="keyguard_charged" msgid="5478247181205188995">"ชาร์จแล้ว"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • กำลังชาร์จแบบไร้สาย"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"ปิดใช้ eSIM ไม่ได้เนื่องจากมีข้อผิดพลาด"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"รูปแบบไม่ถูกต้อง"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"รูปแบบไม่ถูกต้อง ลองใหม่"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"รหัสผ่านไม่ถูกต้อง"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"รหัสผ่านไม่ถูกต้อง ลองใหม่"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN ไม่ถูกต้อง"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN ไม่ถูกต้อง ลองใหม่"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"หรือปลดล็อกด้วยลายนิ้วมือ"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"ไม่รู้จักลายนิ้วมือ"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"ไม่รู้จักใบหน้า"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"ลองอีกครั้งหรือป้อน PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"ลองอีกครั้งหรือป้อนรหัสผ่าน"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"ลองอีกครั้งหรือวาดรูปแบบ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"ต้องป้อน PIN หลังจากลองหลายครั้งเกินไป"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"ต้องป้อนรหัสผ่านหลังจากลองหลายครั้งเกินไป"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"ต้องวาดรูปแบบหลังจากลองหลายครั้งเกินไป"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"ปลดล็อกด้วย PIN หรือลายนิ้วมือ"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"ปลดล็อกด้วยรหัสผ่านหรือลายนิ้วมือ"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"ปลดล็อกด้วยรูปแบบหรือลายนิ้วมือ"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"อุปกรณ์ถูกล็อกโดยนโยบายการทำงานเพื่อเพิ่มความปลอดภัย"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"ต้องป้อน PIN หลังจากการปิดล็อก"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"ต้องป้อนรหัสผ่านหลังจากการปิดล็อก"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"ต้องวาดรูปแบบหลังจากการปิดล็อก"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"การอัปเดตจะติดตั้งในระหว่างชั่วโมงที่ไม่ได้ใช้งาน"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"ต้องเพิ่มความปลอดภัย ไม่ได้ใช้ PIN มาระยะหนึ่ง"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"ต้องเพิ่มความปลอดภัย ไม่ได้ใช้รหัสผ่านมาระยะหนึ่ง"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"ต้องเพิ่มความปลอดภัย ไม่ได้ใช้รูปแบบมาระยะหนึ่ง"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"ต้องเพิ่มความปลอดภัย ไม่ได้ปลดล็อกอุปกรณ์มาระยะหนึ่ง"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"ปลดล็อกด้วยใบหน้าไม่ได้ ลองหลายครั้งเกินไป"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"ปลดล็อกด้วยลายนิ้วมือไม่ได้ ลองหลายครั้งเกินไป"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"เอเจนต์ความน่าเชื่อถือไม่พร้อมใช้งาน"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"ลองโดยใช้ PIN ที่ไม่ถูกต้องหลายครั้งเกินไป"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"ลองโดยใช้รูปแบบที่ไม่ถูกต้องหลายครั้งเกินไป"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"ลองโดยใช้รหัสผ่านที่ไม่ถูกต้องหลายครั้งเกินไป"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{ลองอีกครั้งใน # วินาที}other{ลองอีกครั้งใน # วินาที}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"ป้อน PIN ของซิม"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"ป้อน PIN ของซิมสำหรับ \"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"การปลดล็อกด้วย PUK ของซิมล้มเหลว!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"สลับวิธีการป้อนข้อมูล"</string> <string name="airplane_mode" msgid="2528005343938497866">"โหมดบนเครื่องบิน"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ต้องวาดรูปแบบหลังจากรีสตาร์ทอุปกรณ์"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ต้องป้อน PIN หลังจากรีสตาร์ทอุปกรณ์"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ต้องป้อนรหัสผ่านหลังจากรีสตาร์ทอุปกรณ์"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ใช้รูปแบบแทนเพื่อเพิ่มความปลอดภัย"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ใช้ PIN แทนเพื่อเพิ่มความปลอดภัย"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ใช้รหัสผ่านแทนเพื่อเพิ่มความปลอดภัย"</string> diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml index 4df08f5055ec..4d9102c0fefd 100644 --- a/packages/SystemUI/res-keyguard/values-tl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Ilagay ang iyong PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Ilagay ang PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Ilagay ang iyong pattern"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Iguhit ang pattern"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Ilagay ang iyong password"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Ilagay ang password"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Di-wasto ang Card."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Tapos nang mag-charge"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wireless na nagcha-charge"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Hindi ma-disable ang eSIM dahil sa isang error."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Mali ang pattern"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Maling pattern. Subukan ulit."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Mali ang password"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Mali ang password. Subukan ulit."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Mali ang PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Maling PIN. Subukan ulit."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"O i-unlock gamit ang fingerprint"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Hindi nakilala ang fingerprint"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Hindi nakilala ang mukha"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Subukan ulit o ilagay ang PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Subukan ulit o ilagay ang password"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Subukan ulit o iguhit ang pattern"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Kailangan ang PIN pagkasubok nang napakarami"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Kailangan ang password pagkasubok nang napakarami"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Kailangan ang pattern pagkasubok nang napakarami"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"I-unlock gamit ang PIN o fingerprint"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"I-unlock gamit ang password o fingerprint"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"I-unlock gamit ang pattern o fingerprint"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Na-lock ng work policy ang device para sa seguridad"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Kailangan ang PIN pagkatapos ng lockdown"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Kailangan ang password pagkatapos ng lockdown"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Kailangan ang pattern pagkatapos ng lockdown"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Mag-i-install ang update sa mga hindi aktibong oras"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Kailangan pa ng seguridad. Matagal na hindi ginamit ang PIN."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Kailangan pa ng seguridad. Matagal na hindi ginamit ang password."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Kailangan pa ng seguridad. Matagal na hindi ginamit ang pattern."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Kailangan pa ng seguridad. Matagal na hindi naka-unlock ang device."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Hindi ma-face unlock. Napakaraming pagsubok."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Hindi ma-fingerprint unlock. Napakaraming pagsubok."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Hindi available ang trust agent"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Napakaraming pagsubok gamit ang maling PIN"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Napakaraming pagsubok gamit ang maling pattern"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Napakaraming pagsubok gamit ang maling password"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Subukan ulit sa # segundo.}one{Subukan ulit sa # segundo.}other{Subukan ulit sa # na segundo.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Ilagay ang PIN ng SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Ilagay ang PIN ng SIM para sa \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Nabigo ang operasyon ng PUK ng SIM!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Magpalit ng pamamaraan ng pag-input"</string> <string name="airplane_mode" msgid="2528005343938497866">"Airplane mode"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Kailangan ang pattern pagka-restart ng device"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Kailangan ang PIN pagka-restart ng device"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Kailangan ang password pagka-restart ng device"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para sa karagdagang seguridad, gumamit na lang ng pattern"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para sa karagdagang seguridad, gumamit na lang ng PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para sa karagdagang seguridad, gumamit na lang ng password"</string> diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml index 2aca8ad38190..a2268ef6cfff 100644 --- a/packages/SystemUI/res-keyguard/values-tr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"PIN kodunuzu girin"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN girin"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Deseninizi girin"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Desen çizin"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Şifrenizi girin"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Şifre girin"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Geçersiz Kart."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Şarj oldu"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kablosuz olarak şarj ediliyor"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Bir hata nedeniyle eSIM devre dışı bırakılamıyor."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Yanlış desen"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Yanlış desen. Tekrar deneyin."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Yanlış şifre"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Yanlış şifre. Tekrar deneyin."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Yanlış PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Yanlış PIN. Tekrar deneyin."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Ya da parmak iziyle kilidi açın"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Parmak izi tanınmadı"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Yüz tanınmadı"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Tekrar deneyin veya PIN girin"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Tekrar deneyin veya şifre girin"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Tekrar deneyin veya desen çizin"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Çok fazla deneme yaptığınızdan PIN girmeniz gerek"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Çok fazla deneme yaptığınızdan şifre girmeniz gerek"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Çok fazla deneme yaptığınızdan desen çizmeniz gerek"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN veya parmak iziyle kilidi açın"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Şifre veya parmak iziyle kilidi açın"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Desen veya parmak iziyle kilidi açın"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Daha fazla güvenlik için cihaz, işletme politikası gereği kilitlendi"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Tam kilitlemenin ardından PIN gerekli"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Tam kilitlemenin ardından şifre gerekli"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Tam kilitlemenin ardından desen gerekli"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Güncelleme, etkin olmayan saatlerde yüklenecek"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Daha fazla güvenlik gerekli. PIN bir süredir kullanılmamış."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Daha fazla güvenlik gerekli. Şifre bir süredir kullanılmamış."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Daha fazla güvenlik gerekli. Desen bir süredir kullanılmamış."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Daha fazla güvenlik gerekli. Cihazın kilidi bir süredir açılmamış."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Yüzle kilit açılamıyor. Çok deneme yapıldı."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Parmak iziyle kilit açılamıyor. Çok deneme yapıldı."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Güven aracısı kullanılamıyor"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Yanlış PIN\'le çok fazla deneme yapıldı"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Yanlış desenle çok fazla deneme yapıldı"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Yanlış şifreyle çok fazla deneme yapıldı"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# saniye içinde tekrar deneyin.}other{# saniye içinde tekrar deneyin.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN kodunu girin."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" için SIM PIN kodunu girin."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK işlemi başarısız oldu!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Giriş yöntemini değiştir"</string> <string name="airplane_mode" msgid="2528005343938497866">"Uçak modu"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Cihaz yeniden başlatıldıktan sonra desen gerekir"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Cihaz yeniden başlatıldıktan sonra PIN gerekir"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Cihaz yeniden başlatıldıktan sonra şifre gerekir"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ek güvenlik için bunun yerine desen kullanın"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ek güvenlik için bunun yerine PIN kullanın"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ek güvenlik için bunun yerine şifre kullanın"</string> diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml index 7da9b9873343..2fd193452508 100644 --- a/packages/SystemUI/res-keyguard/values-uk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Введіть PIN-код"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Введіть PIN-код"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Введіть ключ"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Намалюйте ключ"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Введіть пароль"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Введіть пароль"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Недійсна картка."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Заряджено"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Бездротове заряджання"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Не вдається вимкнути eSIM-карту через помилку."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Ввести"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Неправильний ключ"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Не той ключ. Спробуйте ще."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Неправильний пароль"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Не той пароль. Спробуйте ще."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Неправильний PIN-код"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Не той PIN. Спробуйте ще."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Або розблокуйте відбитком пальця"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Відбиток не розпізнано"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Обличчя не розпізнано"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Повторіть спробу або введіть PIN-код"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Повторіть спробу або введіть пароль"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Повторіть спробу або намалюйте ключ"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Після кількох невдалих спроб потрібно ввести PIN-код"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Після кількох невдалих спроб потрібно ввести пароль"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Після кількох невдалих спроб потрібно ввести ключ"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Розблокування PIN-кодом або відбитком пальця"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Розблокування паролем або відбитком пальця"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Розблокування ключем або відбитком пальця"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Пристрій заблоковано згідно з правилами організації"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Після блокування входу потрібно ввести PIN-код"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Після блокування входу потрібно ввести пароль"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Після блокування входу потрібно намалювати ключ"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Оновлення встановиться під час годин неактивності"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Потрібен додатковий захист. PIN-код довго не використовувався."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Потрібен додатковий захист. Пароль довго не використовувався."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Потрібен додатковий захист. Ключ довго не використовувався."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Потрібен додатковий захист. Пристрій довго не розблоковувався."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Не розблоковано (фейсконтроль). Забагато спроб."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Не розблоковано (відбиток пальця). Забагато спроб."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Довірчий агент недоступний"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Неправильний PIN-код введено забагато разів"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Неправильний ключ намальовано забагато разів"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Неправильний пароль введено забагато разів"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Повторіть спробу через # секунду.}one{Повторіть спробу через # секунду.}few{Повторіть спробу через # секунди.}many{Повторіть спробу через # секунд.}other{Повторіть спробу через # секунди.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Введіть PIN-код SIM-карти."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Введіть PIN-код SIM-карти для оператора \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Помилка введення PUK-коду SIM-карти."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Змінити метод введення"</string> <string name="airplane_mode" msgid="2528005343938497866">"Режим польоту"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Після перезапуску пристрою потрібно намалювати ключ"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Після перезапуску пристрою потрібно ввести PIN-код"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Після перезапуску пристрою потрібно ввести пароль"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"З міркувань додаткової безпеки скористайтеся ключем"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"З міркувань додаткової безпеки скористайтеся PIN-кодом"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"З міркувань додаткової безпеки скористайтеся паролем"</string> diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml index 4a75afc989d5..596e47768444 100644 --- a/packages/SystemUI/res-keyguard/values-ur/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"اپنا PIN درج کریں"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN درج کریں"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"اپنا پیٹرن درج کریں"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"پیٹرن ڈرا کریں"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"اپنا پاس ورڈ درج کریں"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"پاس ورڈ درج کریں"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"غلط کارڈ۔"</string> <string name="keyguard_charged" msgid="5478247181205188995">"چارج ہوگئی"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • وائرلیس طریقے سے چارج ہو رہا ہے"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"ایک خرابی کی وجہ سے eSIM کو غیر فعال نہیں کیا جا سکتا۔"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"درج کریں"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"غلط پیٹرن"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"غلط پیٹرن۔ پھر کوشش کریں۔"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"غلط پاس ورڈ"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"غلط پاس ورڈ۔ پھر کوشش کریں۔"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"غلط PIN"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"غلط PIN۔ پھر کوشش کریں۔"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"یا فنگر پرنٹ کے ذریعے غیر مقفل کریں"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"فنگر پرنٹ نہیں پہچانا گيا"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"چہرے کی شناخت نہیں ہو سکی"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"دوبارہ کوشش کریں یا PIN درج کریں"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"دوبارہ کوشش کریں یا پاس ورڈ درج کریں"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"دوبارہ کوشش کریں یا پیٹرن ڈرا کریں"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"کئی بار کوشش کر لینے کے بعد PIN کی ضرورت ہوتی ہے"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"کئی بار کوشش کر لینے کے بعد پاس ورڈ کی ضرورت ہوتی ہے"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"کئی بار کوشش کر لینے کے بعد پیٹرن کی ضرورت ہوتی ہے"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN یا فنگر پرنٹ سے غیر مقفل کریں"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"پاس ورڈ یا فنگر پرنٹ سے غیر مقفل کریں"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"پیٹرن یا فنگر پرنٹ سے غیر مقفل کریں"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"اضافی سیکیورٹی کے لیے، آلہ کام سے متعلق پالیسی کے ذریعے مقفل ہوگیا ہے"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"لاک ڈاؤن کے بعد PIN کی ضرورت ہوتی ہے"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"لاک ڈاؤن کے بعد پاس ورڈ کی ضرورت ہوتی ہے"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"لاک ڈاؤن کے بعد پیٹرن کی ضرورت ہوتی ہے"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"اپ ڈیٹ غیر فعال اوقات کے دوران انسٹال ہوگی"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"مزید سیکیورٹی چاہیے۔ PIN کچھ عرصے اسے استعمال نہیں ہوا ہے۔"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"مزید سیکیورٹی چاہیے۔ پاس ورڈ کچھ عرصے سے استعمال نہیں ہوا ہے۔"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"مزید سیکیورٹی چاہیے۔ پیٹرن کچھ عرصے سے استعمال نہیں ہوا ہے۔"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"مزید سیکیورٹی چاہیے۔ آلہ کچھ عرصے سے غیر مقفل نہیں ہوا ہے۔"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"چہرے سے غیر مقفل نہیں ہو سکا۔ کافی زیادہ کوششیں۔"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"فنگر پرنٹ سے غیر مقفل نہیں ہو سکا۔ کافی زیادہ کوششیں۔"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ٹرسٹ ایجنٹ دستیاب نہیں ہے"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"غلط PIN کے ساتھ کافی زیادہ کوششیں"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"غلط پیٹرن کے ساتھ کافی زیادہ کوششیں"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"غلط پاس ورڈ کے ساتھ کافی زیادہ کوششیں"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# سیکنڈ میں دوبارہ کوشش کریں۔}other{# سیکنڈ میں دوبارہ کوشش کریں۔}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN درج کریں۔"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" کیلئے SIM PIN درج کریں۔"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK کارروائی ناکام ہو گئی!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"اندراج کا طریقہ سوئچ کریں"</string> <string name="airplane_mode" msgid="2528005343938497866">"ہوائی جہاز وضع"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"آلہ ری سٹارٹ ہونے کے بعد پیٹرن کی ضرورت ہوتی ہے"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"آلہ ری سٹارٹ ہونے کے بعد PIN کی ضرورت ہوتی ہے"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"آلہ ری سٹارٹ ہونے کے بعد پاس ورڈ کی ضرورت ہوتی ہے"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"اضافی سیکیورٹی کے لئے، اس کے بجائے پیٹرن استعمال کریں"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"اضافی سیکیورٹی کے لئے، اس کے بجائے PIN استعمال کریں"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"اضافی سیکیورٹی کے لئے، اس کے بجائے پاس ورڈ استعمال کریں"</string> diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml index 4c5f4760e05c..0e2a6cfa9513 100644 --- a/packages/SystemUI/res-keyguard/values-uz/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"PIN kodni kiriting"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN kodni kiriting"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Grafik kalitni chizing"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Grafik kalitni chizing"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Parolni kiriting"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Parolni kiriting"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"SIM karta yaroqsiz."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Quvvat oldi"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Simsiz quvvatlanyapti"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Xatolik tufayli eSIM faolsizlantirilmadi."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter tugmasi"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Grafik kalit xato"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Grafik kalit xato. Qayta urining."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Parol xato"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Parol xato. Qayta urining."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN kod xato"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN xato. Qayta urining."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Yoki barmoq izi bilan oching"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Barmoq izi aniqlanmadi"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Yuz aniqlanmadi"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Qayta urining yoki PIN kodni kiriting"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Qayta urining yoki parolni kiriting"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Qayta urining yoki grafik kalitni chizing"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Koʻp marta urindindiz. Pin kodni kiriting"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Koʻp marta urindindiz. Parolni kiriting"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Koʻp marta urindindiz. Grafik kalitni chizing"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN/barmoq izi bilan oching"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Parol/barmoq izi bilan oching"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Grafik kalit/barmoq izi bilan oching"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Qurilma tashkilot qoidalari asosida bloklangan."</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Bloklangandan keyin PIN kodni kiritish kerak"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Bloklangandan keyin parolni kiritish kerak"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Bloklangandan keyin grafik kalitni chizish kerak"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Yangilanish qurilma nofaol boʻlganda oʻrnatiladi"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Xavfsizlikni oshiring. PIN kod ancha vaqt ishlatilmadi."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Xavfsizlikni oshiring. Parol ancha vaqt ishlatilmadi."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Xavfsizlikni oshiring. Grafik kalit ancha vaqt chizilmadi"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Xavfsizlikni oshiring. Qurilma ancha vaqt ochilmadi."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Yuz bilan ochilmadi. Juda koʻp urinildi."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Barmoq izi bilan ochilmadi. Juda koʻp urinildi."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Ishonchli agent mavjud emas"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"PIN kod koʻp marta xato kiritildi"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Grafik kalit koʻp marta xato chizildi"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Parol koʻp marta xato kiritildi"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{# soniyadan keyin qaytadan urining.}other{# soniyadan keyin qayta urining.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM karta PIN kodini kiriting."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"“<xliff:g id="CARRIER">%1$s</xliff:g>” SIM kartasi PIN kodini kiriting."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM kartani qulfdan chiqarib bo‘lmadi!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Matn kiritish usulini almashtirish"</string> <string name="airplane_mode" msgid="2528005343938497866">"Parvoz rejimi"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Qayta yongandan keyin grafik kalit talab etiladi"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Qayta yongandan keyin PIN kod talab etiladi"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Qayta yongandan keyin parol talab etiladi"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Qoʻshimcha xavfsizlik maqsadida oʻrniga grafik kalitdan foydalaning"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Qoʻshimcha xavfsizlik maqsadida oʻrniga PIN koddan foydalaning"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Qoʻshimcha xavfsizlik maqsadida oʻrniga paroldan foydalaning"</string> diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml index 49abeb617ee1..e2d2525a52a7 100644 --- a/packages/SystemUI/res-keyguard/values-vi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Nhập mã PIN của bạn"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Nhập mã PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Nhập hình mở khóa của bạn"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Vẽ hình mở khoá"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Nhập mật khẩu của bạn"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Nhập mật khẩu"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Thẻ không hợp lệ."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Đã sạc đầy"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc không dây"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Không thể tắt eSIM do lỗi."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Nhập"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Hình mở khóa không chính xác"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Sai hình. Hãy thử lại."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Mật khẩu sai"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Sai mật khẩu. Hãy thử lại."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Mã PIN sai"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Sai mã PIN. Hãy thử lại."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Hoặc mở khoá bằng vân tay"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Không nhận dạng được vân tay"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Không nhận dạng được khuôn mặt"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Thử lại hoặc nhập mã PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Thử lại hoặc nhập mật khẩu"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Thử lại hoặc vẽ hình mở khoá"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Bạn đã thử quá nhiều lần, hãy nhập mã PIN"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Bạn đã thử quá nhiều lần, hãy nhập mật khẩu"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Bạn đã thử quá nhiều lần, hãy vẽ hình mở khoá"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Mở khoá bằng mã PIN hoặc vân tay"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Mở khoá bằng mật khẩu hoặc vân tay"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Mở khoá bằng hình mở khoá hoặc vân tay"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Để bảo mật, chính sách nơi làm việc đã khoá thiết bị"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Cần nhập mã PIN sau khi hết thời gian khoá"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Cần nhập mật khẩu sau khi hết thời gian khoá"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Cần vẽ hình mở khoá sau khi hết thời gian khoá"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Bản cập nhật sẽ cài đặt vào các giờ không hoạt động"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Cần tăng cường bảo mật. Đã lâu chưa dùng mã PIN."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Cần tăng cường bảo mật. Đã lâu chưa dùng mật khẩu"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Cần tăng cường bảo mật. Đã lâu chưa dùng hình mở khoá."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Cần tăng cường bảo mật. Đã lâu thiết bị chưa được mở khoá."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Không mở được bằng khuôn mặt. Đã thử quá nhiều lần."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Không mở được bằng vân tay. Đã thử quá nhiều lần."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Không dùng được tác nhân tin cậy"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Bạn đã nhập sai mã PIN quá nhiều lần"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Bạn đã vẽ sai hình mở khoá quá nhiều lần"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Bạn đã nhập sai mật khẩu quá nhiều lần"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Hãy thử lại sau # giây.}other{Hãy thử lại sau # giây.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Nhập mã PIN của SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Nhập mã PIN của SIM dành cho \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Thao tác mã PUK của SIM không thành công!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Chuyển phương thức nhập"</string> <string name="airplane_mode" msgid="2528005343938497866">"Chế độ trên máy bay"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Cần vẽ hình mở khoá sau khi khởi động lại thiết bị"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Cần nhập mã PIN sau khi khởi động lại thiết bị"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Cần nhập mật khẩu sau khi khởi động lại thiết bị"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Để tăng cường bảo mật, hãy sử dụng hình mở khoá"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Để tăng cường bảo mật, hãy sử dụng mã PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Để tăng cường bảo mật, hãy sử dụng mật khẩu"</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml index 685f835a3b5c..2888c374743c 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"输入您的 PIN 码"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"输入 PIN 码"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"绘制您的图案"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"绘制图案"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"输入您的密码"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"输入密码"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"SIM 卡无效。"</string> <string name="keyguard_charged" msgid="5478247181205188995">"已充满电"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在无线充电"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"出现错误,无法停用 eSIM 卡。"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"输入"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"图案错误"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"图案有误。请重试。"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"密码错误"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"密码有误。请重试。"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN 码错误"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN 码有误。请重试。"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"或使用指纹解锁"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"未能识别指纹"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"无法识别面孔"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"请重试,或输入 PIN 码"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"请重试,或输入密码"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"请重试,或绘制图案"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"如果出错的尝试次数太多,必须输入 PIN 码才能解锁"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"如果出错的尝试次数太多,必须输入密码才能解锁"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"如果出错的尝试次数太多,必须绘制图案才能解锁"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"请使用 PIN 码或指纹解锁"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"请使用密码或指纹解锁"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"请使用图案或指纹解锁"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"为提高安全性,工作政策已锁定设备"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"一旦设备被锁定,必须输入 PIN 码才能解锁"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"一旦设备被锁定,必须输入密码才能解锁"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"一旦设备被锁定,必须绘制图案才能解锁"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"可用更新会在设备闲置期间安装"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"需要锁定设备以提高安全性。已有一段时间未使用 PIN 码了。"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"需要锁定设备以提高安全性。已有一段时间未使用密码了。"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"需要锁定设备以提高安全性。已有一段时间未使用图案了。"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"需要锁定设备以提高安全性。设备处于未锁定状态已有一段时间了。"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"无法使用面孔解锁。尝试次数太多。"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"无法使用指纹解锁。尝试次数太多。"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"可信代理已被停用"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"输错 PIN 码的尝试次数太多"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"绘错图案的尝试次数太多"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"输错密码的尝试次数太多"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{请在 # 秒后重试。}other{请在 # 秒后重试。}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"请输入 SIM 卡 PIN 码。"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"请输入“<xliff:g id="CARRIER">%1$s</xliff:g>”的 SIM 卡 PIN 码。"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM 卡 PUK 码操作失败!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"切换输入法"</string> <string name="airplane_mode" msgid="2528005343938497866">"飞行模式"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"设备重启后,必须绘制图案才能解锁"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"设备重启后,必须输入 PIN 码才能解锁"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"设备重启后,必须输入密码才能解锁"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"为增强安全性,请改用图案"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"为增强安全性,请改用 PIN 码"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"为增强安全性,请改用密码"</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml index e36f2941a616..20a0360178ab 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"請輸入 PIN"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"輸入 PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"請畫出圖案"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"畫出解鎖圖案"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"請輸入密碼"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"輸入密碼"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"SIM 卡無效。"</string> <string name="keyguard_charged" msgid="5478247181205188995">"已完成充電"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 無線充電中"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"發生錯誤,因此無法停用此 eSIM 卡。"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter 鍵 (輸入)"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"圖案錯誤"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"圖案錯誤,請再試一次。"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"密碼錯誤"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"密碼錯誤,請再試一次。"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN 碼錯誤"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN 錯誤,請再試一次。"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"或使用指紋解鎖"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"無法辨識指紋"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"無法辨識面孔"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"請再試一次或輸入 PIN"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"請再試一次或輸入密碼"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"請再試一次或畫出解鎖圖案"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"如果嘗試次數太多,需要輸入 PIN 才能解鎖"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"如果嘗試次數太多,需要輸入密碼才能解鎖"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"如果嘗試次數太多,需要畫出解鎖圖案才能解鎖"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"使用 PIN 或指紋解鎖"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"使用密碼或指紋解鎖"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"使用解鎖圖案或指紋解鎖"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"為提高安全性,公司政策已鎖定裝置"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"需要輸入 PIN 才能解除禁閉模式"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"需要輸入密碼解才能解除禁閉模式"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"需要畫出解鎖圖案才能解除禁閉模式"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"裝置會在閒置時安裝更新"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"需要加強安全設定:已有一段時間沒有使用 PIN。"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"需要加強安全設定:已有一段時間沒有使用密碼。"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"需要加強安全設定:已有一段時間沒有使用解鎖圖案。"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"需要加強安全設定:裝置已有一段時間沒有解鎖。"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"嘗試次數太多,因此無法使用面孔解鎖。"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"嘗試次數太多,因此無法使用面孔解鎖。"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"信任代理程式無法使用"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"PIN 錯誤且嘗試次數過多"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"解鎖圖案錯誤且嘗試次數過多"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"密碼錯誤且嘗試次數過多"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{請在 # 秒後再試一次。}other{請在 # 秒後再試一次。}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"輸入 SIM 卡的 PIN 碼。"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"輸入「<xliff:g id="CARRIER">%1$s</xliff:g>」SIM 卡的 PIN 碼。"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"無法使用 SIM 卡 PUK 碼解鎖!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"轉換輸入方法"</string> <string name="airplane_mode" msgid="2528005343938497866">"飛行模式"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"裝置重新啟動後,需要畫出解鎖圖案才能解鎖"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"裝置重新啟動後,需要輸入 PIN 才能解鎖"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"裝置重新啟動後,需要輸入密碼才能解鎖"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"為提升安全性,請改用圖案"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"為提升安全性,請改用 PIN"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"為提升安全性,請改用密碼"</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml index cd3e7a4580d9..b73e803c5a34 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"輸入 PIN 碼"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"輸入 PIN 碼"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"畫出解鎖圖案"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"畫出解鎖圖案"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"輸入密碼"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"輸入密碼"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"卡片無效。"</string> <string name="keyguard_charged" msgid="5478247181205188995">"充電完成"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 無線充電"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"發生錯誤,因此無法停用 eSIM 卡。"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter 鍵"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"圖案錯誤"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"解鎖圖案錯誤,請再試一次。"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"密碼錯誤"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"密碼錯誤,請再試一次。"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN 碼錯誤"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN 碼錯誤,請再試一次。"</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"或使用指紋解鎖"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"無法辨識指紋"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"無法辨識臉孔"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"請再試一次或輸入 PIN 碼"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"請再試一次或輸入密碼"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"請再試一次或畫出解鎖圖案"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"如果錯誤次數過多,必須輸入 PIN 碼才能解鎖"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"如果錯誤次數過多,必須輸入密碼才能解鎖"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"如果錯誤數過多,必須畫出解鎖圖案才能解鎖"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"使用 PIN 碼或指紋解鎖"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"使用密碼或指紋解鎖"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"使用解鎖圖案或指紋解鎖"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"為提高安全性,公司政策已鎖定裝置"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"裝置鎖定後,必須輸入 PIN 碼才能解鎖"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"裝置鎖定後,必須輸入密碼才能解鎖"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"裝置鎖定後,必須畫出解鎖圖案才能解鎖"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"裝置會在閒置時安裝更新"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"裝置已有一段時間未鎖定,請使用 PIN 碼鎖定裝置以策安全。"</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"裝置已有一段時間未鎖定,請使用密碼鎖定裝置以策安全。"</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"裝置已有一段時間未鎖定,請使用解鎖圖案鎖定裝置以策安全。"</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"裝置已有一段時間未鎖定,請鎖定裝置以策安全。"</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"錯誤次數過多,因此無法使用臉孔解鎖。"</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"錯誤次數過多,因此無法使用指紋解鎖。"</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"信任的代理程式無法使用"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"PIN 碼錯誤次數過多"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"解鎖圖案錯誤次數過多"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"密碼錯誤次數過多"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{請於 # 秒後再試一次。}other{請於 # 秒後再試一次。}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"輸入 SIM 卡的 PIN 碼。"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"輸入「<xliff:g id="CARRIER">%1$s</xliff:g>」SIM 卡的 PIN 碼。"</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM 卡 PUK 碼解鎖失敗!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"切換輸入法"</string> <string name="airplane_mode" msgid="2528005343938497866">"飛航模式"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"裝置重新啟動後,必須畫出解鎖圖案才能解鎖"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"裝置重新啟動後,必須輸入 PIN 碼才能解鎖"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"裝置重新啟動後,必須輸入密碼才能解鎖"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"為強化安全性,請改用解鎖圖案"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"為強化安全性,請改用 PIN 碼"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"為強化安全性,請改用密碼"</string> diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml index 01cf8cff0e82..6a2d36810250 100644 --- a/packages/SystemUI/res-keyguard/values-zu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml @@ -21,14 +21,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Faka iPHINIKHODI yakho"</string> - <!-- no translation found for keyguard_enter_pin (8114529922480276834) --> - <skip /> + <string name="keyguard_enter_pin" msgid="8114529922480276834">"Faka i-PIN"</string> <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Faka iphethini yakho"</string> - <!-- no translation found for keyguard_enter_pattern (7616595160901084119) --> - <skip /> + <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Dweba iphethini"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Faka iphasiwedi yakho"</string> - <!-- no translation found for keyguard_enter_password (6483623792371009758) --> - <skip /> + <string name="keyguard_enter_password" msgid="6483623792371009758">"Faka iphasiwedi"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ikhadi elingavumelekile."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Kushajiwe"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Iyashaja ngaphandle kwentambo"</string> @@ -58,68 +55,38 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"I-eSIM ayikwakhi ukukhutshazwa ngenxa yephutha."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Faka"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"Iphethini engalungile"</string> - <!-- no translation found for kg_wrong_pattern_try_again (3603524940234151881) --> - <skip /> + <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Iphethini engalungile. Zama futhi."</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Iphasiwedi engalungile"</string> - <!-- no translation found for kg_wrong_password_try_again (6602878676125765920) --> - <skip /> + <string name="kg_wrong_password_try_again" msgid="6602878676125765920">"Iphasiwedi engalungile. Zama futhi."</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Iphinikhodi engalungile"</string> - <!-- no translation found for kg_wrong_pin_try_again (3129729383303430190) --> - <skip /> - <!-- no translation found for kg_wrong_input_try_fp_suggestion (3143861542242024833) --> - <skip /> - <!-- no translation found for kg_fp_not_recognized (5183108260932029241) --> - <skip /> - <!-- no translation found for bouncer_face_not_recognized (1666128054475597485) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pin (4752168242723808390) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_password (1473132729225398039) --> - <skip /> - <!-- no translation found for kg_bio_try_again_or_pattern (4867893307468801501) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pin (5850845723433047605) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_password (5551690347827728042) --> - <skip /> - <!-- no translation found for kg_bio_too_many_attempts_pattern (736884689355181602) --> - <skip /> - <!-- no translation found for kg_unlock_with_pin_or_fp (5635161174698729890) --> - <skip /> - <!-- no translation found for kg_unlock_with_password_or_fp (2251295907826814237) --> - <skip /> - <!-- no translation found for kg_unlock_with_pattern_or_fp (2391870539909135046) --> - <skip /> - <!-- no translation found for kg_prompt_after_dpm_lock (6002804765868345917) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pin (5374732179740050373) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_password (9097968458291129795) --> - <skip /> - <!-- no translation found for kg_prompt_after_user_lockdown_pattern (215072203613597906) --> - <skip /> - <!-- no translation found for kg_prompt_unattended_update (8223448855578632202) --> - <skip /> - <!-- no translation found for kg_prompt_pin_auth_timeout (5868644725126275245) --> - <skip /> - <!-- no translation found for kg_prompt_password_auth_timeout (5809110458491920871) --> - <skip /> - <!-- no translation found for kg_prompt_pattern_auth_timeout (1860605401869262178) --> - <skip /> - <!-- no translation found for kg_prompt_auth_timeout (6620679830980315048) --> - <skip /> - <!-- no translation found for kg_face_locked_out (2751559491287575) --> - <skip /> - <!-- no translation found for kg_fp_locked_out (6228277682396768830) --> - <skip /> - <!-- no translation found for kg_trust_agent_disabled (5400691179958727891) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pin (5492230176361601475) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_pattern (8266214607346180952) --> - <skip /> - <!-- no translation found for kg_primary_auth_locked_out_password (6170245108400198659) --> - <skip /> + <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"I-PIN okungeyona. Zama futhi."</string> + <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Noma vula ngezigxivizo zeminwe"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Isigxivizo somunwe asaziwa"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Ubuso abaziwa"</string> + <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Zama futhi noma faka iphinikhodi"</string> + <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Zama futhi noma faka iphasiwedi"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Zama futhi noma dweba iphethini"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"Iphinikhodi iyadingeka ngemva kwemizamo eminingi kakhulu"</string> + <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Iphasiwedi iyadingeka ngemva kwemizamo eminingi kakhulu"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Iphethini iyadingeka ngemva kwemizamo eminingi kakhulu"</string> + <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Vula ngephethini noma izigxivizo zeminwe"</string> + <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Vula ngephasiwedi noma ngezigxivizo zeminwe"</string> + <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Vula ngephethini noma isigxivizo somunwe"</string> + <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Ngokuphepha okungeziwe, idivayisi ikhiyiwe ngenqubomgomo yomsebenzi"</string> + <string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Iphinikhodi iyadingeka ngemva kokukhiya"</string> + <string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Iphasiwedi iyadingeka ngemuva kokukhiya"</string> + <string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Iphethini iyadingeka ngemva kokukhiya"</string> + <string name="kg_prompt_unattended_update" msgid="8223448855578632202">"Isibuyekezo sizongena phakathi namahora okungasebenzi"</string> + <string name="kg_prompt_pin_auth_timeout" msgid="5868644725126275245">"Ukuphepha okwengeziwe kuyadingeka. Iphinikhodi ayisetshenziswanga isikhathi eside."</string> + <string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Ukuphepha okwengeziwe kuyadingeka. Iphasiwedi ayisetshenziswanga isikhathi eside."</string> + <string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Ukuphepha okwengeziwe kuyadingeka. Iphethini ayisetshenziswanga isikhathi eside."</string> + <string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Ukuphepha okwengeziwe kuyadingeka. Idivayisi ayizange ivulwe isikhathi eside."</string> + <string name="kg_face_locked_out" msgid="2751559491287575">"Ayikwazi ukuvula ngobuso. Imizamo eminingi kakhulu."</string> + <string name="kg_fp_locked_out" msgid="6228277682396768830">"Ayikwazi ukuvula ngesigxivizo somunwe. Imizamo eminingi kakhulu."</string> + <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Umenzeli othembekile akatholakali"</string> + <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Imizamo eminingi kakhulu Ngephinikhodi engalungile"</string> + <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Imizamo eminingi kakhulu enephethini engalungile"</string> + <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Imizamo eminingi kakhulu enephasiwedi engalungile"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Zama futhi kumzuzwana ongu-#.}one{Zama futhi kumizuzwana engu-#.}other{Zama futhi kumizuzwana engu-#.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Faka i-PIN ye-SIM"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Faka i-PIN ye-SIM ye-\"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string> @@ -142,12 +109,9 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Umsebenzi we-PUK ye-SIM wehlulekile!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Shintsha indlela yokufaka"</string> <string name="airplane_mode" msgid="2528005343938497866">"Imodi yendiza"</string> - <!-- no translation found for kg_prompt_reason_restart_pattern (3321211830602827742) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_pin (2672166323886110512) --> - <skip /> - <!-- no translation found for kg_prompt_reason_restart_password (3967993994418885887) --> - <skip /> + <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Iphethini iyadingeka ngemva kokuthi idivayisi iqale kabusha"</string> + <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Iphinikhodi iyadingeka ngemva kokuthi idivayisi iqale kabusha"</string> + <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Iphasiwedi iyadingeka ngemuva kokuthi idivayisi iqale kabusha"</string> <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa iphetheni esikhundleni salokho"</string> <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa i-PIN esikhundleni salokho"</string> <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa iphasiwedi esikhundleni salokho"</string> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 2143fc4db852..edd3047203b3 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -21,19 +21,19 @@ <!-- Instructions telling the user to enter their PIN password to unlock the keyguard [CHAR LIMIT=30] --> <string name="keyguard_enter_your_pin">Enter your PIN</string> - <!-- Instructions telling the user to enter their PIN password to unlock the keyguard [CHAR LIMIT=26] --> + <!-- Instructions telling the user to enter their PIN password to unlock the keyguard [CHAR LIMIT=48] --> <string name="keyguard_enter_pin">Enter PIN</string> <!-- Instructions telling the user to enter their pattern to unlock the keyguard [CHAR LIMIT=30] --> <string name="keyguard_enter_your_pattern">Enter your pattern</string> - <!-- Instructions telling the user to enter their pattern to unlock the keyguard [CHAR LIMIT=26] --> + <!-- Instructions telling the user to enter their pattern to unlock the keyguard [CHAR LIMIT=48] --> <string name="keyguard_enter_pattern">Draw pattern</string> <!-- Instructions telling the user to enter their text password to unlock the keyguard [CHAR LIMIT=30] --> <string name="keyguard_enter_your_password">Enter your password</string> - <!-- Instructions telling the user to enter their text password to unlock the keyguard [CHAR LIMIT=26] --> + <!-- Instructions telling the user to enter their text password to unlock the keyguard [CHAR LIMIT=48] --> <string name="keyguard_enter_password">Enter password</string> <!-- Shown in the lock screen when there is SIM card IO error. --> @@ -128,103 +128,103 @@ <!-- Message shown when user enters wrong pattern --> <string name="kg_wrong_pattern">Wrong pattern</string> - <!-- Message shown when user enters wrong pattern [CHAR LIMIT=26] --> + <!-- Message shown when user enters wrong pattern [CHAR LIMIT=48] --> <string name="kg_wrong_pattern_try_again">Wrong pattern. Try again.</string> <!-- Message shown when user enters wrong password --> <string name="kg_wrong_password">Wrong password</string> - <!-- Message shown when user enters wrong pattern [CHAR LIMIT=26] --> + <!-- Message shown when user enters wrong pattern [CHAR LIMIT=48] --> <string name="kg_wrong_password_try_again">Wrong password. Try again.</string> <!-- Message shown when user enters wrong PIN --> <string name="kg_wrong_pin">Wrong PIN</string> - <!-- Message shown when user enters wrong PIN [CHAR LIMIT=26] --> + <!-- Message shown when user enters wrong PIN [CHAR LIMIT=48] --> <string name="kg_wrong_pin_try_again">Wrong PIN. Try again.</string> - <!-- Message shown when user enters wrong PIN/password/pattern below the main message, for ex: "Wrong PIN. Try again" in line 1 and the following text in line 2. [CHAR LIMIT=52] --> + <!-- Message shown when user enters wrong PIN/password/pattern below the main message, for ex: "Wrong PIN. Try again" in line 1 and the following text in line 2. [CHAR LIMIT=70] --> <string name="kg_wrong_input_try_fp_suggestion">Or unlock with fingerprint</string> - <!-- Message shown when user fingerprint is not recognized [CHAR LIMIT=26] --> + <!-- Message shown when user fingerprint is not recognized [CHAR LIMIT=48] --> <string name="kg_fp_not_recognized">Fingerprint not recognized</string> - <!-- Message shown when we want the users to try biometric auth again or use pin/pattern/password [CHAR LIMIT=26] --> + <!-- Message shown when we want the users to try biometric auth again or use pin/pattern/password [CHAR LIMIT=48] --> <string name="bouncer_face_not_recognized">Face not recognized</string> - <!-- Message shown when we want the users to try biometric auth again or use pin/pattern/password [CHAR LIMIT=52] --> + <!-- Message shown when we want the users to try biometric auth again or use pin/pattern/password [CHAR LIMIT=70] --> <string name="kg_bio_try_again_or_pin">Try again or enter PIN</string> - <!-- Message shown when we want the users to try biometric auth again or use pin/pattern/password [CHAR LIMIT=52] --> + <!-- Message shown when we want the users to try biometric auth again or use pin/pattern/password [CHAR LIMIT=70] --> <string name="kg_bio_try_again_or_password">Try again or enter password</string> - <!-- Message shown when we want the users to try biometric auth again or use pin/pattern/password [CHAR LIMIT=52] --> + <!-- Message shown when we want the users to try biometric auth again or use pin/pattern/password [CHAR LIMIT=70] --> <string name="kg_bio_try_again_or_pattern">Try again or draw pattern</string> - <!-- Message shown when we are on bouncer after temporary lockout of either face or fingerprint [CHAR LIMIT=52] --> + <!-- Message shown when we are on bouncer after temporary lockout of either face or fingerprint [CHAR LIMIT=70] --> <string name="kg_bio_too_many_attempts_pin">PIN is required after too many attempts</string> - <!-- Message shown when we are on bouncer after temporary lockout of either face or fingerprint [CHAR LIMIT=52] --> + <!-- Message shown when we are on bouncer after temporary lockout of either face or fingerprint [CHAR LIMIT=70] --> <string name="kg_bio_too_many_attempts_password">Password is required after too many attempts</string> - <!-- Message shown when we are on bouncer after temporary lockout of either face or fingerprint [CHAR LIMIT=52] --> + <!-- Message shown when we are on bouncer after temporary lockout of either face or fingerprint [CHAR LIMIT=70] --> <string name="kg_bio_too_many_attempts_pattern">Pattern is required after too many attempts</string> - <!-- Instructions when the user can unlock with PIN/password/pattern or fingerprint from bouncer. [CHAR LIMIT=26] --> + <!-- Instructions when the user can unlock with PIN/password/pattern or fingerprint from bouncer. [CHAR LIMIT=48] --> <string name="kg_unlock_with_pin_or_fp">Unlock with PIN or fingerprint</string> - <!-- Instructions when the user can unlock with PIN/password/pattern or fingerprint from bouncer. [CHAR LIMIT=26] --> + <!-- Instructions when the user can unlock with PIN/password/pattern or fingerprint from bouncer. [CHAR LIMIT=48] --> <string name="kg_unlock_with_password_or_fp">Unlock with password or fingerprint</string> - <!-- Instructions when the user can unlock with PIN/password/pattern or fingerprint from bouncer. [CHAR LIMIT=26] --> + <!-- Instructions when the user can unlock with PIN/password/pattern or fingerprint from bouncer. [CHAR LIMIT=48] --> <string name="kg_unlock_with_pattern_or_fp">Unlock with pattern or fingerprint</string> - <!-- Message shown when we are on bouncer after Device admin requested lockdown. [CHAR LIMIT=52] --> + <!-- Message shown when we are on bouncer after Device admin requested lockdown. [CHAR LIMIT=70] --> <string name="kg_prompt_after_dpm_lock">For added security, device was locked by work policy</string> - <!-- Message shown for pin/pattern/password when we are on bouncer after user triggered lockdown. [CHAR LIMIT=52] --> + <!-- Message shown for pin/pattern/password when we are on bouncer after user triggered lockdown. [CHAR LIMIT=70] --> <string name="kg_prompt_after_user_lockdown_pin">PIN is required after lockdown</string> - <!-- Message shown for pin/pattern/password when we are on bouncer after user triggered lockdown. [CHAR LIMIT=52] --> + <!-- Message shown for pin/pattern/password when we are on bouncer after user triggered lockdown. [CHAR LIMIT=70] --> <string name="kg_prompt_after_user_lockdown_password">Password is required after lockdown</string> - <!-- Message shown for pin/pattern/password when we are on bouncer after user triggered lockdown. [CHAR LIMIT=52] --> + <!-- Message shown for pin/pattern/password when we are on bouncer after user triggered lockdown. [CHAR LIMIT=70] --> <string name="kg_prompt_after_user_lockdown_pattern">Pattern is required after lockdown</string> - <!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=52] --> + <!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] --> <string name="kg_prompt_unattended_update">Update will install during inactive hours</string> - <!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=52] --> + <!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=70] --> <string name="kg_prompt_pin_auth_timeout">Added security required. PIN not used for a while.</string> - <!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=52] --> + <!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=70] --> <string name="kg_prompt_password_auth_timeout">Added security required. Password not used for a while.</string> - <!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=52] --> + <!-- Message shown when primary authentication hasn't been used for some time. [CHAR LIMIT=76] --> <string name="kg_prompt_pattern_auth_timeout">Added security required. Pattern not used for a while.</string> - <!-- Message shown when device hasn't been unlocked for a while. [CHAR LIMIT=52] --> + <!-- Message shown when device hasn't been unlocked for a while. [CHAR LIMIT=82] --> <string name="kg_prompt_auth_timeout">Added security required. Device wasn\u2019t unlocked for a while.</string> - <!-- Message shown when face unlock is not available after too many failed face authentication attempts. [CHAR LIMIT=52] --> + <!-- Message shown when face unlock is not available after too many failed face authentication attempts. [CHAR LIMIT=70] --> <string name="kg_face_locked_out">Can\u2019t unlock with face. Too many attempts.</string> - <!-- Message shown when fingerprint unlock isn't available after too many failed fingerprint authentication attempts. [CHAR LIMIT=52] --> + <!-- Message shown when fingerprint unlock isn't available after too many failed fingerprint authentication attempts. [CHAR LIMIT=75] --> <string name="kg_fp_locked_out">Can\u2019t unlock with fingerprint. Too many attempts.</string> - <!-- Message shown when Trust Agent is disabled. [CHAR LIMIT=52] --> + <!-- Message shown when Trust Agent is disabled. [CHAR LIMIT=70] --> <string name="kg_trust_agent_disabled">Trust agent is unavailable</string> - <!-- Message shown when primary auth is locked out after too many attempts [CHAR LIMIT=52] --> + <!-- Message shown when primary auth is locked out after too many attempts [CHAR LIMIT=70] --> <string name="kg_primary_auth_locked_out_pin">Too many attempts with incorrect PIN</string> - <!-- Message shown when primary auth is locked out after too many attempts [CHAR LIMIT=52] --> + <!-- Message shown when primary auth is locked out after too many attempts [CHAR LIMIT=70] --> <string name="kg_primary_auth_locked_out_pattern">Too many attempts with incorrect pattern</string> - <!-- Message shown when primary auth is locked out after too many attempts [CHAR LIMIT=52] --> + <!-- Message shown when primary auth is locked out after too many attempts [CHAR LIMIT=70] --> <string name="kg_primary_auth_locked_out_password">Too many attempts with incorrect password</string> - <!-- Countdown message shown after too many failed unlock attempts [CHAR LIMIT=26]--> + <!-- Countdown message shown after too many failed unlock attempts [CHAR LIMIT=48]--> <string name="kg_too_many_failed_attempts_countdown">{count, plural, =1 {Try again in # second.} other {Try again in # seconds.} @@ -296,13 +296,13 @@ <!-- Description of airplane mode --> <string name="airplane_mode">Airplane mode</string> - <!-- An explanation text that the pattern needs to be solved since the device has just been restarted. [CHAR LIMIT=52] --> + <!-- An explanation text that the pattern needs to be solved since the device has just been restarted. [CHAR LIMIT=70] --> <string name="kg_prompt_reason_restart_pattern">Pattern is required after device restarts</string> - <!-- An explanation text that the pin needs to be entered since the device has just been restarted. [CHAR LIMIT=52] --> + <!-- An explanation text that the pin needs to be entered since the device has just been restarted. [CHAR LIMIT=70] --> <string name="kg_prompt_reason_restart_pin">PIN is required after device restarts</string> - <!-- An explanation text that the password needs to be entered since the device has just been restarted. [CHAR LIMIT=52] --> + <!-- An explanation text that the password needs to be entered since the device has just been restarted. [CHAR LIMIT=70] --> <string name="kg_prompt_reason_restart_password">Password is required after device restarts</string> <!-- An explanation text that the pattern needs to be solved since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] --> diff --git a/packages/SystemUI/res/anim/keyguard_settings_popup_ease_out_interpolator.xml b/packages/SystemUI/res/anim/keyguard_settings_popup_ease_out_interpolator.xml new file mode 100644 index 000000000000..8c2937c8c483 --- /dev/null +++ b/packages/SystemUI/res/anim/keyguard_settings_popup_ease_out_interpolator.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<pathInterpolator + xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.30" + android:controlY1="0.00" + android:controlX2="0.33" + android:controlY2="1.00" /> diff --git a/packages/SystemUI/res/anim/long_press_lock_screen_popup_enter.xml b/packages/SystemUI/res/anim/long_press_lock_screen_popup_enter.xml new file mode 100644 index 000000000000..5fa88224968b --- /dev/null +++ b/packages/SystemUI/res/anim/long_press_lock_screen_popup_enter.xml @@ -0,0 +1,49 @@ +<?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. + --> + +<set + xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false"> + + <scale + android:interpolator="@android:anim/accelerate_decelerate_interpolator" + android:duration="200" + android:fromXScale="0.5" + android:fromYScale="0.5" + android:toXScale="1.02" + android:toYScale="1.02" + android:pivotX="50%" + android:pivotY="50%" /> + + <scale + android:interpolator="@anim/keyguard_settings_popup_ease_out_interpolator" + android:startOffset="200" + android:duration="200" + android:fromXScale="1" + android:fromYScale="1" + android:toXScale="0.98" + android:toYScale="0.98" + android:pivotX="50%" + android:pivotY="50%" /> + + <alpha + android:interpolator="@android:anim/linear_interpolator" + android:duration="83" + android:fromAlpha="0" + android:toAlpha="1" /> + +</set> diff --git a/packages/SystemUI/res/anim/long_press_lock_screen_popup_exit.xml b/packages/SystemUI/res/anim/long_press_lock_screen_popup_exit.xml new file mode 100644 index 000000000000..a6938defd4be --- /dev/null +++ b/packages/SystemUI/res/anim/long_press_lock_screen_popup_exit.xml @@ -0,0 +1,39 @@ +<?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. + --> + +<set + xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false"> + + <scale + android:interpolator="@android:anim/accelerate_interpolator" + android:duration="233" + android:fromXScale="1" + android:fromYScale="1" + android:toXScale="0.5" + android:toYScale="0.5" + android:pivotX="50%" + android:pivotY="50%" /> + + <alpha + android:interpolator="@android:anim/linear_interpolator" + android:delay="150" + android:duration="83" + android:fromAlpha="1" + android:toAlpha="0" /> + +</set> diff --git a/packages/SystemUI/res/drawable/chipbar_background.xml b/packages/SystemUI/res/drawable/chipbar_background.xml index 57221776a32f..7530f5ba244a 100644 --- a/packages/SystemUI/res/drawable/chipbar_background.xml +++ b/packages/SystemUI/res/drawable/chipbar_background.xml @@ -17,6 +17,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <solid android:color="?androidprv:attr/colorAccentSecondary" /> + <solid android:color="?androidprv:attr/materialColorSecondaryFixed" /> <corners android:radius="32dp" /> </shape> diff --git a/packages/SystemUI/res/drawable/chipbar_end_button_background.xml b/packages/SystemUI/res/drawable/chipbar_end_button_background.xml index 80c7207a35b6..a3832eef957f 100644 --- a/packages/SystemUI/res/drawable/chipbar_end_button_background.xml +++ b/packages/SystemUI/res/drawable/chipbar_end_button_background.xml @@ -20,7 +20,7 @@ android:color="?android:textColorPrimary"> <item android:id="@android:id/background"> <shape> - <solid android:color="@android:color/system_accent1_200"/> + <solid android:color="?androidprv:attr/materialColorPrimaryFixedDim"/> <corners android:radius="24dp" /> </shape> </item> diff --git a/packages/SystemUI/res/drawable/hearing.xml b/packages/SystemUI/res/drawable/hearing.xml new file mode 100644 index 000000000000..02f5f92ec5fe --- /dev/null +++ b/packages/SystemUI/res/drawable/hearing.xml @@ -0,0 +1,24 @@ +<!-- 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="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M34.4,43.95Q31.55,43.95 29.45,42.4Q27.35,40.85 26.35,38.3Q25.35,35.75 24.375,34.325Q23.4,32.9 20.7,30.75Q17.4,28.1 15.95,25.1Q14.5,22.1 14.5,17.8Q14.5,11.8 18.3,7.975Q22.1,4.15 28.1,4.15Q34,4.15 37.875,7.825Q41.75,11.5 42,17.2H39Q38.75,12.8 35.725,9.975Q32.7,7.15 28.1,7.15Q23.6,7.15 20.55,10.225Q17.5,13.3 17.5,17.8Q17.5,21.4 18.9,24.025Q20.3,26.65 23.55,29.1Q25.5,30.55 26.675,32.25Q27.85,33.95 28.9,36.45Q29.75,38.55 31.125,39.75Q32.5,40.95 34.4,40.95Q36.15,40.95 37.425,39.75Q38.7,38.55 38.95,36.8H41.95Q41.7,39.8 39.55,41.875Q37.4,43.95 34.4,43.95ZM11.95,32.9Q9.1,29.75 7.55,25.825Q6,21.9 6,17.6Q6,13.35 7.475,9.375Q8.95,5.4 11.95,2.35L14.2,4.35Q11.6,7 10.3,10.425Q9,13.85 9,17.6Q9,21.3 10.325,24.725Q11.65,28.15 14.2,30.85ZM28.1,22.45Q26.15,22.45 24.8,21.1Q23.45,19.75 23.45,17.8Q23.45,15.85 24.8,14.45Q26.15,13.05 28.1,13.05Q30.05,13.05 31.45,14.45Q32.85,15.85 32.85,17.8Q32.85,19.75 31.45,21.1Q30.05,22.45 28.1,22.45Z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml b/packages/SystemUI/res/drawable/ic_shade_no_calling_sms.xml index da581061370b..da581061370b 100644 --- a/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml +++ b/packages/SystemUI/res/drawable/ic_shade_no_calling_sms.xml diff --git a/packages/SystemUI/res/drawable/ic_qs_sim_card.xml b/packages/SystemUI/res/drawable/ic_shade_sim_card.xml index 6eda929b54d3..6eda929b54d3 100644 --- a/packages/SystemUI/res/drawable/ic_qs_sim_card.xml +++ b/packages/SystemUI/res/drawable/ic_shade_sim_card.xml diff --git a/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml b/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml index 3807b92ae39d..a0ceb81d42f4 100644 --- a/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml +++ b/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml @@ -17,17 +17,17 @@ <ripple xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - android:color="?android:attr/colorControlHighlight"> + android:color="#4d000000"> <item android:id="@android:id/mask"> <shape android:shape="rectangle"> <solid android:color="@android:color/white"/> - <corners android:radius="28dp" /> + <corners android:radius="@dimen/keyguard_affordance_fixed_radius" /> </shape> </item> <item> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/colorSurface" /> - <corners android:radius="28dp" /> + <solid android:color="?androidprv:attr/materialColorOnBackground" /> + <corners android:radius="@dimen/keyguard_affordance_fixed_radius" /> </shape> </item> </ripple> diff --git a/packages/SystemUI/res/layout/chipbar.xml b/packages/SystemUI/res/layout/chipbar.xml index 762dcdced9c4..8fa975be43d2 100644 --- a/packages/SystemUI/res/layout/chipbar.xml +++ b/packages/SystemUI/res/layout/chipbar.xml @@ -49,15 +49,17 @@ android:alpha="0.0" /> + <!-- LINT.IfChange textColor --> <TextView android:id="@+id/text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:textSize="@dimen/chipbar_text_size" - android:textColor="@color/chipbar_text_and_icon_color" + style="@style/Chipbar.Text" + android:textColor="?androidprv:attr/materialColorOnSecondaryFixed" android:alpha="0.0" /> + <!-- LINT.ThenChange(systemui.temporarydisplay.chipbar.ChipbarInfo.kt) --> <!-- At most one of [loading, failure_icon, undo] will be visible at a time. --> <ImageView @@ -66,7 +68,7 @@ android:layout_height="@dimen/chipbar_end_icon_size" android:layout_marginStart="@dimen/chipbar_end_item_start_margin" android:src="@drawable/ic_progress_activity" - android:tint="@android:color/system_accent2_700" + android:tint="?androidprv:attr/materialColorOnSecondaryFixedVariant" android:alpha="0.0" /> @@ -84,9 +86,9 @@ android:id="@+id/end_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textColor="?androidprv:attr/textColorOnAccent" android:layout_marginStart="@dimen/chipbar_end_item_start_margin" - android:textSize="@dimen/chipbar_text_size" + style="@style/Chipbar.Text" + android:textColor="?androidprv:attr/materialColorOnPrimaryFixed" android:paddingStart="@dimen/chipbar_outer_padding" android:paddingEnd="@dimen/chipbar_outer_padding" android:paddingTop="@dimen/chipbar_end_button_vertical_padding" diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml index dffe40b8454a..441f963a855a 100644 --- a/packages/SystemUI/res/layout/combined_qs_header.xml +++ b/packages/SystemUI/res/layout/combined_qs_header.xml @@ -94,7 +94,7 @@ <include android:id="@+id/carrier_group" - layout="@layout/qs_carrier_group" + layout="@layout/shade_carrier_group" app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height" android:minHeight="@dimen/large_screen_shade_header_min_height" app:layout_constraintWidth_min="48dp" diff --git a/packages/SystemUI/res/layout/controls_more_item.xml b/packages/SystemUI/res/layout/controls_more_item.xml index da9c43ccc1e9..73d1c54b1c64 100644 --- a/packages/SystemUI/res/layout/controls_more_item.xml +++ b/packages/SystemUI/res/layout/controls_more_item.xml @@ -13,13 +13,17 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/controls_more_item_text" style="@style/Control.MenuItem" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="start" + android:layout_height="@dimen/control_menu_item_height" + android:layout_gravity="center_vertical" + android:background="@drawable/controls_popup_item_background" android:paddingStart="@dimen/control_menu_horizontal_padding" android:paddingEnd="@dimen/control_menu_horizontal_padding" - android:textDirection="locale"/> - + android:textDirection="locale" + android:textSize="@dimen/control_item_text_size" + tools:fontFamily="@null" + tools:text="@tools:sample/lorem/random" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/controls_spinner_item.xml b/packages/SystemUI/res/layout/controls_spinner_item.xml index 4048d0371aa8..811965121702 100644 --- a/packages/SystemUI/res/layout/controls_spinner_item.xml +++ b/packages/SystemUI/res/layout/controls_spinner_item.xml @@ -16,18 +16,18 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="@dimen/control_popup_item_height" + android:layout_height="@dimen/control_apps_popup_item_height" android:background="@drawable/controls_popup_item_background" android:gravity="center_vertical|start" android:orientation="horizontal" - android:paddingStart="@dimen/control_popup_item_padding" - android:paddingEnd="@dimen/control_popup_item_padding"> + android:paddingStart="@dimen/control_menu_horizontal_padding" + android:paddingEnd="@dimen/control_menu_horizontal_padding"> <ImageView android:id="@+id/app_icon" android:layout_width="@dimen/controls_header_app_icon_size" android:layout_height="@dimen/controls_header_app_icon_size" - android:layout_marginEnd="@dimen/control_popup_item_padding" + android:layout_marginEnd="@dimen/control_menu_horizontal_padding" android:contentDescription="@null" tools:src="@drawable/ic_android" /> diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 4048a39344bd..e9acf3fa10c8 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -20,7 +20,7 @@ android:id="@+id/keyguard_bottom_area" android:layout_height="match_parent" android:layout_width="match_parent" - android:outlineProvider="none" > <!-- Put it above the status bar header --> + android:outlineProvider="none" > <LinearLayout android:id="@+id/keyguard_indication_area" @@ -59,33 +59,55 @@ </LinearLayout> - <com.android.systemui.animation.view.LaunchableImageView - android:id="@+id/start_button" - android:layout_height="@dimen/keyguard_affordance_fixed_height" - android:layout_width="@dimen/keyguard_affordance_fixed_width" - android:layout_gravity="bottom|start" - 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" - android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset" + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_gravity="bottom" + android:layout_marginHorizontal="@dimen/keyguard_affordance_horizontal_offset" android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset" - android:visibility="gone" /> + android:gravity="bottom" + > - <com.android.systemui.animation.view.LaunchableImageView - android:id="@+id/end_button" - android:layout_height="@dimen/keyguard_affordance_fixed_height" - android:layout_width="@dimen/keyguard_affordance_fixed_width" - android:layout_gravity="bottom|end" - 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" - android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset" - android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset" - android:visibility="gone" /> + <com.android.systemui.animation.view.LaunchableImageView + android:id="@+id/start_button" + android:layout_height="@dimen/keyguard_affordance_fixed_height" + android:layout_width="@dimen/keyguard_affordance_fixed_width" + 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" + android:visibility="invisible" /> + + <FrameLayout + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="wrap_content" + android:paddingHorizontal="24dp" + > + <include + android:id="@+id/keyguard_settings_button" + layout="@layout/keyguard_settings_popup_menu" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="gone" + /> + </FrameLayout> + + <com.android.systemui.animation.view.LaunchableImageView + android:id="@+id/end_button" + android:layout_height="@dimen/keyguard_affordance_fixed_height" + android:layout_width="@dimen/keyguard_affordance_fixed_width" + 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" + android:visibility="invisible" /> + + </LinearLayout> <FrameLayout android:id="@+id/overlay_container" diff --git a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml index 89d88fea1817..65ee8b370f9b 100644 --- a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml +++ b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml @@ -15,25 +15,24 @@ ~ --> -<LinearLayout +<com.android.systemui.animation.view.LaunchableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:minHeight="52dp" + android:minHeight="@dimen/keyguard_affordance_fixed_height" android:orientation="horizontal" android:gravity="center_vertical" android:background="@drawable/keyguard_settings_popup_menu_background" - android:paddingStart="16dp" - android:paddingEnd="24dp" - android:paddingVertical="16dp"> + android:padding="12dp"> <ImageView android:id="@+id/icon" - android:layout_width="20dp" - android:layout_height="20dp" - android:layout_marginEnd="16dp" - android:tint="?android:attr/textColorPrimary" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginEnd="8dp" + android:tint="?androidprv:attr/materialColorOnSecondaryFixed" android:importantForAccessibility="no" tools:ignore="UseAppTint" /> @@ -42,9 +41,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="?android:attr/textColorPrimary" + android:textColor="?androidprv:attr/materialColorOnSecondaryFixed" android:textSize="14sp" android:maxLines="1" android:ellipsize="end" /> -</LinearLayout>
\ No newline at end of file +</com.android.systemui.animation.view.LaunchableLinearLayout> diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml index 11ec02575e97..8b5368098c00 100644 --- a/packages/SystemUI/res/layout/notification_snooze.xml +++ b/packages/SystemUI/res/layout/notification_snooze.xml @@ -21,6 +21,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" + android:paddingTop="2dp" + android:paddingBottom="2dp" android:background="?androidprv:attr/colorSurface" android:theme="@style/Theme.SystemUI"> diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/shade_carrier.xml index a854660f64f8..0fed393a7ed3 100644 --- a/packages/SystemUI/res/layout/qs_carrier.xml +++ b/packages/SystemUI/res/layout/shade_carrier.xml @@ -14,7 +14,7 @@ ~ limitations under the License --> -<com.android.systemui.qs.carrier.QSCarrier +<com.android.systemui.shade.carrier.ShadeCarrier xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/linear_carrier" android:layout_width="wrap_content" @@ -29,7 +29,7 @@ android:focusable="true" > <com.android.systemui.util.AutoMarqueeTextView - android:id="@+id/qs_carrier_text" + android:id="@+id/shade_carrier_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" @@ -53,4 +53,4 @@ android:layout_marginStart="@dimen/qs_carrier_margin_width" android:visibility="gone" /> -</com.android.systemui.qs.carrier.QSCarrier>
\ No newline at end of file +</com.android.systemui.shade.carrier.ShadeCarrier>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_carrier_group.xml b/packages/SystemUI/res/layout/shade_carrier_group.xml index 6e13ab972226..2e8f98cbd190 100644 --- a/packages/SystemUI/res/layout/qs_carrier_group.xml +++ b/packages/SystemUI/res/layout/shade_carrier_group.xml @@ -15,7 +15,7 @@ --> <!-- Extends LinearLayout --> -<com.android.systemui.qs.carrier.QSCarrierGroup +<com.android.systemui.shade.carrier.ShadeCarrierGroup xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/qs_mobile" android:layout_width="0dp" @@ -39,25 +39,25 @@ android:visibility="gone"/> <include - layout="@layout/qs_carrier" + layout="@layout/shade_carrier" android:id="@+id/carrier1" android:layout_weight="1"/> <View - android:id="@+id/qs_carrier_divider1" + android:id="@+id/shade_carrier_divider1" android:layout_width="@dimen/qs_header_carrier_separator_width" android:layout_height="match_parent" android:visibility="gone" android:importantForAccessibility="no"/> <include - layout="@layout/qs_carrier" + layout="@layout/shade_carrier" android:id="@+id/carrier2" android:layout_weight="1" android:visibility="gone"/> <View - android:id="@+id/qs_carrier_divider2" + android:id="@+id/shade_carrier_divider2" android:layout_width="@dimen/qs_header_carrier_separator_width" android:layout_height="match_parent" android:layout_weight="1" @@ -65,9 +65,9 @@ android:importantForAccessibility="no"/> <include - layout="@layout/qs_carrier" + layout="@layout/shade_carrier" android:id="@+id/carrier3" android:layout_weight="1" android:visibility="gone"/> -</com.android.systemui.qs.carrier.QSCarrierGroup>
\ No newline at end of file +</com.android.systemui.shade.carrier.ShadeCarrierGroup>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index a11ffcda9830..d7106762d17b 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -120,10 +120,6 @@ /> </com.android.systemui.shade.NotificationsQuickSettingsContainer> - <include - layout="@layout/keyguard_bottom_area" - android:visibility="gone" /> - <ViewStub android:id="@+id/keyguard_user_switcher_stub" android:layout="@layout/keyguard_user_switcher" @@ -153,9 +149,7 @@ </com.android.keyguard.LockIconView> - <FrameLayout - android:id="@+id/preview_container" - android:layout_width="match_parent" - android:layout_height="match_parent"> - </FrameLayout> + <include + layout="@layout/keyguard_bottom_area" + android:visibility="gone" /> </com.android.systemui.shade.NotificationPanelView> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 752346acfcb3..07ad7957f81c 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Begin"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Eenhandmodus"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontras"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standaard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hoog"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokkeer toestelmikrofoon?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokkeer toestelkamera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokkeer toestelkamera en mikrofoon?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiveer"</string> <string name="sound_settings" msgid="8874581353127418308">"Klank en vibrasie"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Instellings"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Verlaag na veiliger volume"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Die volume was langer as wat aanbeveel word hoog"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Program is vasgespeld"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Oorsig om dit te ontspeld."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Tuis om dit te ontspeld."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Alle kontroles is verwyder"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Veranderinge is nie gestoor nie"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Sien ander programme"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Herrangskik"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Voeg kontroles by"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Terug na wysiging"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Kontroles kon nie gelaai word nie. Gaan die <xliff:g id="APP">%s</xliff:g>-program na om seker te maak dat die programinstellings nie verander het nie."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Versoenbare kontroles is nie beskikbaar nie"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Ander"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Jou werkbeleid laat jou toe om slegs van die werkprofiel af foonoproepe te maak"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skakel oor na werkprofiel"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Maak toe"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Sluitskerminstellings"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-fi is nie beskikbaar nie"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera is geblokkeer"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera en mikrofoon is geblokkeer"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 10c7c44a8f18..cf85656a0bda 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ጀምር"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"አቁም"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"የአንድ እጅ ሁነታ"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"የመሣሪያ ማይክሮፎን እገዳ ይነሳ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"የመሣሪያ ካሜራ እገዳ ይነሳ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"የመሣሪያ ካሜራ እና ማይክሮፎን እገዳ ይነሳ?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"አሰናክል"</string> <string name="sound_settings" msgid="8874581353127418308">"ድምፅ እና ንዝረት"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ቅንብሮች"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"ደህንነቱ ወደ የተጠበቀ ድምፅ ተቀንሷል"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"ድምፁ ከሚመከረው በላይ ረዘም ላለ ጊዜ ከፍተኛ ነበር"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"መተግበሪያ ተሰክቷል"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና አጠቃላይ ዕይታ የሚለውን ይጫኑ እና ይያዙ።"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና መነሻ የሚለውን ይንኩ እና ይያዙ።"</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"ሁሉም መቆጣጠሪያዎች ተወግደዋል"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ለውጦች አልተቀመጡም"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"ሌሎች መተግበሪያዎች ይመልከቱ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"ዳግም ደርድር"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"መቆጣጠሪያዎችን አክል"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ወደ አርትዖት ተመለስ"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"መቆጣጠሪያዎች ሊጫኑ አልቻሉም። የመተግበሪያው ቅንብሮች እንዳልተቀየሩ ለማረጋገጥ <xliff:g id="APP">%s</xliff:g> መተግበሪያን ይፈትሹ።"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"ተኳዃኝ መቆጣጠሪያዎች አይገኙም"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ሌላ"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"የሥራ መመሪያዎ እርስዎ ከሥራ መገለጫው ብቻ ጥሪ እንዲያደርጉ ይፈቅድልዎታል"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"ወደ የሥራ መገለጫ ቀይር"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ዝጋ"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"የማያ ገጽ ቁልፍ ቅንብሮች"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi አይገኝም"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ካሜራ ታግዷል"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ካሜራ እና ማይክሮፎን ታግደዋል"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 1fa13d5ccd83..49abf5a92ed6 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"بدء"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"إيقاف"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"وضع \"التصفح بيد واحدة\""</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"هل تريد إزالة حظر ميكروفون الجهاز؟"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"هل تريد إزالة حظر كاميرا الجهاز؟"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"هل تريد إزالة حظر الكاميرا والميكروفون؟"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"إيقاف"</string> <string name="sound_settings" msgid="8874581353127418308">"الصوت والاهتزاز"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"الإعدادات"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"تم خفض الصوت إلى المستوى الآمن"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"كان مستوى الصوت مرتفعًا لمدة أطول مما يُنصَح به."</string> <string name="screen_pinning_title" msgid="9058007390337841305">"تم تثبيت الشاشة على التطبيق"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"الشاشة الرئيسية\" لإزالة التثبيت."</string> @@ -1123,7 +1129,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"تسمح لك سياسة العمل بإجراء المكالمات الهاتفية من الملف الشخصي للعمل فقط."</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"التبديل إلى الملف الشخصي للعمل"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"إغلاق"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"إعدادات شاشة القفل"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"لا يتوفّر اتصال Wi-Fi."</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"استخدام الكاميرا محظور."</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"استخدام الكاميرا والميكروفون محظور."</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index b42dbeb748e9..8215f51ae2c6 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"আৰম্ভ কৰক"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ কৰক"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইচৰ মাইক্ৰ\'ফ\'ন অৱৰোধৰ পৰা আঁতৰাবনে?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ডিভাইচৰ কেমেৰা অৱৰোধৰ পৰা আঁতৰাবনে?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ডিভাইচৰ কেমেৰা আৰু মাইক্ৰ\'ফ\'ন অৱৰোধৰ পৰা আঁতৰাবনে?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"অক্ষম কৰক"</string> <string name="sound_settings" msgid="8874581353127418308">"ধ্বনি আৰু কম্পন"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ছেটিং"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"নিৰাপদ ভলিউমলৈ কমোৱা হৈছে"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"চুপাৰিছ কৰাতকৈ দীঘলীয়া সময়ৰ বাবে ভলিউম উচ্চ হৈ আছিল"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"এপ্টো পিন কৰা আছে"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'পিছলৈ যাওক\' আৰু \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ পিছলৈ যাওক আৰু হ\'মত স্পৰ্শ কৰি সেঁচি ধৰক।"</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"আটাইবোৰ নিয়ন্ত্ৰণ আঁতৰোৱা হৈছে"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"সালসলনিসমূহ ছেভ নহ’ল"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"অন্য এপ্সমূহ চাওক"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"পুনৰ সজাওক"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"নিয়ন্ত্ৰণ যোগ দিয়ক"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"সম্পাদনালৈ উভতি যাওক"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"নিয়ন্ত্ৰণসমূহ ল’ড কৰিবপৰা নগ’ল। এপ্টোৰ ছেটিং সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APP">%s</xliff:g> এপ্টো পৰীক্ষা কৰক।"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"সমিল নিয়ন্ত্ৰণসমূহ উপলব্ধ নহয়"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"আপোনাৰ কৰ্মস্থানৰ নীতিয়ে আপোনাক কেৱল কৰ্মস্থানৰ প্ৰ’ফাইলৰ পৰা ফ’ন কল কৰিবলৈ দিয়ে"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"কৰ্মস্থানৰ প্ৰ’ফাইললৈ সলনি কৰক"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"বন্ধ কৰক"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"লক স্ক্ৰীনৰ ছেটিং"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ৱাই-ফাই উপলব্ধ নহয়"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"কেমেৰা অৱৰোধ কৰা আছে"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"কেমেৰা আৰু মাইক্ৰ’ফ’ন অৱৰোধ কৰা আছে"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 8c9af864e876..c907101e3b5a 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -53,7 +53,7 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"İcazə verin"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB ilə sazlama qadağandır"</string> <string name="usb_debugging_secondary_user_message" msgid="1888835696965417845">"Hazırda bu cihaza daxil olmuş istifadəçi USB sazlama prosesini aktiv edə bilməz. Bu funksiyadan istifadə etmək üçün admin istifadəçiyə keçin."</string> - <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Sistem dili <xliff:g id="LANGUAGE">%1$s</xliff:g> dilinə dəyişdirilsin?"</string> + <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Sistem dili <xliff:g id="LANGUAGE">%1$s</xliff:g> olsun?"</string> <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Sistem dilinin dəyişdirilməsi başqa cihaz tərəfindən tələb olunur"</string> <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Dili dəyişin"</string> <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Cari dili saxlayın"</string> @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlayın"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Dayandırın"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Birəlli rejim"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standart"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Orta"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yüksək"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonu blokdan çıxarılsın?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerası blokdan çıxarılsın?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası və mikrofonu blokdan çıxarılsın?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiv edin"</string> <string name="sound_settings" msgid="8874581353127418308">"Səs və vibrasiya"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ayarlar"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Təhlükəsiz səs səviyyəsinə azaldıldı"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Səs səviyyəsi tövsiyə ediləndən uzun müddət yüksək olub"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Tətbiq bərkidilib"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"\"Geri\" və \"Əsas ekran\" düymələrinin davamlı basılması ilə çıxarılana qədər tətbiq göz önündə qalır."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Kontrol vidcetləri silindi"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Dəyişikliklər yadda saxlanmadı"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Digər tətbiqlərə baxın"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Yenidən nizamlayın"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Nizamlayıcılar əlavə edin"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Redaktəyə qayıdın"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Nizamlayıcıları yükləmək mümkün olmadı. <xliff:g id="APP">%s</xliff:g> tətbiqinə toxunaraq tətbiq ayarlarının dəyişmədiyinə əmin olun."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Uyğun nizamlayıcılar əlçatan deyil"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Digər"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"İş siyasətiniz yalnız iş profilindən telefon zəngləri etməyə imkan verir"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"İş profilinə keçin"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Bağlayın"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Kilid ekranı ayarları"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi əlçatan deyil"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera bloklanıb"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera və mikrofon bloklanıb"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index fd56a3eba8f4..dba882369afd 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Počnite"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavite"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednom rukom"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardno"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednje"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoko"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite da odblokirate mikrofon uređaja?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite da odblokirate kameru uređaja?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite da odblokirate kameru i mikrofon uređaja?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogućite"</string> <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibriranje"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Podešavanja"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Zvuk je smanjen na bezbednu jačinu"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Zvuk je bio glasan duže nego što se preporučuje"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je zakačena"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Pregled da biste ga otkačili."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Početna da biste ga otkačili."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Sve kontrole su uklonjene"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Promene nisu sačuvane"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Pogledajte druge aplikacije"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Prerasporedi"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Dodaj kontrole"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Nazad na izmene"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Učitavanje kontrola nije uspelo. Pogledajte aplikaciju <xliff:g id="APP">%s</xliff:g> da biste se uverili da se podešavanja aplikacije nisu promenila."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kompatibilne kontrole nisu dostupne"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Smernice za posao vam omogućavaju da telefonirate samo sa poslovnog profila"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Pređi na poslovni profil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zatvori"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Podešavanja zaključanog ekrana"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi nije dostupan"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 80a07f42ec28..76f124d33b4e 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Пачаць"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Спыніць"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Рэжым кіравання адной рукой"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблакіраваць мікрафон прылады?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблакіраваць камеру прылады?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблакіраваць камеру і мікрафон прылады?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"адключыць"</string> <string name="sound_settings" msgid="8874581353127418308">"Гук і вібрацыя"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Налады"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Гук паменшаны да бяспечнага ўзроўню"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Гучнасць была моцнай больш часу, чым рэкамендавана"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Праграма замацавана"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопкі \"Назад\" і \"Агляд\"."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, націсніце і ўтрымлівайце кнопкі \"Назад\" і \"Галоўны экран\"."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Усе элементы кіравання выдалены"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Змяненні не захаваны"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Паказаць іншыя праграмы"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Змяніць парадак"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Дадаць элементы кіравання"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Вярнуцца да рэдагавання"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Не ўдалося загрузіць элементы кіравання. Праверце, ці не змяніліся налады праграмы \"<xliff:g id="APP">%s</xliff:g>\"."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Сумяшчальныя элементы кіравання недаступныя"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Іншае"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Згодна з палітыкай вашай арганізацыі, рабіць тэлефонныя выклікі дазволена толькі з працоўнага профілю"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Пераключыцца на працоўны профіль"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрыць"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Налады экрана блакіроўкі"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Сетка Wi-Fi недаступная"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера заблакіравана"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера і мікрафон заблакіраваны"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 585902f6ab81..220cbe01bb8e 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Старт"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Стоп"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим за работа с една ръка"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартен"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Среден"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Висок"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се отблокира ли микрофонът на устройството?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се отблокира ли камерата на устройството?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се отблокират ли камерата и микрофонът на устройството?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"деактивиране"</string> <string name="sound_settings" msgid="8874581353127418308">"Звук и вибриране"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Настройки"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Силата на звука е намалена до по-безопасно ниво"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Нивото на силата на звука е било високо по-дълго, отколкото е препоръчително"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Приложението е фиксирано"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и този за общ преглед."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и „Начало“."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Всички контроли са премахнати"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Промените не са запазени"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Преглед на други приложения"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Пренареждане"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Добавяне на контроли"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Назад към редактирането"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Контролите не се заредиха. Отворете приложението <xliff:g id="APP">%s</xliff:g> и проверете дали настройките му не са променени."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Не са налице съвместими контроли"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Служебните правила ви дават възможност да извършвате телефонни обаждания само от служебния потребителски профил"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Превключване към служебния потребителски профил"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Затваряне"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Настройки за заключения екран"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi не е налице"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Достъпът до камерата е блокиран"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Достъпът до камерата и микрофона е блокиран"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 76e657ddd5c7..c611e631dec0 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"শুরু করুন"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ করুন"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এক হাতে ব্যবহার করার মোড"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইসের মাইক্রোফোন আনব্লক করতে চান?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ডিভাইসের ক্যামেরা আনব্লক করতে চান?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ডিভাইসের ক্যামেরা এবং মাইক্রোফোন আনব্লক করতে চান?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"বন্ধ হবে"</string> <string name="sound_settings" msgid="8874581353127418308">"সাউন্ড ও ভাইব্রেশন"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"সেটিংস"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"নিরাপদ ভলিউমে কমানো হয়েছে"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"যতক্ষণ সাজেস্ট করা হয়েছে তার থেকে বেশি সময় ভলিউম হাই ছিল"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"অ্যাপ পিন করা হয়েছে"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ফিরুন এবং ওভারভিউ স্পর্শ করে ধরে থাকুন।"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এর ফলে আপনি এটি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করতে \"ফিরে যান\" এবং \"হোম\" বোতামদুটি ট্যাপ করে ধরে রাখুন।"</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"সমস্ত কন্ট্রোল সরানো হয়েছে"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"পরিবর্তন সেভ করা হয়নি"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"অন্যান্য অ্যাপ দেখুন"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"আবার সাজান"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"কন্ট্রোল যোগ করুন"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"’এডিট করুন’ বোতামে ফিরে যান"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"কন্ট্রোল লোড করা যায়নি। অ্যাপ সেটিংসে কোনও পরিবর্তন করা হয়েছে কিনা তা ভাল করে দেখে নিতে <xliff:g id="APP">%s</xliff:g> অ্যাপ চেক করুন।"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"মানানসই কন্ট্রোল উপলভ্য নেই"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"কাজ সংক্রান্ত নীতি, আপনাকে শুধুমাত্র অফিস প্রোফাইল থেকে কল করার অনুমতি দেয়"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"অফিস প্রোফাইলে পাল্টে নিন"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"বন্ধ করুন"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"লক স্ক্রিন সেটিংস"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ওয়াই-ফাই উপলভ্য নয়"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ক্যামেরার অ্যাক্সেস ব্লক করা আছে"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ক্যামেরা এবং মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 4ce0baf96038..bc8f26c965bc 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Započnite"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavite"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardno"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednje"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoko"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokirati mikrofon uređaja?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokirati kameru uređaja?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokirati kameru i mikrofon uređaja?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogući"</string> <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibracija"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Postavke"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Stišano je na sigurniju jačinu zvuka"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Jačina zvuka je bila glasna duže nego što se preporučuje"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je zakačena"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Nazad."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Na ovaj način ekran ostaje prikazan dok ga ne otkačite. Da otkačite ekran, dodirnite i držite dugme Nazad i Početna."</string> @@ -517,13 +519,13 @@ <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Postavke zaključavanja ekrana"</string> <string name="qr_code_scanner_title" msgid="1938155688725760702">"Skener QR koda"</string> <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ažuriranje"</string> - <string name="status_bar_work" msgid="5238641949837091056">"Profil za posao"</string> + <string name="status_bar_work" msgid="5238641949837091056">"Radni profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u avionu"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Pristupna tačka"</string> - <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil za posao"</string> + <string name="accessibility_managed_profile" msgid="4703836746209377356">"Radni profil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string> <string name="tuner_warning" msgid="1861736288458481650">"Podešavač za korisnički interfejs sistema vam omogućava dodatne načine da podesite i prilagodite Androidov interfejs. Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string> <string name="tuner_persistent_warning" msgid="230466285569307806">"Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string> @@ -888,18 +890,15 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Sve kontrole su uklonjene"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Promjene nisu sačuvane"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Prikaži druge aplikacije"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Preuređivanje"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Dodaj kontrole"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Nazad na uređivanje"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Učitavanje kontrola nije uspjelo. Provjerite aplikaciju <xliff:g id="APP">%s</xliff:g> da se uvjerite da postavke aplikacije nisu izmijenjene."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kompatibilne kontrole nisu dostupne"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string> <string name="controls_dialog_title" msgid="2343565267424406202">"Dodajte u kontrole uređaja"</string> <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string> - <string name="controls_dialog_remove" msgid="3775288002711561936">"Uklanjanje"</string> + <string name="controls_dialog_remove" msgid="3775288002711561936">"Ukloni"</string> <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string> <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string> <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Prikazati uređaje i kontrolirati njima sa zaključanog ekrana?"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Radna pravila vam dozvoljavaju upućivanje telefonskih poziva samo s radnog profila"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Pređite na radni profil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zatvori"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Postavke zaključavanja ekrana"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi mreža nije dostupna"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index c08858affbdb..bdd72b9157b1 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inicia"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Atura"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode d\'una mà"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estàndard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mitjà"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alt"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vols desbloquejar el micròfon del dispositiu?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vols desbloquejar la càmera del dispositiu?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vols desbloquejar la càmera i el micròfon del dispositiu?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactivar"</string> <string name="sound_settings" msgid="8874581353127418308">"So i vibració"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuració"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"El volum s\'ha abaixat a un nivell més segur"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"El volum ha estat elevat durant més temps del recomanat"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"L\'aplicació està fixada"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premudes els botons Enrere i Aplicacions recents."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, mantén premuts els botons Enrere i Inici."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"S\'han suprimit tots els controls"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Els canvis no s\'han desat"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Mostra altres aplicacions"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Reordena"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Afegeix controls"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Torna a l\'edició"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"No s\'han pogut carregar els controls. Consulta l\'aplicació <xliff:g id="APP">%s</xliff:g> per assegurar-te que la configuració de l\'aplicació no hagi canviat."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Els controls compatibles no estan disponibles"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altres"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"La teva política de treball et permet fer trucades només des del perfil de treball"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Canvia al perfil de treball"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tanca"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Configuració pantalla de bloqueig"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"No hi ha cap Wi‑Fi disponible"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La càmera està bloquejada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La càmera i el micròfon estan bloquejats"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index a63025fec4ff..ebc0b07e3a72 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Spustit"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončit"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jedné ruky"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardní"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Střední"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Vysoká"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokovat mikrofon zařízení?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokovat fotoaparát zařízení?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Odblokovat fotoaparát a mikrofon zařízení?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktivovat"</string> <string name="sound_settings" msgid="8874581353127418308">"Zvuk a vibrace"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavení"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Ztišeno na bezpečnější hlasitost"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Hlasitost byla vysoká déle, než je doporučeno"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikace je připnutá"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítek Zpět a Přehled."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude připnut v zobrazení, dokud ho neuvolníte. Uvolníte ho podržením tlačítek Zpět a Plocha."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Všechny ovládací prvky byly odstraněny"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Změny nebyly uloženy"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Zobrazit další aplikace"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Uspořádání"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Přidat ovládací prvky"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Zpět k úpravám"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Ovládací prvky se nepodařilo načíst. V aplikaci <xliff:g id="APP">%s</xliff:g> zkontrolujte, zda se nezměnilo nastavení."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kompatibilní ovládání není k dispozici"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Jiné"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Vaše pracovní zásady vám umožňují telefonovat pouze z pracovního profilu"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Přepnout na pracovní profil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zavřít"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Nastavení obrazovky uzamčení"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Síť Wi-Fi není dostupná"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokována"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofon jsou blokovány"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index e0e1a24e7681..7d2f00928aa7 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndstilstand"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du fjerne blokeringen af enhedens mikrofon?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du fjerne blokeringen af enhedens kamera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du fjerne blokeringen af enhedens kamera og mikrofon?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiver"</string> <string name="sound_settings" msgid="8874581353127418308">"Lyd og vibration"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Indstillinger"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Der blev skruet ned til en mere sikker lydstyrke"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Lydstyrken har været for høj i længere tid end anbefalet"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er fastgjort"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Tilbage og Startskærm nede for at frigøre skærmen."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Alle styringselementerne blev fjernet"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ændringerne blev ikke gemt"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Se andre apps"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Omorganiser"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Tilføj styringselementer"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Tilbage til redigering"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Betjeningselementerne kunne ikke indlæses. Tjek <xliff:g id="APP">%s</xliff:g>-appen for at sikre, at dine appindstillinger ikke er blevet ændret."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kompatible betjeningselementer er ikke tilgængelige"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andre"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Din arbejdspolitik tillader kun, at du kan foretage telefonopkald fra arbejdsprofilen"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skift til arbejdsprofil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Luk"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Indstillinger for låseskærm"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ikke tilgængeligt"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokeret"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Der er blokeret for kameraet og mikrofonen"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 662393c260d1..5ffd063da1fb 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Beenden"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhandmodus"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Blockierung des Gerätemikrofons aufheben?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Blockierung der Gerätekamera aufheben?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Blockierung von Gerätekamera und Gerätemikrofon aufheben?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktivieren"</string> <string name="sound_settings" msgid="8874581353127418308">"Ton & Vibration"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Einstellungen"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Lautstärke zur Sicherheit verringert"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Die Lautstärke war länger als empfohlen hoch eingestellt"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"App ist auf dem Bildschirm fixiert"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Übersicht\"."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Startbildschirm\"."</string> @@ -1123,7 +1129,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Gemäß den Arbeitsrichtlinien darfst du nur über dein Arbeitsprofil telefonieren"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Zum Arbeitsprofil wechseln"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Schließen"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Sperrbildschirm-Einstellungen"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Kein WLAN verfügbar"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera blockiert"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera und Mikrofon blockiert"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 50b0b4965b43..bd924145d60a 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Έναρξη"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Διακοπή"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Λειτουργία ενός χεριού"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Κατάργηση αποκλεισμού μικροφώνου συσκευής;"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Κατάργηση αποκλεισμού κάμερας συσκευής;"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Κατάργηση αποκλεισμού κάμερας και μικροφώνου συσκευής;"</string> @@ -886,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Όλα τα στοιχεία ελέγχου καταργήθηκαν"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Οι αλλαγές δεν αποθηκεύτηκαν"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Εμφάνιση άλλων εφαρμογών"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Αναδιάταξη"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Προσθήκη στοιχείων ελέγχου"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Επιστροφή στην επεξεργασία"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Δεν ήταν δυνατή η φόρτωση των στοιχείων ελέγχου. Ελέγξτε την εφαρμογή <xliff:g id="APP">%s</xliff:g> για να βεβαιωθείτε ότι δεν έχουν αλλάξει οι ρυθμίσεις της εφαρμογής."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Μη διαθέσιμα συμβατά στοιχεία ελέγχου"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Άλλο"</string> @@ -1121,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Η πολιτική εργασίας σάς επιτρέπει να πραγματοποιείτε τηλεφωνικές κλήσεις μόνο από το προφίλ εργασίας σας."</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Εναλλαγή σε προφίλ εργασίας"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Κλείσιμο"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Ρυθμίσεις κλειδώματος οθόνης"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Δεν υπάρχει διαθέσιμο δίκτυο Wi-Fi"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Η κάμερα έχει αποκλειστεί"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Η κάμερα και το μικρόφωνο έχουν αποκλειστεί"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 6913b2df9334..b0df36a2e43c 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string> <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Lowered to safer volume"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"The volume has been high for longer than recommended"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch & hold Back and Overview to unpin."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch & hold Back and Home to unpin."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Changes not saved"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"See other apps"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Rearrange"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Add controls"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Back to editing"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Controls could not be loaded. Check the <xliff:g id="APP">%s</xliff:g> app to make sure that the app settings haven’t changed."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Compatible controls unavailable"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Lock screen settings"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 5e3f6ae7c71d..fe496b6fc57b 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> @@ -1118,7 +1122,7 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Lock screen settings"</string> + <string name="lock_screen_settings" msgid="6152703934761402399">"Customize lock screen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera blocked"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 6913b2df9334..b0df36a2e43c 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string> <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Lowered to safer volume"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"The volume has been high for longer than recommended"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch & hold Back and Overview to unpin."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch & hold Back and Home to unpin."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Changes not saved"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"See other apps"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Rearrange"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Add controls"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Back to editing"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Controls could not be loaded. Check the <xliff:g id="APP">%s</xliff:g> app to make sure that the app settings haven’t changed."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Compatible controls unavailable"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Lock screen settings"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 6913b2df9334..b0df36a2e43c 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string> <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Lowered to safer volume"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"The volume has been high for longer than recommended"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch & hold Back and Overview to unpin."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch & hold Back and Home to unpin."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Changes not saved"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"See other apps"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Rearrange"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Add controls"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Back to editing"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Controls could not be loaded. Check the <xliff:g id="APP">%s</xliff:g> app to make sure that the app settings haven’t changed."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Compatible controls unavailable"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Lock screen settings"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index fd6a2920c95e..3b5c1a5d9ac1 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> @@ -1118,7 +1122,7 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Lock screen settings"</string> + <string name="lock_screen_settings" msgid="6152703934761402399">"Customize lock screen"</string> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera blocked"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index e067d944da85..893a39235e88 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo una mano"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estándar"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Quieres desbloquear el micrófono del dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Quieres desbloquear la cámara del dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Quieres desbloquear la cámara y el micrófono del dispositivo?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"inhabilitar"</string> <string name="sound_settings" msgid="8874581353127418308">"Sonido y vibración"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuración"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Se bajó el volumen a un nivel seguro"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"El volumen se mantuvo elevado por más tiempo del recomendado"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"La app está fijada"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionados los botones Atrás y Recientes."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionados los botones de inicio y Atrás."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Se quitaron todos los controles"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"No se guardaron los cambios"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Ver otras apps"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Reorganizar"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Agregar controles"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Volver a la edición"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"No se pudieron cargar los controles. Revisa la app de <xliff:g id="APP">%s</xliff:g> para asegurarte de que su configuración no haya cambiado."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"No hay ningún control compatible disponible"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Tu política del trabajo te permite hacer llamadas telefónicas solo desde el perfil de trabajo"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Config. de pantalla de bloqueo"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi no disponible"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La cámara está bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La cámara y el micrófono están bloqueados"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 5ba337e69e3b..cf38c13cc8bb 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo Una mano"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estándar"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Desbloquear el micrófono del dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Desbloquear la cámara del dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Desbloquear la cámara y el micrófono del dispositivo?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactivar"</string> <string name="sound_settings" msgid="8874581353127418308">"Sonido y vibración"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ajustes"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Se ha bajado el volumen a un nivel más seguro"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"El volumen ha sido elevado durante más tiempo del recomendado"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplicación fijada"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"La aplicación se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsados los botones Atrás y Aplicaciones recientes."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La aplicación se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsados los botones Atrás e Inicio."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Todos los controles quitados"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"No se han guardado los cambios"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Ver otras aplicaciones"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Reorganizar"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Añadir controles"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Volver a editar"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"No se han podido cargar los controles. Comprueba que no hayan cambiado los ajustes de la aplicación <xliff:g id="APP">%s</xliff:g>."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Los controles compatibles no están disponibles"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Tu política del trabajo solo te permite hacer llamadas telefónicas desde el perfil de trabajo"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Ajustes de pantalla de bloqueo"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Red Wi-Fi no disponible"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Cámara bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Cámara y micrófono bloqueados"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 7db471ac7a0f..50288333234a 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Alustage"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Peatage"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ühekäerežiim"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kas tühistada seadme mikrofoni blokeerimine?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kas tühistada seadme kaamera blokeerimine?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kas tühistada seadme kaamera ja mikrofoni blokeerimine?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"keela"</string> <string name="sound_settings" msgid="8874581353127418308">"Heli ja vibreerimine"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Seaded"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Ohutuma helitugevuse huvides vähendatud"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Heli on olnud vali soovitatavast ajast kauem"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Rakendus on kinnitatud"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Avakuva."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Kõik juhtelemendid eemaldati"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Muudatusi ei salvestatud"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Kuva muud rakendused"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Korralda ümber"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Lisa juhtelemente"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Tagasi muutmise juurde"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Juhtelemente ei õnnestunud laadida. Kontrollige rakendust <xliff:g id="APP">%s</xliff:g> ja veenduge, et rakenduse seaded poleks muutunud."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Ühilduvaid juhtelemente pole saadaval"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Teie töökoha eeskirjad lubavad teil helistada ainult tööprofiililt"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Lülitu tööprofiilile"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Sule"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Lukustuskuva seaded"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi pole saadaval"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kaamera on blokeeritud"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kaamera ja mikrofon on blokeeritud"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 492bb6faa402..5dfcdd9e4504 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hasi"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Gelditu"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Esku bakarreko modua"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrastea"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Arrunta"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Tartekoa"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Altua"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Gailuaren mikrofonoa desblokeatu nahi duzu?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Gailuaren kamera desblokeatu nahi duzu?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Gailuaren kamera eta mikrofonoa desblokeatu nahi dituzu?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desgaitu"</string> <string name="sound_settings" msgid="8874581353127418308">"Audioa eta dardara"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ezarpenak"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Bolumena jaitsi da entzumena babesteko"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Gomendatutakoa baino denbora gehiagoan eduki da bolumena ozen"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikazioa ainguratuta dago"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak."</string> @@ -517,13 +519,13 @@ <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Pantaila blokeatuaren ezarpenak"</string> <string name="qr_code_scanner_title" msgid="1938155688725760702">"QR kodeen eskanerra"</string> <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Eguneratzen"</string> - <string name="status_bar_work" msgid="5238641949837091056">"Work profila"</string> + <string name="status_bar_work" msgid="5238641949837091056">"Laneko profila"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Hegaldi modua"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ez duzu entzungo hurrengo alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string> <string name="alarm_template" msgid="2234991538018805736">"ordua: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"data: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Wifi-gunea"</string> - <string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profila"</string> + <string name="accessibility_managed_profile" msgid="4703836746209377356">"Laneko profila"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Dibertsioa batzuentzat, baina ez guztientzat"</string> <string name="tuner_warning" msgid="1861736288458481650">"Sistemaren erabiltzaile-interfazearen konfiguratzaileak Android erabiltzaile-interfazea moldatzeko eta pertsonalizatzeko modu gehiago eskaintzen dizkizu. Baliteke eginbide esperimental horiek hurrengo kaleratzeetan aldatuta, etenda edo desagertuta egotea. Kontuz erabili."</string> <string name="tuner_persistent_warning" msgid="230466285569307806">"Baliteke eginbide esperimental horiek hurrengo kaleratzeetan aldatuta, etenda edo desagertuta egotea. Kontuz erabili."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Kendu dira kontrolatzeko aukera guztiak"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ez dira gorde aldaketak"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Ikusi beste aplikazio batzuk"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Berrantolatu"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Gehitu kontrolatzeko aukerak"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Itzuli editatzeko pantailara"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Ezin izan dira kargatu kontrolatzeko aukerak. Joan <xliff:g id="APP">%s</xliff:g> aplikaziora, eta ziurtatu aplikazioaren ezarpenak ez direla aldatu."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Ez dago erabilgarri kontrolatzeko aukera bateragarririk"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Beste bat"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Deiak laneko profiletik soilik egiteko baimena ematen dizute laneko gidalerroek"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Aldatu laneko profilera"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Itxi"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Pantaila blokeatuaren ezarpenak"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi-konexioa ez dago erabilgarri"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera blokeatuta dago"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera eta mikrofonoa blokeatuta daude"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index b8bf0c91cb54..57c043027cf5 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"متوقف کردن"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"حالت یکدستی"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"تضاد"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"استاندارد"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"متوسط"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"بالا"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"دوربین و میکروفون دستگاه لغو انسداد شود؟"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"غیرفعال کردن"</string> <string name="sound_settings" msgid="8874581353127418308">"صدا و لرزش"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"تنظیمات"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"به میزان صدای ایمنتر کاهش یافت"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"صدا برای مدتی طولانیتر از حد توصیهشده بلند بوده است"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"برنامه سنجاق شده است"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"تا زمانی که سنجاق را برندارید، در نما نگهداشته میشود. برای برداشتن سنجاق، «برگشت» و «نمای کلی» را لمس کنید و نگهدارید."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"تا برداشتن سنجاق، در نما نگهداشته میشود. برای برداشتن سنجاق، «برگشت» و «صفحه اصلی» را لمس کنید و نگهدارید."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"همه کنترلها برداشته شدهاند"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"تغییرات ذخیره نشد"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"دیدن برنامههای دیگر"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"مرتبسازی مجدد"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"افزودن کنترلها"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"برگشتن به ویرایش"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"کنترلها بار نشدند. برنامه <xliff:g id="APP">%s</xliff:g> را بررسی کنید تا مطمئن شوید تنظیمات برنامه تغییر نکرده باشد."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"کنترلهای سازگار دردسترس نیستند"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"موارد دیگر"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"خطمشی کاری شما فقط به برقراری تماس ازطریق نمایه کاری اجازه میدهد"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"رفتن به نمایه کاری"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"بستن"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"تنظیمات صفحه قفل"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi دردسترس نیست"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"دوربین مسدود شده است"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"دوربین و میکروفون مسدود شدهاند"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index d7d211715d01..767d18eb4b1e 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Aloita"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Lopeta"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Yhden käden moodi"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kumotaanko laitteen mikrofonin esto?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kumotaanko laitteen kameran esto?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kumotaanko laitteen kameran ja mikrofonin esto?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"poista käytöstä"</string> <string name="sound_settings" msgid="8874581353127418308">"Ääni ja värinä"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Asetukset"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Äänenvoimakkuutta vähennetty turvallisemmalle tasolle"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Äänenvoimakkuus on ollut suuri yli suositellun ajan"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Sovellus on kiinnitetty"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Viimeisimmät."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Aloitusnäyttö."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Kaikki säätimet poistettu"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Muutoksia ei tallennettu"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Katso muita sovelluksia"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Järjestä uudelleen"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Lisää asetuksia"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Palaa muokkaukseen"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Säätimiä ei voitu ladata. Avaa <xliff:g id="APP">%s</xliff:g> ja tarkista, että sovelluksen asetukset eivät ole muuttuneet."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Yhteensopivat säätimet eivät käytettävissä"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Työkäytäntö sallii sinun soittaa puheluita vain työprofiilista"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Vaihda työprofiiliin"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Sulje"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Lukitusnäytön asetukset"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi-yhteys ei ole käytettävissä"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera estetty"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ja mikrofoni estetty"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 4abf838a3fc5..e7a9c874d267 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode Une main"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le microphone de l\'appareil?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer l\'appareil photo de l\'appareil?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Débloquer l\'appareil photo et le microphone?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string> <string name="sound_settings" msgid="8874581353127418308">"Son et vibration"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Paramètres"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Réduction du volume à un niveau moins dangereux"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Le niveau du volume est resté élevé au-delà de la durée recommandée"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Retour » et « Aperçu »."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur les touches Retour et Accueil."</string> @@ -852,8 +858,7 @@ <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_fullscreen" msgid="5043514702759201964">"Plein écran"</string> <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> @@ -1124,7 +1129,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Votre politique de l\'entreprise vous autorise à passer des appels téléphoniques uniquement à partir de votre profil professionnel"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fermer"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Paramètres écran de verrouillage"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non accessible"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Appareil photo bloqué"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Appareil photo et microphone bloqués"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index fa48b7ab472a..d20258bae89c 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode une main"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le micro de l\'appareil ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer l\'appareil photo de l\'appareil ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Débloquer l\'appareil photo et le micro de l\'appareil ?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string> <string name="sound_settings" msgid="8874581353127418308">"Son et vibreur"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Paramètres"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Volume réduit à un niveau plus sûr"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"La période pendant laquelle le volume est resté élevé est supérieure à celle recommandée"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Elle restera visible jusqu\'à ce que vous la retiriez. Pour la retirer, appuyez de manière prolongée sur les boutons Retour et Récents."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Elle restera visible jusqu\'à ce que vous la retiriez. Pour la retirer, appuyez de manière prolongée sur les boutons Retour et Accueil."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Toutes les commandes ont été supprimées"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Les modifications n\'ont pas été enregistrées"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Afficher d\'autres applications"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Réorganiser"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Ajouter des commandes"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Retour à l\'édition"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Impossible de charger les commandes. Vérifiez l\'application <xliff:g id="APP">%s</xliff:g> pour vous assurer que les paramètres n\'ont pas changé."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Commandes compatibles indisponibles"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string> @@ -953,7 +956,7 @@ <string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Ajouter une appli"</string> - <string name="controls_menu_remove" msgid="3006525275966023468">"Supprimer l\'application"</string> + <string name="controls_menu_remove" msgid="3006525275966023468">"Supprimer l\'appli"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ajouter des sorties"</string> <string name="media_output_dialog_group" msgid="5571251347877452212">"Groupe"</string> <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 appareil sélectionné"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Votre règle professionnelle ne vous permet de passer des appels que depuis le profil professionnel"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fermer"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Paramètres écran de verrouillage"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponible"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Caméra bloquée"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 7828b209113a..41fee6a55419 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Deter"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo dunha soa man"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Queres desbloquear o micrófono do dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Queres desbloquear a cámara do dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Queres desbloquear a cámara e o micrófono do dispositivo?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactiva"</string> <string name="sound_settings" msgid="8874581353127418308">"Son e vibración"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuración"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"O volume baixouse a un nivel máis seguro"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"O volume estivo a un nivel alto durante máis tempo do recomendado"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"A aplicación está fixada"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"A pantalla manterase visible ata que deixes de fixala. Para facelo, mantén premido Atrás e Visión xeral."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"A pantalla manterase visible ata que deixes de fixala. Para facelo, mantén premido Atrás e Inicio."</string> @@ -1123,7 +1129,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"A política do teu traballo só che permite facer chamadas de teléfono desde o perfil de traballo"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar ao perfil de traballo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Pechar"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Configuración pantalla bloqueo"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi non dispoñible"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"A cámara está bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"A cámara e o micrófono están bloqueados"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 012607ee9115..1201b79c8ef7 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"શરૂ કરો"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"રોકો"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"એક-હાથે વાપરો મોડ"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"કોન્ટ્રાસ્ટ"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"સ્ટૅન્ડર્ડ"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"મધ્યમ"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"વધુ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ડિવાઇસના માઇક્રોફોનને અનબ્લૉક કરીએ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ડિવાઇસના કૅમેરાને અનબ્લૉક કરીએ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ડિવાઇસના કૅમેરા અને માઇક્રોફોનને અનબ્લૉક કરીએ?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"બંધ કરો"</string> <string name="sound_settings" msgid="8874581353127418308">"સાઉન્ડ અને વાઇબ્રેશન"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"સેટિંગ"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"વૉલ્યૂમ ઘટાડીને સલામત વૉલ્યૂમ જેટલું કર્યું"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"સુઝાવ આપેલા સમય કરતાં વધુ સમય સુધી વૉલ્યૂમ વધારે રહ્યું છે"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ઍપને પિન કરેલી છે"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે પાછળ અને ઓવરવ્યૂને સ્પર્શ કરી રાખો."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે પાછળ અને હોમને સ્પર્શ કરી રાખો."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"બધા નિયંત્રણો કાઢી નાખ્યા"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ફેરફારો સાચવ્યા નથી"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"અન્ય બધી ઍપ જુઓ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"ફરીથી ગોઠવો"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"નિયંત્રણો ઉમેરો"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ફેરફાર કરવા માટે પાછા જાઓ"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"નિયંત્રણો લોડ કરી શકાયા નથી. ઍપના સેટિંગ બદલાયા નથી તેની ખાતરી કરવા માટે <xliff:g id="APP">%s</xliff:g> ઍપ ચેક કરો."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"સુસંગત નિયંત્રણો ઉપલબ્ધ નથી"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"અન્ય"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"તમારી ઑફિસની પૉલિસી તમને માત્ર ઑફિસની પ્રોફાઇલ પરથી જ ફોન કૉલ કરવાની મંજૂરી આપે છે"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"ઑફિસની પ્રોફાઇલ પર સ્વિચ કરો"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"બંધ કરો"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"લૉક સ્ક્રીનના સેટિંગ"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"કૅમેરા બ્લૉક કરેલો છે"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"કૅમેરા અને માઇક્રોફોન બ્લૉક કરેલા છે"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 4728ea1413d9..9eb124e2abaa 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"शुरू करें"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोकें"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"वन-हैंडेड मोड"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"कंट्रास्ट"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"स्टैंडर्ड"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"सामान्य"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"ज़्यादा"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"क्या आपको डिवाइस का माइक्रोफ़ोन अनब्लॉक करना है?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"क्या आपको डिवाइस का कैमरा अनब्लॉक करना है?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"क्या आप डिवाइस का कैमरा और माइक्रोफ़ोन अनब्लॉक करना चाहते हैं?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करें"</string> <string name="sound_settings" msgid="8874581353127418308">"आवाज़ और वाइब्रेशन"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिंग"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"बेहतर ऑडियो के लिए वॉल्यूम का लेवल कम किया गया"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"सुझाए गए समय से ज़्यादा देर तक वॉल्यूम का लेवल ज़्यादा रहा है"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ऐप्लिकेशन पिन किया गया है"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है, जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम और वापस जाएं वाले बटन को दबाकर रखें."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"सभी कंट्रोल हटा दिए गए"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"बदलाव सेव नहीं किए गए"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"दूसरे ऐप्लिकेशन देखें"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"फिर से व्यवस्थित करें"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"कंट्रोल बटन जोड़ें"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"बदलाव करने के लिए वापस जाएं"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"कंट्रोल लोड नहीं किए जा सके. <xliff:g id="APP">%s</xliff:g> ऐप्लिकेशन देखें, ताकि यह पक्का किया जा सके कि ऐप्लिकेशन की सेटिंग में कोई बदलाव नहीं हुआ है."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"इस सेटिंग के साथ काम करने वाले कंट्रोल उपलब्ध नहीं हैं"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ऑफ़िस की नीति के तहत, वर्क प्रोफ़ाइल होने पर ही फ़ोन कॉल किए जा सकते हैं"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"वर्क प्रोफ़ाइल पर स्विच करें"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"बंद करें"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"लॉक स्क्रीन की सेटिंग"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाई-फ़ाई उपलब्ध नहीं है"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कैमरे का ऐक्सेस नहीं है"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कैमरे और माइक्रोफ़ोन का ऐक्सेस नहीं है"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index a68d09930c0f..f284bb6826e8 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Početak"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavi"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardni"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednji"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoki"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite li deblokirati mikrofon uređaja?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite li deblokirati fotoaparat uređaja?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite li deblokirati fotoaparat i mikrofon uređaja?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogući"</string> <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibracija"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Postavke"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Stišano na sigurniju glasnoću"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Zvuk je bio glasan duže nego što se preporučuje"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je prikvačena"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i zadržite Natrag i Pregled da biste ga otkvačili."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite gumbe Natrag i Početna i zadržite pritisak da biste ga otkvačili."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Sve su kontrole uklonjene"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Promjene nisu spremljene"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Pogledajte ostale aplikacije"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Promjena rasporeda"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Dodajte kontrole"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Natrag na uređivanje"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Kontrole se ne mogu učitati. U aplikaciji <xliff:g id="APP">%s</xliff:g> provjerite da se postavke aplikacije nisu promijenile."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kompatibilne kontrole nisu dostupne"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Vaša pravila za poslovne uređaje omogućuju vam upućivanje poziva samo s poslovnog profila"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Prijeđite na poslovni profil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zatvori"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Postavke zaključanog zaslona"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nije dostupan"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Blokirani su kamera i mikrofon"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index e2f0eb0612b0..3eb58183ed34 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Indítás"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Leállítás"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Egykezes mód"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Feloldja az eszközmikrofon letiltását?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Feloldja az eszközkamera letiltását?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Feloldja az eszközkamera és -mikrofon letiltását?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"letiltás"</string> <string name="sound_settings" msgid="8874581353127418308">"Hang és rezgés"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Beállítások"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Hangerő csökkentve a biztonság érdekében"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"A hangerő az ajánlottnál hosszabb ideig volt nagy"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Az alkalmazás ki van tűzve"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és az Áttekintés lehetőséget."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és a Kezdőképernyő elemet."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Minden vezérlő eltávolítva"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"A rendszer nem mentette a módosításokat"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Többi alkalmazás megtekintése"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Átrendezés"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Vezérlők hozzáadása"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Vissza a szerkesztéshez"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Nem sikerült betölteni a vezérlőket. Ellenőrizze a(z) <xliff:g id="APP">%s</xliff:g> alkalmazást, és győződjön meg arról, hogy nem változtak az alkalmazásbeállítások."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Nem állnak rendelkezésre kompatibilis vezérlők"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Más"</string> @@ -1037,7 +1040,7 @@ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nincs automatikus mobiladat-kapcsolat"</string> <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nincs kapcsolat"</string> <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nincs több rendelkezésre álló hálózat"</string> - <string name="all_network_unavailable" msgid="4112774339909373349">"Nincs rendelkezésre álló hálózat"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nincs elérhető hálózat"</string> <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> <string name="tap_a_network_to_connect" msgid="1565073330852369558">"A kapcsolódáshoz koppintson a kívánt hálózatra"</string> <string name="unlock_to_view_networks" msgid="5072880496312015676">"Zárolás feloldása a hálózatok megtekintéséhez"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"A munkahelyi házirend csak munkaprofilból kezdeményezett telefonhívásokat engedélyez"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Váltás munkaprofilra"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Bezárás"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Lezárási képernyő beállításai"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Nem áll rendelkezésre Wi-Fi"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera letiltva"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera és mikrofon letiltva"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 26a43157805b..9d872c47e003 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Սկսել"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Կանգնեցնել"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Մեկ ձեռքի ռեժիմ"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Արգելահանե՞լ սարքի խոսափողը"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Արգելահանե՞լ սարքի տեսախցիկը"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Արգելահանե՞լ սարքի տեսախցիկը և խոսափողը"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"անջատել"</string> <string name="sound_settings" msgid="8874581353127418308">"Ձայն և թրթռոց"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Կարգավորումներ"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Ձայնն իջեցվեց անվտանգ մակարդակի"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Ձայնը բարձր է եղել առաջարկված ժամանակահատվածից ավելի երկար"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Հավելվածն ամրացված է"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները:"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև չեղարկեք ամրացումը: Չեղարկելու համար հպեք և պահեք «Հետ» և «Գլխավոր էկրան» կոճակները"</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Կառավարման բոլոր տարրերը հեռացվեցին"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Փոփոխությունները չեն պահվել"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Տեսնել այլ հավելվածներ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Վերադասավորել"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Ավելացնել կարգավորումներ"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Վերադառնալ խմբագրման ռեժիմին"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Չհաջողվեց բեռնել կառավարման տարրերը։ Ստուգեք <xliff:g id="APP">%s</xliff:g> հավելվածը՝ համոզվելու, որ հավելվածի կարգավորումները չեն փոխվել։"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Համատեղելի կառավարման տարրերը հասանելի չեն"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Այլ"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Ձեր աշխատանքային կանոնների համաձայն՝ դուք կարող եք զանգեր կատարել աշխատանքային պրոֆիլից"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Անցնել աշխատանքային պրոֆիլ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Փակել"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Կողպէկրանի կարգավորումներ"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ցանց հասանելի չէ"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Տեսախցիկն արգելափակված է"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Տեսախցիկն ու խոսափողը արգելափակված են"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index dade59c20dd8..f62ef6010132 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mulai"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode satu tangan"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontras"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standar"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Sedang"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Tinggi"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Berhenti memblokir mikrofon perangkat?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Berhenti memblokir kamera perangkat?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Berhenti memblokir kamera dan mikrofon perangkat?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"nonaktifkan"</string> <string name="sound_settings" msgid="8874581353127418308">"Suara & getaran"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Setelan"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Diturunkan ke volume yang lebih aman"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Volume tinggi selama lebih lama dari yang direkomendasikan"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikasi disematkan"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ini akan terus ditampilkan sampai Anda melepas sematan. Sentuh lama tombol Kembali dan Ringkasan untuk melepas sematan."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ini akan terus ditampilkan sampai Anda melepas sematan. Sentuh lama tombol Kembali dan Beranda untuk melepas sematan."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Semua kontrol dihapus"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Perubahan tidak disimpan"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Lihat aplikasi lainnya"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Atur ulang"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Tambahkan kontrol"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Kembali mengedit"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Kontrol tidak dapat dimuat. Periksa aplikasi <xliff:g id="APP">%s</xliff:g> untuk memastikan setelan aplikasi tidak berubah."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kontrol yang kompatibel tidak tersedia"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lainnya"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Kebijakan kantor mengizinkan Anda melakukan panggilan telepon hanya dari profil kerja"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Beralih ke profil kerja"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tutup"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Setelan layar kunci"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi tidak tersedia"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera diblokir"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon diblokir"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index a588d36d13b4..e85621e48adf 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hefja"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stöðva"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhent stilling"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Opna fyrir hljóðnema tækisins?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Opna fyrir myndavél tækisins?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Opna fyrir myndavél og hljóðnema tækisins?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"slökkva"</string> <string name="sound_settings" msgid="8874581353127418308">"Hljóð og titringur"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Stillingar"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Lækkað í öruggari hljóðstyrk"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Hljóðstyrkurinn hefur verið hár í lengri tíma en mælt er með"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Forrit er fest"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Þetta heldur þessu opnu þangað til þú losar það. Haltu fingri á „Til baka“ og „Yfirlit“ til að losa."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Þetta heldur þessu opnu þangað til það er losað. Haltu inni bakkhnappinum og heimahnappinum til að losa."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Allar stýringar fjarlægðar"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Breytingar ekki vistaðar"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Sjá önnur forrit"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Endurraða"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Bæta við stýringum"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Aftur í breytingar"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Ekki tókst að hlaða stýringum. Athugaðu <xliff:g id="APP">%s</xliff:g> til að ganga úr skugga um að stillingar forritsins hafi ekki breyst."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Samhæfar stýringar eru ekki tiltækar"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annað"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Vinnureglur gera þér aðeins kleift að hringja símtöl úr vinnusniði"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skipta yfir í vinnusnið"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Loka"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Stillingar fyrir lásskjá"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ekki til staðar"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Lokað fyrir myndavél"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Lokað fyrir myndavél og hljóðnema"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index f46ccb73246a..3044a29f48d4 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inizia"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Interrompi"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modalità a una mano"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrasto"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vuoi sbloccare il microfono del dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vuoi sbloccare la fotocamera del dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vuoi sbloccare la fotocamera e il microfono del dispositivo?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disattiva"</string> <string name="sound_settings" msgid="8874581353127418308">"Suoni e vibrazione"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Impostazioni"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Audio abbassato a un volume più sicuro"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Il volume è alto da più tempo di quanto consigliato"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"L\'app è bloccata sullo schermo"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Indietro e Panoramica."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Indietro e Home."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Tutti i controlli sono stati rimossi"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Modifiche non salvate"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Mostra altre app"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Riordina"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Aggiungi controlli"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Torna alle modifiche"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Impossibile caricare i controlli. Verifica nell\'app <xliff:g id="APP">%s</xliff:g> che le relative impostazioni non siano cambiate."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Controlli compatibili non disponibili"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altro"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Le norme di lavoro ti consentono di fare telefonate soltanto dal profilo di lavoro"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passa al profilo di lavoro"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Chiudi"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Impostazioni schermata di blocco"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponibile"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Videocamera bloccata"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Videocamera e microfono bloccati"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 7eb276435a10..044e9edfe7db 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"התחלה"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"עצירה"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"מצב שימוש ביד אחת"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"ניגודיות"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"רגילה"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"בינונית"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"גבוהה"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"לבטל את חסימת המיקרופון של המכשיר?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"לבטל את חסימת המצלמה של המכשיר?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"לבטל את חסימת המצלמה והמיקרופון של המכשיר?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"השבתה"</string> <string name="sound_settings" msgid="8874581353127418308">"צליל ורטט"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"הגדרות"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"עוצמת הקול הוחלשה לרמה בטוחה יותר"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"עוצמת הקול הייתה גבוהה במשך יותר זמן מהמומלץ"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"האפליקציה מוצמדת"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"כל הפקדים הוסרו"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"השינויים לא נשמרו"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"הצגת אפליקציות אחרות"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"סידור מחדש"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"הוספת פקדים"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"חזרה לעריכה"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"לא ניתן היה לטעון את הפקדים. יש לבדוק את האפליקציה <xliff:g id="APP">%s</xliff:g> כדי לוודא שהגדרות האפליקציה לא השתנו."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"פקדים תואמים לא זמינים"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"אחר"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"המדיניות של מקום העבודה מאפשרת לך לבצע שיחות טלפון רק מפרופיל העבודה"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"מעבר לפרופיל עבודה"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"סגירה"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"הגדרות מסך הנעילה"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ה-Wi-Fi לא זמין"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"המצלמה חסומה"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"המצלמה והמיקרופון חסומים"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 6f43e4bde475..ed7006eb1368 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"片手モード"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"コントラスト"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"標準"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"デバイスのマイクのブロックを解除しますか?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"デバイスのカメラのブロックを解除しますか?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"デバイスのカメラとマイクのブロックを解除しますか?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"無効にする"</string> <string name="sound_settings" msgid="8874581353127418308">"音とバイブレーション"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"安全な音量まで下げました"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"おすすめの時間よりも長く大音量になっていました"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"アプリは固定されています"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"固定を解除するまで画面が常に表示されるようになります。[戻る] と [最近] を同時に押し続けると固定が解除されます。"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"固定を解除するまで画面が常に表示されるようになります。[戻る] と [ホーム] を同時に押し続けると固定が解除されます。"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"すべてのコントロールを削除しました"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"変更が保存されていません"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"その他のアプリを表示"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"再配置"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"コントロールを追加する"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"編集に戻る"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"コントロールを読み込めませんでした。<xliff:g id="APP">%s</xliff:g> アプリで、アプリの設定が変更されていないことをご確認ください。"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"互換性のあるコントロールがありません"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"その他"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"仕事用ポリシーでは、通話の発信を仕事用プロファイルからのみに制限できます"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"仕事用プロファイルに切り替える"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"閉じる"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"ロック画面の設定"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi は利用できません"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"カメラはブロックされています"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"カメラとマイクはブロックされています"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 97ccc04c1bae..3e02cae29349 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"დაწყება"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"შეწყვეტა"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ცალი ხელის რეჟიმი"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"კონტრასტი"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"სტანდარტული"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"საშუალო"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"მაღალი"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"გსურთ მოწყობილობის მიკროფონის განბლოკვა?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"გსურთ მოწყობილობის კამერის განბლოკვა?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"გსურთ მოწყობილობის კამერის და მიკროფონის განბლოკვა?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"გამორთვა"</string> <string name="sound_settings" msgid="8874581353127418308">"ხმა და ვიბრაცია"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"პარამეტრები"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"ხმა დაკლებულია უსაფრთხო დონემდე"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"ხმა მაღალია რეკომენდებულზე მეტი ხნის განავლობაში"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"აპი ჩამაგრებულია"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან და მიმოხილვა“-ს."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან მთავარ გვერდზე“-ს."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"მართვის ყველა საშუალება ამოიშალა"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ცვლილებები არ შენახულა"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"სხვა აპების ნახვა"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"გადაწყობა"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"მართვის საშუალებების დამატება"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"რედაქტირებაზე დაბრუნება"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"მართვის საშუალებების ჩატვირთვა ვერ მოხერხდა. შეამოწმეთ <xliff:g id="APP">%s</xliff:g> აპი, რათა დარწმუნდეთ, რომ აპის პარამეტრები არ შეცვლილა."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"მართვის თავსებადი საშუალებები მიუწვდომელია"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"სხვა"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"თქვენი სამსახურის წესები საშუალებას გაძლევთ, სატელეფონო ზარები განახორციელოთ მხოლოდ სამსახურის პროფილიდან"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"სამსახურის პროფილზე გადართვა"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"დახურვა"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"ჩაკეტილი ეკრანის პარამეტრები"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi მიუწვდომელია"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"კამერა დაბლოკილია"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"კამერა და მიკროფონი დაბლოკილია"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 609dba4af432..7479937a760b 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Бастау"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Тоқтату"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бір қолмен басқару режимі"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Құрылғы микрофонының бөгеуі алынсын ба?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Құрылғы камерасының бөгеуі алынсын ба?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Құрылғы камерасы мен микрофонының бөгеуі алынсын ба?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өшіру"</string> <string name="sound_settings" msgid="8874581353127418308">"Дыбыс және діріл"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Параметрлер"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Қауіпсіз дыбыс деңгейіне төмендетілді"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Дыбыстың жоғары деңгейі ұсынылғаннан уақыттан ұзағырақ болды."</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Қолданба бекітілді"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Өзіңіз босатқаша ашық тұрады. Босату үшін \"Артқа\" және \"Шолу\" түймелерін басып тұрыңыз."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Өзіңіз босатқаша ашық тұрады. Босату үшін \"Артқа\" және \"Негізгі бет\" түймелерін басып тұрыңыз"</string> @@ -852,8 +858,7 @@ <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_fullscreen" msgid="5043514702759201964">"Толық экран"</string> <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> @@ -889,18 +894,15 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Барлық басқару элементтері жойылды."</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өзгерістер сақталмады."</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Басқа қолданбаларды көру"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Қайта реттеу"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Басқару элементтерін қосу"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Өзгерту бетіне оралу"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Басқару элементтері жүктелмеді. Қолданба параметрлерінің өзгермегенін тексеру үшін <xliff:g id="APP">%s</xliff:g> қолданбасын қараңыз."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Үйлесімді басқару элементтері қолжетімді емес."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Басқа"</string> <string name="controls_dialog_title" msgid="2343565267424406202">"Құрылғы басқару элементтеріне қосу"</string> <string name="controls_dialog_ok" msgid="2770230012857881822">"Енгізу"</string> - <string name="controls_dialog_remove" msgid="3775288002711561936">"Өшіру"</string> + <string name="controls_dialog_remove" msgid="3775288002711561936">"Жою"</string> <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ұсынған"</string> <string name="controls_tile_locked" msgid="731547768182831938">"Құрылғы құлыпталды."</string> <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Құрылғыларды құлып экранынан көрсетуге және басқаруға рұқсат берілсін бе?"</string> @@ -954,7 +956,7 @@ <string name="controls_menu_add" msgid="4447246119229920050">"Басқару элементтерін қосу"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Басқару элементтерін өзгерту"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Қолданба қосу"</string> - <string name="controls_menu_remove" msgid="3006525275966023468">"Қолданбаны өшіру"</string> + <string name="controls_menu_remove" msgid="3006525275966023468">"Қолданбаны жою"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Шығыс сигналдарды қосу"</string> <string name="media_output_dialog_group" msgid="5571251347877452212">"Топ"</string> <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 құрылғы таңдалды."</string> @@ -1124,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Жұмыс саясатыңызға сәйкес тек жұмыс профилінен қоңырау шалуға болады."</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Жұмыс профиліне ауысу"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Жабу"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Экран құлпының параметрлері"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi қолжетімсіз."</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера бөгелген."</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера мен микрофон бөгелген."</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 0d4333f81bd7..02a453bab763 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ចាប់ផ្ដើម"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ឈប់"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"មុខងារប្រើដៃម្ខាង"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"កម្រិតរំលេចពណ៌"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ស្តង់ដារ"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"មធ្យម"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"ខ្ពស់"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ឈប់ទប់ស្កាត់មីក្រូហ្វូនរបស់ឧបករណ៍ឬ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ឈប់ទប់ស្កាត់កាមេរ៉ារបស់ឧបករណ៍ឬ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ឈប់ទប់ស្កាត់កាមេរ៉ា និងមីក្រូហ្វូនរបស់ឧបករណ៍ឬ?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"បិទ"</string> <string name="sound_settings" msgid="8874581353127418308">"សំឡេង និងការញ័រ"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ការកំណត់"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"បានបន្ថយទៅកម្រិតសំឡេងដែលកាន់តែមានសុវត្ថិភាព"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"កម្រិតសំឡេងខ្ពស់ក្នុងរយៈពេលយូរជាងកម្រិតដែលបានណែនាំ"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"កម្មវិធីត្រូវបានខ្ទាស់"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"វានឹងនៅតែបង្ហាញ រហូតទាល់តែអ្នកដកការដៅ។ សូមសង្កត់ប៊ូតុងថយក្រោយ និងប៊ូតុងទិដ្ឋភាពរួមឲ្យជាប់ ដើម្បីដកការដៅ។"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"វានឹងនៅតែបង្ហាញ រហូតទាល់តែអ្នកដកការដៅ។ សូមចុចប៊ូតុងថយក្រោយ និងប៊ូតុងទំព័រដើមឱ្យជាប់ ដើម្បីដកការដៅ។"</string> @@ -517,13 +519,13 @@ <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ការកំណត់អេក្រង់ចាក់សោ"</string> <string name="qr_code_scanner_title" msgid="1938155688725760702">"កម្មវិធីស្កេនកូដ QR"</string> <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"កំពុងដំឡើងកំណែ"</string> - <string name="status_bar_work" msgid="5238641949837091056">"ប្រវត្តិរូបការងារ"</string> + <string name="status_bar_work" msgid="5238641949837091056">"កម្រងព័ត៌មានការងារ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ពេលជិះយន្តហោះ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"អ្នកនឹងមិនលឺម៉ោងរោទ៍ <xliff:g id="WHEN">%1$s</xliff:g> បន្ទាប់របស់អ្នកទេ"</string> <string name="alarm_template" msgid="2234991538018805736">"នៅ <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"នៅ <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ហតស្ប៉ត"</string> - <string name="accessibility_managed_profile" msgid="4703836746209377356">"ប្រវត្តិរូបការងារ"</string> + <string name="accessibility_managed_profile" msgid="4703836746209377356">"កម្រងព័ត៌មានការងារ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"ល្អសម្រាប់អ្នកប្រើមួយចំនួន តែមិនសម្រាប់គ្រប់គ្នាទេ"</string> <string name="tuner_warning" msgid="1861736288458481650">"កម្មវិធីសម្រួល UI ប្រព័ន្ធផ្តល់ជូនអ្នកនូវមធ្យោបាយបន្ថែមទៀតដើម្បីកែសម្រួល និងប្តូរចំណុចប្រទាក់អ្នកប្រើ Android តាមបំណង។ លក្ខណៈពិសេសសាកល្បងនេះអាចនឹងផ្លាស់ប្តូរ បំបែក ឬបាត់បង់បន្ទាប់ពីការចេញផ្សាយនាពេលអនាគត។ សូមបន្តដោយប្រុងប្រយ័ត្ន។"</string> <string name="tuner_persistent_warning" msgid="230466285569307806">"លក្ខណៈពិសេសសាកល្បងនេះអាចនឹងផ្លាស់ប្តូរ បំបែក ឬបាត់បង់បន្ទាប់ពីការចេញផ្សាយនាពេលអនាគត។ សូមបន្តដោយប្រុងប្រយ័ត្ន។"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"បានដកផ្ទាំងគ្រប់គ្រងទាំងអស់ហើយ"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"មិនបានរក្សាទុកការផ្លាស់ប្ដូរទេ"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"មើលកម្មវិធីផ្សេងទៀត"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"តម្រៀបឡើងវិញ"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"បញ្ចូលការគ្រប់គ្រង"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ត្រឡប់ទៅការកែវិញ"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"មិនអាចផ្ទុកការគ្រប់គ្រងបានទេ។ សូមពិនិត្យមើលកម្មវិធី <xliff:g id="APP">%s</xliff:g> ដើម្បីធ្វើឱ្យប្រាកដថាការកំណត់កម្មវិធីមិនបានផ្លាស់ប្ដូរ។"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"មិនអាចប្រើការគ្រប់គ្រងដែលត្រូវគ្នាបានទេ"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ផ្សេងៗ"</string> @@ -951,7 +950,7 @@ <string name="controls_error_generic" msgid="352500456918362905">"មិនអាចផ្ទុកស្ថានភាពបានទេ"</string> <string name="controls_error_failed" msgid="960228639198558525">"មានបញ្ហា សូមព្យាយាមម្តងទៀត"</string> <string name="controls_menu_add" msgid="4447246119229920050">"បញ្ចូលផ្ទាំងគ្រប់គ្រង"</string> - <string name="controls_menu_edit" msgid="890623986951347062">"កែផ្ទាំងគ្រប់គ្រង"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"កែការគ្រប់គ្រង"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"បញ្ចូលកម្មវិធី"</string> <string name="controls_menu_remove" msgid="3006525275966023468">"ដកកម្មវិធីចេញ"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"បញ្ចូលឧបករណ៍មេឌៀ"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"គោលការណ៍ការងាររបស់អ្នកអនុញ្ញាតឱ្យអ្នកធ្វើការហៅទូរសព្ទបានតែពីកម្រងព័ត៌មានការងារប៉ុណ្ណោះ"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"ប្ដូរទៅកម្រងព័ត៌មានការងារ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"បិទ"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"ការកំណត់អេក្រង់ចាក់សោ"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"មិនមាន Wi-Fi ទេ"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"បានទប់ស្កាត់កាមេរ៉ា"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"បានទប់ស្កាត់កាមេរ៉ា និងមីក្រូហ្វូន"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 43fc73516269..40497e9f5cce 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ಪ್ರಾರಂಭಿಸಿ"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ನಿಲ್ಲಿಸಿ"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ಒಂದು ಕೈ ಮೋಡ್"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"ಕಾಂಟ್ರಾಸ್ಟ್"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ಪ್ರಮಾಣಿತ"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ಮಧ್ಯಮ"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"ಹೆಚ್ಚು"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ಸಾಧನದ ಮೈಕ್ರೋಫೋನ್ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ಸಾಧನದ ಕ್ಯಾಮರಾ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ಸಾಧನದ ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಅನ್ಬ್ಲಾಕ್ ಮಾಡಬೇಕೇ?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string> <string name="sound_settings" msgid="8874581353127418308">"ಧ್ವನಿ & ವೈಬ್ರೇಷನ್"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"ಸುರಕ್ಷಿತ ವಾಲ್ಯೂಮ್ಗೆ ಕಡಿಮೆ ಮಾಡಲಾಗಿದೆ"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"ಶಿಫಾರಸು ಮಾಡಿದ ಸಮಯಕ್ಕಿಂತ ಹೆಚ್ಚು ಸಮಯ ವಾಲ್ಯೂಮ್ ಹೆಚ್ಚಾಗಿರುತ್ತದೆ"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ಆ್ಯಪ್ ಅನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"ನೀವು ಅನ್ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್ಪಿನ್ ಮಾಡಲು ಅವಲೋಕಿಸಿ."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ನೀವು ಅನ್ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್ಪಿನ್ ಮಾಡಲು ಮುಖಪುಟಕ್ಕೆ ಹಿಂತಿರುಗಿ."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"ಎಲ್ಲಾ ನಿಯಂತ್ರಣಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗಿಲ್ಲ"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"ಇತರ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"ಮರುಹೊಂದಿಸಿ"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"ಕಂಟ್ರೋಲ್ಗಳನ್ನು ಸೇರಿಸಿ"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ಎಡಿಟ್ ಮಾಡುವಿಕೆಗೆ ಹಿಂತಿರುಗಿ"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"ನಿಯಂತ್ರಣಗಳನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ಆ್ಯಪ್ ಸೆಟ್ಟಿಂಗ್ಗಳು ಬದಲಾಗಿಲ್ಲ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು <xliff:g id="APP">%s</xliff:g> ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"ಹೊಂದಾಣಿಕೆಯ ನಿಯಂತ್ರಣಗಳು ಲಭ್ಯವಿಲ್ಲ"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ಇತರ"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ನಿಮ್ಮ ಕೆಲಸದ ನೀತಿಯು ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ನಿಂದ ಮಾತ್ರ ಫೋನ್ ಕರೆಗಳನ್ನು ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ಗೆ ಬದಲಿಸಿ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ಮುಚ್ಚಿರಿ"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲ"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ಕ್ಯಾಮರಾವನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 724233c65846..3490542208d0 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"시작"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"중지"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"한 손 사용 모드"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"대비"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"표준"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"보통"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"높음"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 &#173;차단 해제하시겠습니까?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"기기 카메라를 차단 해제하시겠습니까?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"기기 카메라 및 마이크를 차단 해제하시겠습니까?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"사용 중지"</string> <string name="sound_settings" msgid="8874581353127418308">"소리 및 진동"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"설정"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"청력 보호를 위해 적정 볼륨으로 낮춤"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"볼륨이 권장 시간보다 긴 시간 동안 높은 상태였습니다"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"앱 고정됨"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 최근 사용을 길게 터치하세요."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 홈을 길게 터치하세요."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"모든 컨트롤 삭제됨"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"변경사항이 저장되지 않음"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"다른 앱 보기"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"다시 정렬"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"제어 기능 추가"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"수정 모드로 돌아가기"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"컨트롤을 로드할 수 없습니다. <xliff:g id="APP">%s</xliff:g> 앱에서 설정이 변경되지 않았는지 확인하세요."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"호환 컨트롤을 사용할 수 없습니다."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"기타"</string> @@ -951,7 +950,7 @@ <string name="controls_error_generic" msgid="352500456918362905">"통계를 로드할 수 없음"</string> <string name="controls_error_failed" msgid="960228639198558525">"오류. 다시 시도하세요."</string> <string name="controls_menu_add" msgid="4447246119229920050">"컨트롤 추가"</string> - <string name="controls_menu_edit" msgid="890623986951347062">"제어 설정 수정"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"컨트롤 수정"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"앱 추가"</string> <string name="controls_menu_remove" msgid="3006525275966023468">"앱 삭제"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"출력 추가"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"직장 정책이 직장 프로필에서만 전화를 걸도록 허용합니다."</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"직장 프로필로 전환"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"닫기"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"잠금 화면 설정"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi를 사용할 수 없음"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"카메라 차단됨"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"카메라 및 마이크 차단됨"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 2c43d93c0636..23e553c6da57 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Баштадык"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Токтотуу"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бир кол режими"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Кадимки"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Орточо"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Жогору"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Түзмөктүн микрофонун бөгөттөн чыгарасызбы?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Түзмөктүн камерасын бөгөттөн чыгарасызбы?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Түзмөктүн камерасы менен микрофону бөгөттөн чыгарылсынбы?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өчүрүү"</string> <string name="sound_settings" msgid="8874581353127418308">"Үн жана дирилдөө"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Параметрлер"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Коопсуз үн көлөмүнө төмөндөтүлдү"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Үн көлөмү сунушталгандан узагыраак убакыт жогору болду"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Колдонмо кадалды"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн \"Артка\" жана \"Назар\" баскычтарын басып, кармап туруңуз."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Бардык башкаруу элементтери өчүрүлдү"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өзгөртүүлөр сакталган жок"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Башка колдонмолорду көрүү"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Иреттештирүү"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Башкаруу элементтерин кошуу"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Түзөтүүгө кайтуу"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Башкаруу элементтери жүктөлгөн жок. <xliff:g id="APP">%s</xliff:g> колдонмосуна өтүп, колдонмонун параметрлери өзгөрбөгөнүн текшериңиз."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Шайкеш башкаруу элементтери жеткиликсиз"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Башка"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Жумуш саясатыңызга ылайык, жумуш профилинен гана чалууларды аткара аласыз"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Жумуш профилине которулуу"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Жабуу"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Кулпуланган экран параметрлери"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi жеткиликтүү эмес"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера бөгөттөлдү"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера менен микрофон бөгөттөлдү"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index b57f8368bcdb..9c56eac3e42e 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ເລີ່ມ"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ຢຸດ"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ໂໝດມືດຽວ"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"ຄອນທຣາສ"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ມາດຕະຖານ"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ປານກາງ"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"ສູງ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ຍົກເລີກການບລັອກໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ຍົກເລີກການບລັອກກ້ອງຖ່າຍຮູບອຸປະກອນບໍ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ຍົກເລີກການບລັອກກ້ອງຖ່າຍຮູບ ຫຼື ໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string> @@ -886,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"ລຶບການຄວບຄຸມທັງໝົດອອກແລ້ວ"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ບໍ່ໄດ້ບັນທຶກການປ່ຽນແປງໄວ້"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"ເບິ່ງແອັບອື່ນໆ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"ຈັດຮຽງຄືນໃໝ່"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"ເພີ່ມການຄວບຄຸມ"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ກັບຄືນໄປຫາການແກ້ໄຂ"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"ບໍ່ສາມາດໂຫຼດການຄວບຄຸມໄດ້. ກວດສອບແອັບ <xliff:g id="APP">%s</xliff:g> ເພື່ອໃຫ້ແນ່ໃຈວ່າຍັງບໍ່ມີການປ່ຽນແປງການຕັ້ງຄ່າແອັບເທື່ອ."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"ບໍ່ມີການຄວບຄຸມທີ່ໃຊ້ຮ່ວມກັນທີ່ສາມາດໃຊ້ໄດ້"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ອື່ນໆ"</string> @@ -1121,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ນະໂຍບາຍບ່ອນເຮັດວຽກຂອງທ່ານອະນຸຍາດໃຫ້ທ່ານໂທລະສັບໄດ້ຈາກໂປຣໄຟລ໌ບ່ອນເຮັດວຽກເທົ່ານັ້ນ"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"ສະຫຼັບໄປໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ປິດ"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"ການຕັ້ງຄ່າໜ້າຈໍລັອກ"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ບໍ່ພ້ອມໃຫ້ນຳໃຊ້"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ກ້ອງຖ່າຍຮູບຖືກບລັອກຢູ່"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນຖືກບລັອກຢູ່"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index ab2ac5ae3c25..3938ae377aab 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Pradėti"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stabdyti"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienos rankos režimas"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Panaikinti įrenginio mikrofono blokavimą?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Panaikinti įrenginio fotoaparato blokavimą?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Panaikinti įrenginio fotoaparato ir mikrofono blokavimą?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"išjungti"</string> <string name="sound_settings" msgid="8874581353127418308">"Garsas ir vibravimas"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nustatymai"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Sumažinta iki saugesnio garsumo"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Garsumas buvo aukštas ilgiau, nei rekomenduojama"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Programa prisegta"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Apžvalga“, kad atsegtumėte."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Pagrindinis ekranas“, kad atsegtumėte."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Visi valdikliai pašalinti"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Pakeitimai neišsaugoti"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Žr. kitas programas"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Pertvarkyti"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Pridėti valdiklių"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Atgal į redagavimą"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Nepavyko įkelti valdiklių. Eikite į programą „<xliff:g id="APP">%s</xliff:g>“ ir įsitikinkite, kad programos nustatymai nepakeisti."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Suderinami valdikliai nepasiekiami"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Kita"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Pagal jūsų darbo politiką galite skambinti telefonu tik iš darbo profilio"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Perjungti į darbo profilį"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Uždaryti"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Užrakinimo ekrano nustatymai"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"„Wi-Fi“ ryšys nepasiekiamas"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Fotoaparatas užblokuotas"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparatas ir mikrofonas užblokuoti"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 4992eb169c2a..963744a9452a 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Sākt"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Apturēt"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienas rokas režīms"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vai atbloķēt ierīces mikrofonu?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vai vēlaties atbloķēt ierīces kameru?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vai atbloķēt ierīces kameru un mikrofonu?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"atspējot"</string> <string name="sound_settings" msgid="8874581353127418308">"Skaņa un vibrācija"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Iestatījumi"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Skaļums samazināts līdz drošākam"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Skaļums ir bijis liels ilgāk, nekā ieteicams."</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Lietotne ir piesprausta"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogām Atpakaļ un Pārskats un turiet tās."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogām “Atpakaļ” un “Sākums” un turiet tās."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Visas vadīklas ir noņemtas"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Izmaiņas nav saglabātas."</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Skatīt citas lietotnes"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Pārkārtot"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Pievienot vadīklas"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Atgriezties pie rediģēšanas"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Nevarēja ielādēt vadīklas. Lietotnē <xliff:g id="APP">%s</xliff:g> pārbaudiet, vai nav mainīti lietotnes iestatījumi."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Nav pieejamas saderīgas vadīklas"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Cita"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Saskaņā ar jūsu darba politiku tālruņa zvanus drīkst veikt tikai no darba profila"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Pārslēgties uz darba profilu"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Aizvērt"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Bloķēšanas ekrāna iestatījumi"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nav pieejams"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera ir bloķēta"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameras un mikrofona lietošana ir bloķēta"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index ec30a5baf027..936552c10742 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Започни"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Сопри"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим со една рака"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се одблокира пристапот до микрофонот на уредот?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се одблокира пристапот до камерата на уредот?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се одблокира пристапот до камерата и микрофонот на уредот?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"оневозможи"</string> <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрации"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Поставки"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Намалено на побезбедна јачина на звук"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Јачината на звукот е висока подолго од препорачаното"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е закачена"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Назад“ и „Почетен екран“ за откачување."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Сите контроли се отстранети"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Промените не се зачувани"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Видете други апликации"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Преуредување"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Додајте контроли"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Назад на изменување"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Контролите не може да се вчитаат. Проверете ја апликацијата <xliff:g id="APP">%s</xliff:g> за да се уверите дека поставките за апликацијата не се променети."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Нема компатибилни контроли"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друга"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Вашето работно правило ви дозволува да упатувате повици само од работниот профил"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Префрли се на работен профил"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Затвори"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Поставки за заклучен екран"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi не е достапно"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерата е блокирана"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камерата и микрофонот се блокирани"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 790ebdb26553..bf69050d2342 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ആരംഭിക്കുക"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"നിര്ത്തുക"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ഒറ്റക്കൈ മോഡ്"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"കോൺട്രാസ്റ്റ്"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"സ്റ്റാൻഡേർഡ്"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ഇടത്തരം"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"കൂടുതൽ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ഉപകരണ മൈക്രോഫോൺ അൺബ്ലോക്ക് ചെയ്യണോ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ഉപകരണ ക്യാമറ അൺബ്ലോക്ക് ചെയ്യണോ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ഉപകരണ ക്യാമറയോ മൈക്രോഫോണോ അൺബ്ലോക്ക് ചെയ്യണോ?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"പ്രവർത്തനരഹിതമാക്കുക"</string> <string name="sound_settings" msgid="8874581353127418308">"ശബ്ദവും വൈബ്രേഷനും"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ക്രമീകരണം"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"കൂടുതൽ സുരക്ഷിതമായ നിലയിലേക്ക് വോളിയം കുറച്ചു"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"നിർദ്ദേശിച്ചതിനേക്കാൾ കൂടുതൽ സമയം വോളിയം ഉയർന്ന നിലയിലായിരുന്നു"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ആപ്പ് പിൻ ചെയ്തു"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ\', \'ചുരുക്കവിവരണം\' എന്നിവ സ്പർശിച്ച് പിടിക്കുക."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ പോവുക\', \'ഹോം\' ബട്ടണുകൾ സ്പർശിച്ച് പിടിക്കുക."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"എല്ലാ നിയന്ത്രണങ്ങളും നീക്കം ചെയ്തു"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"മാറ്റങ്ങൾ സംരക്ഷിച്ചിട്ടില്ല"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"മറ്റ് ആപ്പുകൾ കാണുക"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"പുനഃക്രമീകരിക്കുക"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"എഡിറ്റിംഗിലേക്ക് മടങ്ങുക"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"നിയന്ത്രണങ്ങൾ ലോഡ് ചെയ്യാനായില്ല. ആപ്പ് ക്രമീകരണം മാറ്റിയിട്ടില്ലെന്ന് ഉറപ്പാക്കാൻ <xliff:g id="APP">%s</xliff:g> ആപ്പ് പരിശോധിക്കുക."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"അനുയോജ്യമായ നിയന്ത്രണങ്ങൾ ലഭ്യമല്ല"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"മറ്റുള്ളവ"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ഔദ്യോഗിക പ്രൊഫൈലിൽ നിന്ന് മാത്രം ഫോൺ കോളുകൾ ചെയ്യാനാണ് നിങ്ങളുടെ ഔദ്യോഗിക നയം അനുവദിക്കുന്നത്"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"അടയ്ക്കുക"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"ലോക്ക് സ്ക്രീൻ ക്രമീകരണം"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"വൈഫൈ ലഭ്യമല്ല"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ക്യാമറ ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ക്യാമറയും മൈക്രോഫോണും ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 5d00da28987f..a1add2755f2f 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Эхлүүлэх"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зогсоох"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Нэг гарын горим"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Ялгарал"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандарт"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Дунд зэрэг"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Өндөр"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Төхөөрөмжийн микрофоныг блокоос гаргах уу?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Төхөөрөмжийн камерыг блокоос гаргах уу?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Төхөөрөмжийн камер болон микрофоныг блокоос гаргах уу?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"идэвхгүй болгох"</string> <string name="sound_settings" msgid="8874581353127418308">"Дуу, чичиргээ"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Тохиргоо"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Аюулгүй дууны түвшин рүү багасгасан"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Дууны түвшин санал болгосноос удаан хугацааны туршид өндөр байсан"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Аппыг бэхэлсэн"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулна. Тогтоосныг болиулахын тулд Буцах, Тоймыг дараад хүлээнэ үү."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд Буцах, Нүүр хуудас товчлуурыг дараад хүлээнэ үү."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Бүх хяналтыг хассан"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өөрчлөлтийг хадгалаагүй"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Бусад аппыг харах"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Дахин эмхлэх"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Тохиргоо нэмэх"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Засах руу буцах"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Хяналтыг ачаалж чадсангүй. Аппын тохиргоог өөрчлөөгүй эсэхийг нягтлахын тулд <xliff:g id="APP">%s</xliff:g> аппыг шалгана уу."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Тохирох хяналт байхгүй"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Бусад"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Таны ажлын бодлого танд зөвхөн ажлын профайлаас утасны дуудлага хийхийг зөвшөөрдөг"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Ажлын профайл руу сэлгэх"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Хаах"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Түгжигдсэн дэлгэцийн тохиргоо"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi боломжгүй байна"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерыг блоклосон"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камер болон микрофоныг блоклосон"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 20b1267a95f6..8f70aaf454f5 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरू"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"थांबा"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एकहाती मोड"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"कॉंट्रास्ट"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"साधारण"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"मध्यम"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"उच्च"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिव्हाइसचा मायक्रोफोन अनब्लॉक करायचा आहे का?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिव्हाइसचा कॅमेरा अनब्लॉक करायचा आहे का?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिव्हाइसचा कॅमेरा आणि मायक्रोफोन अनब्लॉक करायचा आहे का?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करा"</string> <string name="sound_settings" msgid="8874581353127418308">"आवाज आणि व्हायब्रेशन"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिंग्ज"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"सुरक्षित आवाजापर्यंत कमी केले"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"आवाजाची पातळी शिफारस केलेल्या वेळेपेक्षा जास्त वेळ उच्च आहे"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ॲप पिन केले आहे"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"तुम्ही अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्यासाठी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तुम्ही अनपिन करेर्यंत हे त्याला दृश्यामध्ये ठेवते. अनपिन करण्यासाठी मागे आणि होम वर स्पर्श करा आणि धरून ठेवा."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"सर्व नियंत्रणे काढून टाकली आहेत"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"बदल सेव्ह केले गेले नाहीत"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"इतर अॅप्स पहा"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"पुन्हा संगतवार लावा"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"नियंत्रणे जोडा"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"संपादनावर परत जा"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"नियंत्रणे लोड करता अली नाहीत. ॲपची सेटिंग्ज बदलली नसल्याची खात्री करण्यासाठी <xliff:g id="APP">%s</xliff:g> ॲप तपासा."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"कंपॅटिबल नियंत्रणे उपलब्ध नाहीत"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"इतर"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"तुमचे कामाशी संबंधित धोरण तुम्हाला फक्त कार्य प्रोफाइलवरून फोन कॉल करन्याची अनुमती देते"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"कार्य प्रोफाइलवर स्विच करा"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"बंद करा"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"लॉक स्क्रीन सेटिंग्ज"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाय-फाय उपलब्ध नाही"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कॅमेरा ब्लॉक केला"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कॅमेरा आणि मायक्रोफोन ब्लॉक केले आहेत"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 5936fc811f98..24f60fd1dbfd 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mula"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mod sebelah tangan"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontras"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Sederhana"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Tinggi"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Nyahsekat mikrofon peranti?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Nyahsekat kamera peranti?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Nyahsekat kamera dan mikrofon peranti?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"lumpuhkan"</string> <string name="sound_settings" msgid="8874581353127418308">"Bunyi & getaran"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Tetapan"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Dikurangkan kepada kelantangan yang lebih selamat"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Kelantangan tinggi melebihi tempoh yang disyorkan"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Apl telah disemat"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh & tahan Kembali dan Ikhtisar untuk menyahsemat."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh & tahan Kembali dan Skrin Utama untuk menyahsemat."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Semua kawalan dialih keluar"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Perubahan tidak disimpan"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Lihat apl lain"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Susun semula"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Tambah kawalan"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Kembali mengedit"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Kawalan tidak dapat dimuatkan. Semak apl <xliff:g id="APP">%s</xliff:g> untuk memastikan bahawa tetapan apl tidak berubah."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kawalan serasi tidak tersedia"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lain-lain"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Dasar kerja anda membenarkan anda membuat panggilan telefon hanya daripada profil kerja"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Tukar kepada profil kerja"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tutup"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Tetapan skrin kunci"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi tidak tersedia"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera disekat"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon disekat"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index ae55ab2f2749..873d488433c4 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"စတင်ရန်"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ရပ်ရန်"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"လက်တစ်ဖက်သုံးမုဒ်"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"ဆန့်ကျင်ဘက်"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ပုံမှန်"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"အသင့်အတင့်"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"များ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"စက်၏မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"စက်၏ကင်မရာကို ပြန်ဖွင့်မလား။"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"စက်၏ကင်မရာနှင့် မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ပိတ်ရန်"</string> <string name="sound_settings" msgid="8874581353127418308">"အသံနှင့် တုန်ခါမှု"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ဆက်တင်များ"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"ပိုအန္တရာယ်ကင်းသော အသံသို့ လျှော့ထားသည်"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"အသံကို အကြံပြုထားသည်ထက် ပိုကြာမြင့်စွာ ချဲ့ထားသည်"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"အက်ပ်ကို ပင်ထိုးထားသည်"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"သင်ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် Back နှင့် Overview ကို ထိ၍ဖိထားပါ။"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"သင်က ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'ပင်မ\' ခလုတ်တို့ကို တို့၍ဖိထားပါ။"</string> @@ -875,7 +877,7 @@ <string name="controls_removed" msgid="3731789252222856959">"ဖယ်ရှားထားသည်"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ထည့်မလား။"</string> <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="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> <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"အကြိုက်ဆုံးမှ ဖယ်ရှားထားသည်"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"ထိန်းချုပ်မှုအားလုံး ဖယ်ရှားလိုက်သည်"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"အပြောင်းအလဲများကို သိမ်းမထားပါ"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"အခြားအက်ပ်များကိုကြည့်ပါ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"ပြန်စီရန်"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"သတ်မှတ်ချက်များ ထည့်ရန်"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"တည်းဖြတ်ခြင်းသို့ ပြန်သွားရန်"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"ထိန်းချုပ်မှုများကို ဖွင့်၍မရပါ။ အက်ပ်ဆက်တင်များ ပြောင်းမထားကြောင်း သေချာစေရန် <xliff:g id="APP">%s</xliff:g> အက်ပ်ကို စစ်ဆေးပါ။"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"ကိုက်ညီသော ထိန်းချုပ်မှုများကို မရရှိနိုင်ပါ"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"အခြား"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"သင့်အလုပ်မူဝါဒသည် သင့်အား အလုပ်ပရိုဖိုင်မှသာ ဖုန်းခေါ်ဆိုခွင့် ပြုသည်"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"အလုပ်ပရိုဖိုင်သို့ ပြောင်းရန်"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ပိတ်ရန်"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"လော့ခ်မျက်နှာပြင် ဆက်တင်များ"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi မရနိုင်ပါ"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ကင်မရာကို ပိတ်ထားသည်"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ကင်မရာနှင့် မိုက်ခရိုဖုန်းကို ပိတ်ထားသည်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index ea274600fdf4..b52f611807e2 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -248,7 +248,7 @@ <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internett"</string> <string name="quick_settings_networks_available" msgid="1875138606855420438">"Tilgjengelige nettverk"</string> <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nettverk er utilgjengelige"</string> - <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ingen tilgjengelige Wifi-nettverk"</string> + <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ingen tilgjengelige wifi-nettverk"</string> <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Slår på …"</string> <string name="quick_settings_cast_title" msgid="2279220930629235211">"Skjermcasting"</string> <string name="quick_settings_casting" msgid="1435880708719268055">"Casting"</string> @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stopp"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndsmodus"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du oppheve blokkeringen av enhetsmikrofonen?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du oppheve blokkeringen av enhetskameraet?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du oppheve blokkeringen av enhetskameraet og -mikrofonen?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiver"</string> <string name="sound_settings" msgid="8874581353127418308">"Lyd og vibrering"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Innstillinger"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Redusert til et tryggere volum"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Volumet har vært høyt lengre enn anbefalt"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er festet"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Gjør at den vises til du løsner den. Trykk og hold inne Tilbake og Oversikt for å løsne den."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Gjør at den vises til du løsner den. Trykk og hold inne Tilbake og Startside for å løsne den."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Alle kontroller er fjernet"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Endringene er ikke lagret"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Se andre apper"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Omorganiser"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Legg til kontroller"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Tilbake til redigering"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Kunne ikke laste inn kontrollene. Sjekk <xliff:g id="APP">%s</xliff:g>-appen for å sjekke at appinnstillingene ikke er endret."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kompatible kontroller er ikke tilgjengelige"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annet"</string> @@ -1046,7 +1049,7 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi kobles ikke til automatisk inntil videre"</string> <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string> - <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter Wifi-nettverk når som helst – også når Wifi er slått av. Du kan endre dette i innstillingene for wifi-skanning. "<annotation id="link">"Endre"</annotation></string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter wifi-nettverk når som helst – også når Wifi er slått av. Du kan endre dette i innstillingene for wifi-skanning. "<annotation id="link">"Endre"</annotation></string> <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Slå av flymodus"</string> <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil legge til denne brikken i Hurtiginnstillinger"</string> <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Legg til brikke"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Som følge av jobbreglene dine kan du bare starte telefonanrop fra jobbprofilen."</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Bytt til jobbprofilen"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Lukk"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Innstillinger for låseskjermen"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi er ikke tilgjengelig"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokkert"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameraet og mikrofonen er blokkert"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 8a2057a98fe3..a58391893625 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरु गर्नुहोस्"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोक्नुहोस्"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एक हाते मोड"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"कन्ट्रास्ट"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"डिफल्ट"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"मध्यम"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"उच्च"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिभाइसको माइक्रोफोन अनब्लक गर्ने हो?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिभाइसको क्यामेरा अनब्लक गर्ने हो?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिभाइसको क्यामेरा र माइक्रोफोन अनब्लक गर्ने हो?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"असक्षम पार्नुहोस्"</string> <string name="sound_settings" msgid="8874581353127418308">"साउन्ड तथा भाइब्रेसन"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिङ"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"तपाईं आरामदायी तरिकाले अडियो सुन्न सक्नुहोस् भन्नाका लागि भोल्युम घटाइएको छ"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"सिफारिस गरिएको समयभन्दा बढी समयदेखि भोल्युमको स्तर उच्च छ"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"एप पिन गरिएको छ"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई टच एण्ड होल्ड गर्नुहोस्।"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र गृह नामक बटनहरूलाई टच एण्ड होल्ड गर्नुहोस्।"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"सबै कन्ट्रोल हटाइए"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"परिवर्तनहरू सुरक्षित गरिएका छैनन्"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"अन्य एपहरू हेर्नुहोस्"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"पुनः मिलाउनुहोस्"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"कन्ट्रोलहरू हाल्नुहोस्"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"सम्पादन गर्ने स्क्रिनमा फर्कनुहोस्"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"नियन्त्रण सुविधाहरू लोड गर्न सकिएन। <xliff:g id="APP">%s</xliff:g> एपका सेटिङ परिवर्तन गरिएका छैनन् भन्ने कुरा सुनिश्चित गर्न उक्त एप जाँच्नुहोस्।"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"मिल्दा नियन्त्रण सुविधाहरू उपलब्ध छैनन्"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string> @@ -951,7 +950,7 @@ <string name="controls_error_generic" msgid="352500456918362905">"वस्तुस्थिति लोड गर्न सकिएन"</string> <string name="controls_error_failed" msgid="960228639198558525">"त्रुटि भयो, फेरि प्रयास गर्नु…"</string> <string name="controls_menu_add" msgid="4447246119229920050">"कन्ट्रोल थप्नुहोस्"</string> - <string name="controls_menu_edit" msgid="890623986951347062">"कन्ट्रोल सम्पादन गर्नुहोस्"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"सेटिङ सम्पादन गर्नुहोस्"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"एप हाल्नुहोस्"</string> <string name="controls_menu_remove" msgid="3006525275966023468">"यो एप हटाउनुहोस्"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट यन्त्रहरू थप्नुहोस्"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"तपाईंको कामसम्बन्धी नीतिअनुसार कार्य प्रोफाइलबाट मात्र फोन कल गर्न सकिन्छ"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"कार्य प्रोफाइल प्रयोग गर्नुहोस्"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"बन्द गर्नुहोस्"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"लक स्क्रिनसम्बन्धी सेटिङ"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi उपलब्ध छैन"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"क्यामेरा ब्लक गरिएको छ"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"क्यामेरा र माइक्रोफोन ब्लक गरिएको छ"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 1a0265fa6e60..19113a0e1ecd 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppen"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Bediening met 1 hand"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standaard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Gemiddeld"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hoog"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Blokkeren van apparaatmicrofoon opheffen?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Blokkeren van apparaatcamera opheffen?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Blokkeren van apparaatcamera en -microfoon opheffen?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"uitzetten"</string> <string name="sound_settings" msgid="8874581353127418308">"Geluid en trillen"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Instellingen"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Verlaagd naar veiliger volume"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Het volume is langer dan de aanbevolen tijd hoog geweest"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"App is vastgezet"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Overzicht en houd deze vast om het scherm los te maken."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Home en houd deze vast om het scherm los te maken."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Alle bedieningselementen verwijderd"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Wijzigingen zijn niet opgeslagen"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Andere apps bekijken"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Opnieuw indelen"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Bedieningselementen toevoegen"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Terug naar bewerken"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Bedieningselementen kunnen niet worden geladen. Check de <xliff:g id="APP">%s</xliff:g>-app om na te gaan of de app-instellingen niet zijn gewijzigd."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Geen geschikte bedieningselementen beschikbaar"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Overig"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Op basis van je werkbeleid kun je alleen bellen vanuit het werkprofiel"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Overschakelen naar werkprofiel"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Sluiten"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Instellingen vergrendelscherm"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi niet beschikbaar"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera geblokkeerd"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera en microfoon geblokkeerd"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index df284c18807f..acabe348b5e4 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ଆରମ୍ଭ କରନ୍ତୁ"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ଏକ-ହାତ ମୋଡ"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"କଣ୍ଟ୍ରାଷ୍ଟ"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ଷ୍ଟାଣ୍ଡାର୍ଡ"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ମଧ୍ୟମ"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"ଅଧିକ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ଡିଭାଇସର ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ କରିବେ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ଡିଭାଇସର କ୍ୟାମେରାକୁ ଅନବ୍ଲକ କରିବେ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ଡିଭାଇସର କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ୍ କରିବେ?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ଅକ୍ଷମ କରନ୍ତୁ"</string> <string name="sound_settings" msgid="8874581353127418308">"ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେସନ"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ସେଟିଂସ"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"ଭଲ୍ୟୁମକୁ ସୁରକ୍ଷିତ ସ୍ତରକୁ କମ କରାଯାଇଛି"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"ସୁପାରିଶ କରାଯାଇଥିବାଠାରୁ ଅଧିକ ସମୟ ପାଇଁ ଭଲ୍ୟୁମକୁ ଉଚ୍ଚ ସ୍ତରରେ ରଖାଯାଇଛି"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ଆପକୁ ପିନ୍ କରାଯାଇଛି"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"ଆପଣ ଅନପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ ଓ ଦେଖନ୍ତୁ।"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ଆପଣ ଅନପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍ କରିବା ପାଇଁ ହୋମ ଓ ବ୍ୟାକ ବଟନକୁ ଦବାଇ ଧରନ୍ତୁ।"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"ସମସ୍ତ ନିୟନ୍ତ୍ରଣ କାଢ଼ି ଦିଆଯାଇଛି"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ପରିବର୍ତ୍ତନଗୁଡ଼ିକ ସେଭ୍ କରାଯାଇନାହିଁ"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"ଅନ୍ୟ ଆପ୍ ଦେଖନ୍ତୁ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"ପୁଣି ସଜାନ୍ତୁ"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ଏଡିଟିଂକୁ ଫେରନ୍ତୁ"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଲୋଡ୍ କରାଯାଇପାରିଲା ନାହିଁ। ଆପ୍ ସେଟିଂସ୍ ପରିବର୍ତ୍ତନ ହୋଇନାହିଁ ବୋଲି ନିଶ୍ଚିତ କରିବାକୁ <xliff:g id="APP">%s</xliff:g> ଆପ୍ ଯାଞ୍ଚ କରନ୍ତୁ।"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"ସୁସଙ୍ଗତ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ଅନ୍ୟ"</string> @@ -947,7 +946,7 @@ <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>କୁ ଆକ୍ସେସ୍ କରିହେଲା ନାହିଁ। ନିୟନ୍ତ୍ରଣ ଏବେ ବି ଉପଲବ୍ଧ ଅଛି ଏବଂ ଆପ୍ ସେଟିଂସ୍ ବଦଳାଯାଇ ନାହିଁ ବୋଲି ସୁନିଶ୍ଚିତ କରିବାକୁ <xliff:g id="APPLICATION">%2$s</xliff:g> ଆପକୁ ଯାଞ୍ଚ କରନ୍ତୁ।"</string> - <string name="controls_open_app" msgid="483650971094300141">"ଆପ୍ ଖୋଲନ୍ତୁ"</string> + <string name="controls_open_app" msgid="483650971094300141">"ଆପ ଖୋଲନ୍ତୁ"</string> <string name="controls_error_generic" msgid="352500456918362905">"ସ୍ଥିତି ଲୋଡ୍ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="controls_error_failed" msgid="960228639198558525">"ତ୍ରୁଟି ହୋଇଛି, ପୁଣି ଚେଷ୍ଟା କର"</string> <string name="controls_menu_add" msgid="4447246119229920050">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ଆପଣଙ୍କ ୱାର୍କ ନୀତି ଆପଣଙ୍କୁ କେବଳ ୱାର୍କ ପ୍ରୋଫାଇଲରୁ ଫୋନ କଲ କରିବାକୁ ଅନୁମତି ଦିଏ"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"ୱାର୍କ ପ୍ରୋଫାଇଲକୁ ସ୍ୱିଚ କରନ୍ତୁ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ବନ୍ଦ କରନ୍ତୁ"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"ଲକ ସ୍କ୍ରିନ ସେଟିଂସ"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"କେମେରାକୁ ବ୍ଲକ କରାଯାଇଛି"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"କେମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ବ୍ଲକ କରାଯାଇଛି"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 67f13143fc59..a2a8aac72260 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ਸ਼ੁਰੂ ਕਰੋ"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ਰੋਕੋ"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ਇੱਕ ਹੱਥ ਮੋਡ"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"ਕੰਟ੍ਰਾਸਟ"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ਮਿਆਰੀ"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ਦਰਮਿਆਨਾ"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"ਜ਼ਿਆਦਾ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰੇ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰੇ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ਬੰਦ ਕਰੋ"</string> <string name="sound_settings" msgid="8874581353127418308">"ਧੁਨੀ ਅਤੇ ਥਰਥਰਾਹਟ"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ਸੈਟਿੰਗਾਂ"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"ਸੁਰੱਖਿਅਤ ਸੀਮਾ ਤੱਕ ਅਵਾਜ਼ ਨੂੰ ਘਟਾਇਆ ਗਿਆ"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"ਅਵਾਜ਼ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੇ ਸਮੇਂ ਤੋਂ ਲੰਮੇ ਸਮੇਂ ਤੱਕ ਉੱਚੀ ਰਹੀ ਹੈ"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ਐਪ ਨੂੰ ਪਿੰਨ ਕੀਤਾ ਗਿਆ ਹੈ"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਅਨਪਿੰਨ ਕੀਤੇ ਜਾਣ ਤੱਕ ਇਸਨੂੰ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਹੋਮ\' ਨੂੰ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"ਸਾਰੇ ਕੰਟਰੋਲ ਹਟਾਏ ਗਏ"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ਤਬਦੀਲੀਆਂ ਨੂੰ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"ਹੋਰ ਐਪਾਂ ਦੇਖੋ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"ਮੁੜ-ਵਿਵਸਥਿਤ ਕਰੋ"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ਸੰਪਾਦਨ ’ਤੇ ਵਾਪਸ ਜਾਓ"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"ਕੰਟਰੋਲਾਂ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਇਹ ਪੱਕਾ ਕਰਨ ਲਈ <xliff:g id="APP">%s</xliff:g> ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ ਕਿ ਐਪ ਸੈਟਿੰਗਾਂ ਨਹੀਂ ਬਦਲੀਆਂ ਹਨ।"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"ਕੋਈ ਅਨੁਰੂਪ ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ਹੋਰ"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ਤੁਹਾਡੀ ਕਾਰਜ ਨੀਤੀ ਤੁਹਾਨੂੰ ਸਿਰਫ਼ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਹੀ ਫ਼ੋਨ ਕਾਲਾਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ਬੰਦ ਕਰੋ"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"ਲਾਕ ਸਕ੍ਰੀਨ ਸੈਟਿੰਗਾਂ"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ਕੈਮਰਾ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤੇ ਗਏ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index db2ea3788b0e..b8554e1ef3b6 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Rozpocznij"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zatrzymaj"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tryb jednej ręki"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokować mikrofon urządzenia?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokować aparat urządzenia?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Odblokować aparat i mikrofon urządzenia?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"wyłącz"</string> <string name="sound_settings" msgid="8874581353127418308">"Dźwięk i wibracje"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ustawienia"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Obniżono głośność do bezpieczniejszego poziomu"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Głośność była zbyt duża przez czas dłuższy niż zalecany"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacja jest przypięta"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Wstecz oraz Przegląd."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Wstecz oraz Ekran główny."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Usunięto wszystkie elementy sterujące"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Zmiany nie zostały zapisane"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Wyświetl pozostałe aplikacje"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Zmień kolejność"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Dodaj elementy sterujące"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Wróć do edycji"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Nie udało się wczytać elementów sterujących. Sprawdź aplikację <xliff:g id="APP">%s</xliff:g>, aby upewnić się, że jej ustawienia się nie zmieniły."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Zgodne elementy sterujące niedostępne"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Inne"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Zasady obowiązujące w firmie zezwalają na nawiązywanie połączeń telefonicznych tylko w profilu służbowym"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Przełącz na profil służbowy"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zamknij"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Ustawienia ekranu blokady"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Sieć Wi-Fi jest niedostępna"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera jest zablokowana"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon są zablokowane"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 9e434d5d77cd..17ca232dbdbc 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo para uma mão"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Padrão"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Desbloquear a câmera e o microfone do dispositivo?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desativar"</string> <string name="sound_settings" msgid="8874581353127418308">"Som e vibração"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configurações"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Volume diminuído para um nível mais seguro"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"O volume ficou alto por mais tempo do que o recomendado"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Todos os controles foram removidos"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"As mudanças não foram salvas"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Ver outros apps"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Reorganizar"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Adicionar controles"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Voltar para a edição"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Não foi possível carregar os controles. Verifique o app <xliff:g id="APP">%s</xliff:g> para garantir que as configurações não tenham sido modificadas."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Controles compatíveis indisponíveis"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Sua política de trabalho só permite fazer ligações pelo perfil de trabalho"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Alternar para o perfil de trabalho"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fechar"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Configurações de tela de bloqueio"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 5de3135a6b28..c181a2c6d2a5 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo para uma mão"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Padrão"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmara do dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Pretende desbloquear a câmara e o microfone?"</string> @@ -886,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Todos os controlos foram removidos."</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Alterações não guardadas."</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Ver outras apps"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Reorganizar"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Adicionar controlos"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Regressar à edição"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Não foi possível carregar os controlos. Verifique a app <xliff:g id="APP">%s</xliff:g> para se certificar de que as definições da mesma não foram alteradas."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Controlos compatíveis indisponíveis"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string> @@ -1121,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"A sua Política de Trabalho só lhe permite fazer chamadas telefónicas a partir do perfil de trabalho"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Mudar para perfil de trabalho"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fechar"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Definições do ecrã de bloqueio"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmara e microfone bloqueados"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 9e434d5d77cd..17ca232dbdbc 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo para uma mão"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Padrão"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Desbloquear a câmera e o microfone do dispositivo?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desativar"</string> <string name="sound_settings" msgid="8874581353127418308">"Som e vibração"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configurações"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Volume diminuído para um nível mais seguro"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"O volume ficou alto por mais tempo do que o recomendado"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Todos os controles foram removidos"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"As mudanças não foram salvas"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Ver outros apps"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Reorganizar"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Adicionar controles"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Voltar para a edição"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Não foi possível carregar os controles. Verifique o app <xliff:g id="APP">%s</xliff:g> para garantir que as configurações não tenham sido modificadas."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Controles compatíveis indisponíveis"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Sua política de trabalho só permite fazer ligações pelo perfil de trabalho"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Alternar para o perfil de trabalho"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fechar"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Configurações de tela de bloqueio"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 6380223f2467..a68d650e4746 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Începe"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Oprește"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modul cu o mână"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mediu"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Ridicat"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblochezi microfonul dispozitivului?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblochezi camera dispozitivului?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblochezi camera și microfonul dispozitivului?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"dezactivează"</string> <string name="sound_settings" msgid="8874581353127418308">"Sunete și vibrații"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Setări"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Redus la un volum mai sigur"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Volumul a fost ridicat mai mult timp decât este recomandat"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplicația este fixată"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Astfel rămâne afișat până anulezi fixarea. Atinge lung opțiunile Înapoi și Recente pentru a anula fixarea."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Astfel rămâne afișat până anulezi fixarea. Atinge lung opțiunile Înapoi și Acasă pentru a anula fixarea."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Au fost șterse toate comenzile"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Modificările nu au fost salvate"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Vezi alte aplicații"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Rearanjează"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Adaugă comenzi"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Revino la editare"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Comenzile nu au putut fi încărcate. Accesează aplicația <xliff:g id="APP">%s</xliff:g> pentru a te asigura că setările aplicației nu s-au schimbat."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Nu sunt disponibile comenzi compatibile"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altul"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Politica privind activitatea îți permite să efectuezi apeluri telefonice numai din profilul de serviciu"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Comută la profilul de serviciu"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Închide"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Setările ecranului de blocare"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Conexiune Wi-Fi indisponibilă"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera foto a fost blocată"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera foto și microfonul sunt blocate"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index dd6aff6a3c18..8c434f866ee7 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Начать"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Остановить"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим управления одной рукой"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контрастность"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартная"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Средняя"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Высокая"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблокировать микрофон устройства?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблокировать камеру устройства?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблокировать камеру и микрофон устройства?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"отключить"</string> <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрация"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Открыть настройки"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Громкость уменьшена до безопасного уровня"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Громкость была высокой дольше рекомендованного периода."</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Приложение закреплено"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Обзор\"."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Главный экран\"."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Все виджеты управления удалены."</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Изменения не сохранены."</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Показать другие приложения"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Изменить порядок"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Добавить элементы управления"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Назад к редактированию"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Не удалось загрузить список виджетов для управления устройствами. Проверьте, не изменились ли настройки приложения \"<xliff:g id="APP">%s</xliff:g>\"."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Управление недоступно."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Другое"</string> @@ -951,7 +950,7 @@ <string name="controls_error_generic" msgid="352500456918362905">"Не удалось загрузить статус."</string> <string name="controls_error_failed" msgid="960228639198558525">"Ошибка. Повторите попытку."</string> <string name="controls_menu_add" msgid="4447246119229920050">"Добавить виджеты"</string> - <string name="controls_menu_edit" msgid="890623986951347062">"Изменить виджеты"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"Изменить настройки"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Добавить приложение"</string> <string name="controls_menu_remove" msgid="3006525275966023468">"Удалить приложение"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Добавление устройств вывода"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Согласно правилам вашей организации вы можете совершать телефонные звонки только из рабочего профиля."</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Перейти в рабочий профиль"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрыть"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Настройки блокировки экрана"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Функция Wi-Fi недоступна"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера заблокирована"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера и микрофон заблокированы"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 67ebeabffa1a..450693ea7364 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ආරම්භ කරන්න"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"නතර කරන්න"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"තනි අත් ප්රකාරය"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"උපාංග මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"උපාංග කැමරාව අවහිර කිරීම ඉවත් කරන්නද?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"උපාංග කැමරාව සහ මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"අබල කරන්න"</string> <string name="sound_settings" msgid="8874581353127418308">"ශබ්ද සහ කම්පනය"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"සැකසීම්"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"සුරක්ෂිත පරිමාවකට අඩු කරන ලදි"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"නිර්දේශිත ප්රමාණයට වඩා වැඩි කාලයක් පරිමාව ඉහළ මට්ටමක පවතී"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"යෙදුම අමුණා ඇත"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"මෙය ඔබ ගලවන තෙක් එය දසුන තුළ තබයි. ගැලවීමට දළ විශ්ලේෂණය ස්පර්ශ කර ආපසු අල්ලාගෙන සිටින්න."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"මෙය ඔබ ගලවන තෙක් එය දසුන තුළ තබයි. ගැලවීමට මුල් පිටුව ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"සියලු පාලන ඉවත් කර ඇත"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"වෙනස් කිරීම් නොසුරැකිණි"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"වෙනත් යෙදුම් බලන්න"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"නැවත පිළිවෙල කරන්න"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"පාලන එක් කරන්න"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ආපසු සංස්කරණයට"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"පාලන පූරණය කළ නොහැකි විය. යෙදුම් සැකසීම් වෙනස් වී නැති බව සහතික කර ගැනීමට <xliff:g id="APP">%s</xliff:g> යෙදුම පරීක්ෂා කරන්න."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"ගැළපෙන පාලන ලබා ගත නොහැකිය"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"වෙනත්"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ඔබේ වැඩ ප්රතිපත්තිය ඔබට කාර්යාල පැතිකඩෙන් පමණක් දුරකථන ඇමතුම් ලබා ගැනීමට ඉඩ සලසයි"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"කාර්යාල පැතිකඩ වෙත මාරු වන්න"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"වසන්න"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"අගුළු තිර සැකසීම්"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ලද නොහැක"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"කැමරාව අවහිරයි"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"කැමරාව සහ මයික්රොෆෝනය අවහිරයි"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 45faf7fff11d..f36fe2a39932 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začať"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončiť"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednej ruky"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Štandardný"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Stredný"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Vysoký"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Chcete odblokovať mikrofón zariadenia?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Chcete odblokovať kameru zariadenia?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Chcete odblokovať fotoaparát a mikrofón zariadenia?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"zakázať"</string> <string name="sound_settings" msgid="8874581353127418308">"Zvuk a vibrácie"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavenia"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Znížené na bezpečnú hlasitosť"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Hlasitosť bola vysoká dlhšie, ako sa odporúča"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikácia je pripnutá"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidiel Späť a Prehľad."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho pridržaním tlačidiel Späť a Domov."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Všetky ovládače boli odstránené"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Zmeny neboli uložené"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Zobraziť ďalšie aplikácie"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Usporiadať"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Pridať ovládanie"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Späť k úpravám"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Ovládacie prvky sa nepodarilo načítať. V aplikácii <xliff:g id="APP">%s</xliff:g> skontrolujte, či sa nezmenili nastavenia."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kompatibilné ovládacie prvky nie sú k dispozícii"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iné"</string> @@ -951,7 +950,7 @@ <string name="controls_error_generic" msgid="352500456918362905">"Stav sa nepodarilo načítať"</string> <string name="controls_error_failed" msgid="960228639198558525">"Chyba, skúste to znova"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Pridať ovládače"</string> - <string name="controls_menu_edit" msgid="890623986951347062">"Upraviť ovládače"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"Upraviť ovládanie"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Pridať aplikáciu"</string> <string name="controls_menu_remove" msgid="3006525275966023468">"Odstrániť aplikáciu"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Pridanie výstupov"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Pracovné pravidlá vám umožňujú telefonovať iba v pracovnom profile"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Prepnúť na pracovný profil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zavrieť"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Nastavenia uzamknutej obrazovky"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi‑Fi nie je k dispozícii"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokovaná"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofón sú blokované"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index e90a29de57e6..9edaaaeac86a 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začni"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ustavi"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enoročni način"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite odblokirati mikrofon v napravi?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite odblokirati fotoaparat v napravi?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite odblokirati fotoaparat in mikrofon v napravi?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogoči"</string> <string name="sound_settings" msgid="8874581353127418308">"Zvok in vibriranje"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavitve"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Glasnost znižana na varnejšo raven"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Glasnost je bila visoka dalj časa, kot je priporočeno."</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je pripeta"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, hkrati pridržite gumba za nazaj in za začetni zaslon."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Vsi kontrolniki so bili odstranjeni."</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Spremembe niso shranjene"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Prikaz drugih aplikacij"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Razvrščanje"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Dodajte kontrolnike"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Nazaj na urejanje"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Kontrolnikov ni bilo mogoče naložiti. Preverite aplikacijo <xliff:g id="APP">%s</xliff:g> in se prepričajte, da se njene nastavitve niso spremenile."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Združljivi kontrolniki niso na voljo"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Službeni pravilnik dovoljuje opravljanje telefonskih klicev le iz delovnega profila."</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Preklopi na delovni profil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zapri"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Nastavitve zaklepanja zaslona"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ni na voljo."</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Fotoaparat je blokiran."</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparat in mikrofon sta blokirana."</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 37248fe2874a..bcb9773e6a87 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Nis"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ndalo"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modaliteti i përdorimit me një dorë"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrasti"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mesatar"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"I lartë"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Të zhbllokohet mikrofoni i pajisjes?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Të zhbllokohet kamera e pajisjes?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Të zhbllokohen kamera dhe mikrofoni i pajisjes?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"çaktivizo"</string> <string name="sound_settings" msgid="8874581353127418308">"Tingulli dhe dridhjet"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Cilësimet"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Ulur në një volum më të sigurt"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Volumi ka qenë i lartë për një kohë më të gjatë nga sa rekomandohet"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacioni është i gozhduar"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Kreu\" për ta hequr nga gozhdimi."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Të gjitha kontrollet u hoqën"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ndryshimet nuk u ruajtën"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Shiko aplikacionet e tjera"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Riorganizo"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Shto kontrollet"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Kthehu prapa te modifikimi"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Kontrollet nuk mund të ngarkoheshin. Kontrollo aplikacionin <xliff:g id="APP">%s</xliff:g> për t\'u siguruar që cilësimet e aplikacionit nuk janë ndryshuar."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Kontrollet e përputhshme nuk ofrohen"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Tjetër"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Politika jote e punës të lejon të bësh telefonata vetëm nga profili i punës"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Kalo te profili i punës"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Mbyll"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Cilësimet e ekranit të kyçjes"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nuk ofrohet"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera u bllokua"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dhe mikrofoni u bllokuan"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index d26d5a49d5ee..b2d2b946f65d 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почните"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зауставите"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим једном руком"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Контраст"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандардно"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Средње"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Високо"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Желите да одблокирате микрофон уређаја?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Желите да одблокирате камеру уређаја?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Желите да одблокирате камеру и микрофон уређаја?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"онемогућите"</string> <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрирање"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Подешавања"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Звук је смањен на безбедну јачину"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Звук је био гласан дуже него што се препоручује"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Апликација је закачена"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Преглед да бисте га откачили."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Почетна да бисте га откачили."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Све контроле су уклоњене"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Промене нису сачуване"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Погледајте друге апликације"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Прераспореди"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Додај контроле"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Назад на измене"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Учитавање контрола није успело. Погледајте апликацију <xliff:g id="APP">%s</xliff:g> да бисте се уверили да се подешавања апликације нису променила."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Компатибилне контроле нису доступне"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Смернице за посао вам омогућавају да телефонирате само са пословног профила"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Пређи на пословни профил"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Затвори"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Подешавања закључаног екрана"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi није доступан"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера је блокирана"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера и микрофон су блокирани"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 58a74269706d..2def56db4ed9 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starta"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppa"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhandsläge"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vill du återaktivera enhetens mikrofon?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vill du återaktivera enhetens kamera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vill du återaktivera enhetens kamera och mikrofon?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"inaktivera"</string> <string name="sound_settings" msgid="8874581353127418308">"Ljud och vibration"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Inställningar"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Sänkte till säkrare volym"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Volymen har varit hög längre än vad som rekommenderas"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Appen har fästs"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Skärmen visas tills du lossar den. Tryck länge på Tillbaka och Översikt om du vill lossa skärmen."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Skärmen visas tills du lossar den. Tryck länge på Tillbaka och Startsida om du vill lossa skärmen."</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Alla kontroller har tagits bort"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ändringarna har inte sparats"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Visa andra appar"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Ordna om"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Lägg till kontroller"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Tillbaka till redigering"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Det gick inte att läsa in enhetsstyrning. Kontrollera att inställningarna inte har ändrats i <xliff:g id="APP">%s</xliff:g>-appen."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Ingen kompatibel enhetsstyrning tillgänglig"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Övrigt"</string> @@ -951,7 +954,7 @@ <string name="controls_error_generic" msgid="352500456918362905">"Status otillgänglig"</string> <string name="controls_error_failed" msgid="960228639198558525">"Fel, försök igen"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Lägg till snabbkontroller"</string> - <string name="controls_menu_edit" msgid="890623986951347062">"Redigera snabbkontroller"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"Redigera kontroller"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Lägg till app"</string> <string name="controls_menu_remove" msgid="3006525275966023468">"Ta bort app"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Lägg till utgångar"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Jobbprincipen tillåter endast att du ringer telefonsamtal från jobbprofilen"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Byt till jobbprofilen"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Stäng"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Inställningar för låsskärm"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi är inte tillgängligt"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameran är blockerad"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameran och mikrofonen är blockerade"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index a3cd09818ead..6f1fd67ee640 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Anza kurekodi"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Acha kurekodi"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Hali ya kutumia kwa mkono mmoja"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Utofautishaji"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Kawaida"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Wastani"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Juu"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Ungependa kuwacha kuzuia maikrofoni ya kifaa?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Ungependa kuwacha kuzuia kamera ya kifaa?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Ungependa kuwacha kuzuia kamera na maikrofoni ya kifaa?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"zima"</string> <string name="sound_settings" msgid="8874581353127418308">"Sauti na mtetemo"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Mipangilio"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Sauti imepunguzwa kuwa kiwango salama"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Sauti imekuwa juu kwa muda mrefu kuliko inavyopendekezwa"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Programu imebandikwa"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Nyuma na Muhtasari ili ubandue."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kitufe cha kurudisha Nyuma na cha Mwanzo kwa pamoja ili ubandue."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Umeondoa vidhibiti vyote"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Mabadiliko hayajahifadhiwa"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Angalia programu zingine"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Panga upya"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Weka vidhibiti"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Rudi kwenye ukurasa wa kubadilisha"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Imeshindwa kupakia vidhibiti. Angalia programu ya <xliff:g id="APP">%s</xliff:g> ili uhakikishe kuwa mipangilio yake haijabadilika."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Vidhibiti vinavyooana havipatikani"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Nyingine"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Sera ya mahali pako pa kazi inakuruhusu upige simu kutoka kwenye wasifu wa kazini pekee"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Tumia wasifu wa kazini"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Funga"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Mipangilio ya skrini iliyofungwa"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi haipatikani"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera imezuiwa"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera na maikrofoni zimezuiwa"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 41a77433e3d7..21b7f3387bbe 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"தொடங்கு"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"நிறுத்து"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ஒற்றைக் கைப் பயன்முறை"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"சாதனத்தின் மைக்ரோஃபோனுக்கான தடுப்பை நீக்கவா?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"சாதனத்தின் கேமராவுக்கான தடுப்பை நீக்கவா?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"சாதனத்தின் கேமராவுக்கும் மைக்ரோஃபோனுக்குமான தடுப்பை நீக்கவா?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"முடக்கும்"</string> <string name="sound_settings" msgid="8874581353127418308">"ஒலி & அதிர்வு"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"அமைப்புகள்"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"பாதுகாப்பான ஒலியளவிற்குக் குறைக்கப்பட்டது"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"பரிந்துரைக்கப்பட்டதை விட ஒலியளவு அதிகமாக உள்ளது"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ஆப்ஸ் பின் செய்யப்பட்டது"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்பு பட்டன்களைத் தொட்டுப் பிடிக்கவும்."</string> @@ -852,8 +858,7 @@ <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_fullscreen" msgid="5043514702759201964">"முழுத்திரை"</string> <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> @@ -1124,7 +1129,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"உங்கள் பணிக் கொள்கையின்படி நீங்கள் பணிக் கணக்கில் இருந்து மட்டுமே ஃபோன் அழைப்புகளைச் செய்ய முடியும்"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"பணிக் கணக்கிற்கு மாறு"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"மூடுக"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"பூட்டுத் திரை அமைப்புகள்"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"வைஃபை கிடைக்கவில்லை"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"கேமரா தடுக்கப்பட்டுள்ளது"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"கேமராவும் மைக்ரோஃபோனும் தடுக்கப்பட்டுள்ளன"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index fa549b817884..0c0949343811 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ప్రారంభించండి"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ఆపు"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"వన్-హ్యాండెడ్ మోడ్"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"కాంట్రాస్ట్"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"స్టాండర్డ్"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"మధ్యస్థం"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"అధికం"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"పరికరం మైక్రోఫోన్ను అన్బ్లాక్ చేయమంటారా?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"పరికరంలోని కెమెరాను అన్బ్లాక్ చేయమంటారా?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"పరికరంలోని కెమెరా, మైక్రోఫోన్లను అన్బ్లాక్ చేయమంటారా?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"నిలిపివేయండి"</string> <string name="sound_settings" msgid="8874581353127418308">"సౌండ్ & వైబ్రేషన్"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"సెట్టింగ్లు"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"సురక్షితమైన వాల్యూమ్కు తగ్గించబడింది"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"సిఫార్సు చేసిన దానికంటే ఎక్కువ కాలం వాల్యూమ్ ఎక్కువగా ఉంది"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"యాప్ పిన్ చేయబడి ఉంది"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"దీని వలన మీరు అన్పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టి తాకి & అలాగే పట్టుకోండి."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"దీని వలన మీరు అన్పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్పిన్ చేయడానికి వెనుకకు మరియు హోమ్ని తాకి & అలాగే పట్టుకోండి."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"అన్ని కంట్రోల్స్ తీసివేయబడ్డాయి"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"మార్పులు సేవ్ చేయబడలేదు"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"ఇతర యాప్లను చూడండి"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"తిరిగి అమర్చండి"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"కంట్రోల్స్ను జోడించండి"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ఎడిటింగ్కు తిరిగి వెళ్లండి"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"కంట్రోల్లను లోడ్ చేయడం సాధ్యపడలేదు. యాప్ సెట్టింగ్లు మారలేదని నిర్ధారించడానికి <xliff:g id="APP">%s</xliff:g> యాప్ను చెక్ చేయండి."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"అనుకూల కంట్రోల్లు అందుబాటులో లేవు"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ఇతరం"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"మీ వర్క్ పాలసీ, మిమ్మల్ని వర్క్ ప్రొఫైల్ నుండి మాత్రమే ఫోన్ కాల్స్ చేయడానికి అనుమతిస్తుంది"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"వర్క్ ప్రొఫైల్కు మారండి"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"మూసివేయండి"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"లాక్ స్క్రీన్ సెట్టింగ్లు"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi అందుబాటులో లేదు"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"కెమెరా బ్లాక్ చేయబడింది"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"కెమెరా, మైక్రోఫోన్ బ్లాక్ చేయబడ్డాయి"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 110b62aede94..ed8db9c23be1 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"เริ่ม"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"หยุด"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"โหมดมือเดียว"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"คอนทราสต์"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"มาตรฐาน"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ปานกลาง"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"สูง"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"เลิกบล็อกไมโครโฟนของอุปกรณ์ใช่ไหม"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"เลิกบล็อกกล้องของอุปกรณ์ใช่ไหม"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"เลิกบล็อกกล้องและไมโครโฟนของอุปกรณ์ใช่ไหม"</string> @@ -452,16 +456,14 @@ <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g> <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string> <string name="accessibility_volume_settings" msgid="1458961116951564784">"การตั้งค่าเสียง"</string> <string name="volume_odi_captions_tip" msgid="8825655463280990941">"แสดงคำบรรยายสื่อโดยอัตโนมัติ"</string> - <string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"เคล็ดลับเกี่ยวกับคำอธิบายภาพ"</string> - <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"การวางซ้อนคำบรรยายภาพ"</string> + <string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"เคล็ดลับเกี่ยวกับคำบรรยายแทนเสียง"</string> + <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"การวางซ้อนคำบรรยายแทนเสียง"</string> <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"เปิดใช้"</string> <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ปิดใช้"</string> <string name="sound_settings" msgid="8874581353127418308">"เสียงและการสั่น"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"การตั้งค่า"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"ลดเสียงลงไประดับที่ปลอดภัยขึ้นแล้ว"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"เสียงอยู่ในระดับที่ดังเป็นระยะเวลานานกว่าที่แนะนำ"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ปักหมุดแอปอยู่"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้เพื่อเลิกปักหมุด"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"กลับ\" และ \"หน้าแรก\" ค้างไว้เพื่อเลิกปักหมุด"</string> @@ -875,7 +877,7 @@ <string name="controls_removed" msgid="3731789252222856959">"นำออกแล้ว"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"เพิ่ม <xliff:g id="APPNAME">%s</xliff:g> ไหม"</string> <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="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> <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"นำออกจากรายการโปรดแล้ว"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"นำตัวควบคุมทั้งหมดออกแล้ว"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ยังไม่ได้บันทึกการเปลี่ยนแปลง"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"ดูแอปอื่นๆ"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"จัดเรียงใหม่"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"เพิ่มตัวควบคุม"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"กลับไปที่การแก้ไข"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"โหลดตัวควบคุมไม่ได้ ตรวจสอบแอป <xliff:g id="APP">%s</xliff:g> ให้แน่ใจว่าการตั้งค่าของแอปไม่เปลี่ยนแปลง"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"ตัวควบคุมที่เข้ากันได้ไม่พร้อมใช้งาน"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"อื่นๆ"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"นโยบายการทำงานอนุญาตให้คุณโทรออกได้จากโปรไฟล์งานเท่านั้น"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"สลับไปใช้โปรไฟล์งาน"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ปิด"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"การตั้งค่าหน้าจอล็อก"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ไม่พร้อมใช้งาน"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"กล้องถูกบล็อกอยู่"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"กล้องและไมโครโฟนถูกบล็อกอยู่"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 285b865e6789..ceee6062e961 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Magsimula"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ihinto"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-hand mode"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Katamtaman"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Mataas"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"I-unblock ang mikropono ng device?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"I-unblock ang camera ng device?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"I-unblock ang camera at mikropono ng device?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"i-disable"</string> <string name="sound_settings" msgid="8874581353127418308">"Tunog at pag-vibrate"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Mga Setting"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Hininaan sa mas ligtas na volume"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Naging malakas ang volume nang mas matagal sa inirerekomenda"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Naka-pin ang app"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Overview upang mag-unpin."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Home upang mag-unpin."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Inalis ang lahat ng kontrol"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Hindi na-save ang mga pagbabago"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Tingnan ang iba pang app"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Ayusin ulit"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Magdagdag ng mga kontrol"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Bumalik sa pag-edit"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Hindi ma-load ang mga kontrol. Tingnan ang app na <xliff:g id="APP">%s</xliff:g> para matiyak na hindi nabago ang mga setting ng app."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Hindi available ang mga compatible na kontrol"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iba pa"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Pinapayagan ka ng iyong patakaran sa trabaho na tumawag lang mula sa profile sa trabaho"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Lumipat sa profile sa trabaho"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Isara"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Mga setting ng lock screen"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Hindi available ang Wi-Fi"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Naka-block ang camera"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Naka-block ang camera at mikropono"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index f82194d72660..1fde899026f7 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlat"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Durdur"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tek el modu"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standart"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Orta"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yüksek"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonunun engellemesi kaldırılsın mı?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerasının engellemesi kaldırılsın mı?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası ile mikrofonunun engellemesi kaldırılsın mı?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"devre dışı bırak"</string> <string name="sound_settings" msgid="8874581353127418308">"Ses ve titreşim"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ayarlar"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Ses, sağlık açısından daha güvenli bir seviyeye düşürüldü"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Ses, önerilenden daha uzun süredir yüksek seviyede"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Uygulama sabitlendi"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Genel Bakış\'a dokunup basılı tutun."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Ana sayfaya dokunup basılı tutun."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Tüm denetimler kaldırıldı"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Değişiklikler kaydedilmedi"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Tüm uygulamaları göster"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Yeniden düzenle"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Kontrol ekle"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Düzenlemeye dön"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Kontroller yüklenemedi. Uygulama ayarlarının değişmediğinden emin olmak için <xliff:g id="APP">%s</xliff:g> uygulamasını kontrol edin."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Uyumlu kontrol bulunamadı"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Diğer"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"İşletme politikanız yalnızca iş profilinden telefon araması yapmanıza izin veriyor"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"İş profiline geç"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Kapat"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Kilit ekranı ayarları"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Kablosuz bağlantı kullanılamıyor"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera engellendi"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ve mikrofon engellendi"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 62e1ec6493ab..d61f52efcf6b 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почати"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зупинити"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим керування однією рукою"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Надати доступ до мікрофона?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Надати доступ до камери пристрою?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Надати доступ до камери й мікрофона?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"вимкнути"</string> <string name="sound_settings" msgid="8874581353127418308">"Звук і вібрація"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Налаштування"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Гучність знижено до безпечнішого рівня"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Аудіо відтворювалося з високою гучністю довше, ніж рекомендується"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Додаток закріплено"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\"."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ви бачитимете цей екран, доки не відкріпите його. Для цього натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\"."</string> @@ -481,7 +487,7 @@ <string name="stream_system" msgid="7663148785370565134">"Система"</string> <string name="stream_ring" msgid="7550670036738697526">"Дзвінок"</string> <string name="stream_music" msgid="2188224742361847580">"Медіа"</string> - <string name="stream_alarm" msgid="16058075093011694">"Сигнал"</string> + <string name="stream_alarm" msgid="16058075093011694">"Будильник"</string> <string name="stream_notification" msgid="7930294049046243939">"Сповіщення"</string> <string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth"</string> <string name="stream_dtmf" msgid="7322536356554673067">"Двотональний багаточастотний аналоговий сигнал"</string> @@ -506,7 +512,7 @@ <string name="enable_demo_mode" msgid="3180345364745966431">"Увімкнути демонстраційний режим"</string> <string name="show_demo_mode" msgid="3677956462273059726">"Показати демонстраційний режим"</string> <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string> - <string name="status_bar_alarm" msgid="87160847643623352">"Сигнал"</string> + <string name="status_bar_alarm" msgid="87160847643623352">"Будильник"</string> <string name="wallet_title" msgid="5369767670735827105">"Гаманець"</string> <string name="wallet_empty_state_label" msgid="7776761245237530394">"Швидше й безпечніше сплачуйте за покупки за допомогою телефона"</string> <string name="wallet_app_button_label" msgid="7123784239111190992">"Показати все"</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Усі елементи керування вилучено"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Зміни не збережено"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Переглянути інші додатки"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Упорядкувати"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Додати елементи керування"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Повернутися до редагування"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Не вдалося завантажити елементи керування. Перевірте в додатку <xliff:g id="APP">%s</xliff:g>, чи його налаштування не змінились."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Сумісні елементи керування недоступні"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Інше"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Відповідно до правил організації ви можете телефонувати лише з робочого профілю"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Перейти в робочий профіль"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрити"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Параметри заблокованого екрана"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Мережа Wi-Fi недоступна"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камеру заблоковано"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камеру й мікрофон заблоковано"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index c2bbe9dfc2ab..8a869dddbdb7 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع کریں"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"روکیں"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ایک ہاتھ کی وضع"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"کنٹراسٹ"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"معیاری"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"متوسط"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"زیادہ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"آلے کا مائیکروفون غیر مسدود کریں؟"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"آلے کا کیمرا غیر مسدود کریں؟"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"آلے کا کیمرا اور مائیکروفون غیر مسدود کریں؟"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"غیر فعال کریں"</string> <string name="sound_settings" msgid="8874581353127418308">"آواز اور وائبریشن"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ترتیبات"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"محفوظ والیوم تک کم کر دیا گیا"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"والیوم تجویز کردہ مدت سے زیادہ بلند رہا ہے"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"ایپ کو پن کر دیا گیا ہے"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"اس سے یہ اس وقت تک منظر میں رہتی ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ کے بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"اس سے یہ اس وقت تک منظر میں رہتی ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"پیچھے\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string> @@ -875,7 +877,7 @@ <string name="controls_removed" msgid="3731789252222856959">"ہٹا دیا گیا"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> کو شامل کریں؟"</string> <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="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> <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ناپسند کردہ"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"سبھی کنٹرولز ہٹا دیے گئے"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"تبدیلیاں محفوظ نہیں ہوئیں"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"دیگر ایپس دیکھیں"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"دوبارہ ترتیب دیں"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"کنٹرولز شامل کریں"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"ترمیم پر واپس جائیں"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"کنٹرولز کو لوڈ نہیں کیا جا سکا۔ یہ یقینی بنانے کے لیے <xliff:g id="APP">%s</xliff:g> ایپ کو چیک کریں کہ ایپ کی ترتیبات تبدیل نہیں ہوئی ہیں۔"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"موافق کنٹرولز دستیاب نہیں ہیں"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"دیگر"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"آپ کے کام سے متعلق پالیسی آپ کو صرف دفتری پروفائل سے فون کالز کرنے کی اجازت دیتی ہے"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"دفتری پروفائل پر سوئچ کریں"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"بند کریں"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"مقفل اسکرین کی ترتیبات"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi دستیاب نہیں ہے"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"کیمرا مسدود ہے"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"کیمرا اور مائیکروفون مسدود ہے"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index fb20f8b7ceeb..73d40beed2c9 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Boshlash"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Toʻxtatish"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ixcham rejim"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standart"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Oʻrtacha"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yuqori"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Qurilma mikrofoni blokdan chiqarilsinmi?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Qurilma kamerasi blokdan chiqarilsinmi?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Qurilma kamerasi va mikrofoni blokdan chiqarilsinmi?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"faolsizlantirish"</string> <string name="sound_settings" msgid="8874581353127418308">"Tovush va tebranish"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Sozlamalar"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Tovush balandligi xavfsiz darajaga tushirildi"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Tovush tavsiya qilinganidan koʻra uzoqroq vaqt baland boʻldi"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Ilova mahkamlandi"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran yechib olinmagunicha u mahkamlangan holatda qoladi. Uni yechish uchun Orqaga va Asosiy tugmalarni birga bosib turing."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Barcha boshqaruv elementlari olib tashlandi"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Oʻzgarishlar saqlanmadi"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Boshqa ilovalar"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Qayta tartiblash"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Tugma kiritish"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Tahrirlashga qaytish"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Boshqaruvlar yuklanmadi. <xliff:g id="APP">%s</xliff:g> ilovasining sozlamalari oʻzgarmaganini tekshiring."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Mos boshqaruv elementlari mavjud emas"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Boshqa"</string> @@ -951,7 +950,7 @@ <string name="controls_error_generic" msgid="352500456918362905">"Holat axboroti yuklanmadi"</string> <string name="controls_error_failed" msgid="960228639198558525">"Xato, qayta urining"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Element kiritish"</string> - <string name="controls_menu_edit" msgid="890623986951347062">"Elementlarni tahrirlash"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"Boshqaruvni tahrirlash"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Ilova kiritish"</string> <string name="controls_menu_remove" msgid="3006525275966023468">"Ilovani olib tashlash"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Chiquvchi qurilmani kiritish"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Ishga oid siyosatingiz faqat ish profilidan telefon chaqiruvlarini amalga oshirish imkonini beradi"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Ish profiliga almashish"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Yopish"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Qulflangan ekran sozlamalari"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi mavjud emas"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera bloklangan"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera va mikrofon bloklangan"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 0f2ebf65a51d..ea599888d47a 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Bắt đầu"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Dừng"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Chế độ một tay"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Độ tương phản"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Chuẩn"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Vừa"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Cao"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Bỏ chặn micrô của thiết bị?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Bỏ chặn máy ảnh của thiết bị?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Bỏ chặn máy ảnh và micrô của thiết bị?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"tắt"</string> <string name="sound_settings" msgid="8874581353127418308">"Âm thanh và chế độ rung"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Cài đặt"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Đã giảm âm lượng xuống mức an toàn hơn"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Âm lượng ở mức cao trong khoảng thời gian lâu hơn khuyến nghị"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"Đã ghim ứng dụng"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string> @@ -852,8 +854,7 @@ <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_fullscreen" msgid="5043514702759201964">"Toàn màn hình"</string> <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> @@ -876,7 +877,7 @@ <string name="controls_removed" msgid="3731789252222856959">"Đã xóa"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Thêm <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> có thể chọn các nút điều khiển và nội dung hiện ở đây."</string> - <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Xoá chế độ cài đặt cho <xliff:g id="APPNAME">%s</xliff:g>?"</string> + <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Xoá chế độ điều khiển cho <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Được yêu thích"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Được yêu thích, vị trí số <xliff:g id="NUMBER">%d</xliff:g>"</string> <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Không được yêu thích"</string> @@ -889,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Đã xóa tất cả tùy chọn điều khiển"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Chưa lưu các thay đổi"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Xem ứng dụng khác"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Sắp xếp lại"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Thêm chế độ điều khiển"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Quay lại chế độ chỉnh sửa"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Không tải được các chức năng điều khiển. Hãy kiểm tra ứng dụng <xliff:g id="APP">%s</xliff:g> để đảm bảo rằng thông tin cài đặt của ứng dụng chưa thay đổi."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Không có các chức năng điều khiển tương thích"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Khác"</string> @@ -952,7 +950,7 @@ <string name="controls_error_generic" msgid="352500456918362905">"Không tải được trạng thái"</string> <string name="controls_error_failed" msgid="960228639198558525">"Lỗi, hãy thử lại"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Thêm các tùy chọn điều khiển"</string> - <string name="controls_menu_edit" msgid="890623986951347062">"Chỉnh sửa tùy chọn điều khiển"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"Chỉnh sửa chế độ điều khiển"</string> <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Thêm ứng dụng"</string> <string name="controls_menu_remove" msgid="3006525275966023468">"Xoá ứng dụng"</string> <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Thêm thiết bị đầu ra"</string> @@ -1124,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Chính sách của nơi làm việc chỉ cho phép bạn gọi điện thoại từ hồ sơ công việc"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Chuyển sang hồ sơ công việc"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Đóng"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Cài đặt màn hình khoá"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Không có Wi-Fi"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Máy ảnh bị chặn"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Máy ảnh và micrô bị chặn"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 571ee95bbd13..84c6441faa59 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"开始"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"单手模式"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"对比度"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"标准"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解锁设备麦克风吗?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解锁设备摄像头吗?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解锁设备摄像头和麦克风吗?"</string> @@ -456,12 +460,10 @@ <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕重叠显示"</string> <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"启用"</string> <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string> - <string name="sound_settings" msgid="8874581353127418308">"提示音和振动"</string> + <string name="sound_settings" msgid="8874581353127418308">"声音和振动"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"设置"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"已降低至较安全的音量"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"音量保持较高的时间超过了建议时长"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"应用已固定"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“概览”即可取消固定屏幕。"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“主屏幕”即可取消固定屏幕。"</string> @@ -875,7 +877,7 @@ <string name="controls_removed" msgid="3731789252222856959">"已移除"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"添加“<xliff:g id="APPNAME">%s</xliff:g>”?"</string> <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="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> <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"已取消收藏"</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"已移除所有控制器"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"未保存更改"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"查看其他应用"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"重新排列"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"添加控件"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"返回以继续修改"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"无法加载控件。请查看<xliff:g id="APP">%s</xliff:g>应用,确保应用设置没有更改。"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"找不到兼容的控件"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"根据您的工作政策,您只能通过工作资料拨打电话"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"切换到工作资料"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"关闭"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"锁屏设置"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"没有 WLAN 连接"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"已禁用摄像头"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已禁用摄像头和麦克风"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 8df1c3df94cc..aceae5e3cdf3 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解除封鎖裝置相機和麥克風嗎?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string> <string name="sound_settings" msgid="8874581353127418308">"音效和震動"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"已調低至較安全的音量"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"使用高音量已超過建議的時間"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"已固定應用程式"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"應用程式將會固定在螢幕上顯示,直至您取消固定為止。按住「返回」和「概覽」按鈕即可取消固定。"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"應用程式將會固定在螢幕上顯示,直至您取消固定為止。按住「返回」按鈕和主按鈕即可取消固定。"</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"已移除所有控制項"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"未儲存變更"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"查看其他應用程式"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"重新排列"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"新增控制項"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"繼續編輯"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"無法載入控制項。請檢查 <xliff:g id="APP">%s</xliff:g> 應用程式,確保設定沒有變動。"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"沒有兼容的控制項"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"您的公司政策只允許透過工作設定檔撥打電話"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"切換至工作設定檔"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"關閉"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"上鎖畫面設定"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"無法連線至 Wi-Fi"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"已封鎖相機"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已封鎖相機和麥克風"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index a25fc44ed60b..11e56a2b752e 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -299,6 +299,14 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string> + <!-- no translation found for quick_settings_contrast_label (988087460210159123) --> + <skip /> + <!-- no translation found for quick_settings_contrast_standard (2538227821968061832) --> + <skip /> + <!-- no translation found for quick_settings_contrast_medium (5158352575583902566) --> + <skip /> + <!-- no translation found for quick_settings_contrast_high (656049259587494499) --> + <skip /> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要將裝置麥克風解除封鎖嗎?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要將裝置相機解除封鎖嗎?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要將裝置的相機和麥克風解除封鎖嗎?"</string> @@ -458,10 +466,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string> <string name="sound_settings" msgid="8874581353127418308">"音效與震動"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"已調低至較安全的音量"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"已超過建議的高音量時間"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"應用程式已固定"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住 [返回] 按鈕和主畫面按鈕即可取消固定。"</string> @@ -875,7 +881,7 @@ <string name="controls_removed" msgid="3731789252222856959">"已移除"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"要新增「<xliff:g id="APPNAME">%s</xliff:g>」嗎?"</string> <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="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> <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"從收藏中移除"</string> @@ -888,12 +894,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"所有控制項都已移除"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"未儲存變更"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"查看其他應用程式"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"重新排列"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"新增控制選項"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"繼續編輯"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"無法載入控制項。請查看「<xliff:g id="APP">%s</xliff:g>」應用程式,確認應用程式設定沒有任何異動。"</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"找不到相容的控制項"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string> @@ -960,7 +963,7 @@ <string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 部裝置"</string> <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(連線中斷)"</string> <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"無法切換,輕觸即可重試。"</string> - <string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"建立裝置連線"</string> + <string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"連接裝置"</string> <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如要投放這個工作階段,請開啟應用程式。"</string> <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明的應用程式"</string> <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string> @@ -1123,7 +1126,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"貴公司政策僅允許透過工作資料夾撥打電話"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"切換至工作資料夾"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"關閉"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"螢幕鎖定設定"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"無法連上 Wi-Fi"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"已封鎖攝影機"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已封鎖攝影機和麥克風"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 59884dbce7e5..7417a85079f4 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -299,6 +299,10 @@ <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Qala"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Misa"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Imodi yesandla esisodwa"</string> + <string name="quick_settings_contrast_label" msgid="988087460210159123">"Ukugqama"</string> + <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Okujwayelekile"</string> + <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Okuphakathi"</string> + <string name="quick_settings_contrast_high" msgid="656049259587494499">"Phezulu"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vulela imakrofoni yedivayisi?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vulela ikhamera yedivayisi?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vulela ikhamera yedivayisi nemakrofoni?"</string> @@ -458,10 +462,8 @@ <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"khubaza"</string> <string name="sound_settings" msgid="8874581353127418308">"Umsindo nokudlidliza"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Amasethingi"</string> - <!-- no translation found for csd_lowered_title (1786173629015030856) --> - <skip /> - <!-- no translation found for csd_system_lowered_text (2001603282316829500) --> - <skip /> + <string name="csd_lowered_title" product="default" msgid="1786173629015030856">"Yehliselwe kuvolumu ephephile"</string> + <string name="csd_system_lowered_text" product="default" msgid="2001603282316829500">"Ivolumu beyiphezulu isikhathi eside kunokunconyiwe"</string> <string name="screen_pinning_title" msgid="9058007390337841305">"I-app iphiniwe"</string> <string name="screen_pinning_description" msgid="8699395373875667743">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe okuthi Emuva Nokubuka konke ukuze ususe ukuphina."</string> <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Lokhu kuyigcina ibonakala uze uyisuse. Thinta uphinde ubambe okuthi Emuva nokuthi Ekhaya ukuze ususe ukuphina."</string> @@ -888,12 +890,9 @@ <string name="controls_favorite_removed" msgid="5276978408529217272">"Zonke izilawuli zisusiwe"</string> <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Izinguquko azilondolozwanga"</string> <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Bona ezinye izinhlelo zokusebenza"</string> - <!-- no translation found for controls_favorite_rearrange_button (2942788904364641185) --> - <skip /> - <!-- no translation found for controls_favorite_add_controls (1221420435546694004) --> - <skip /> - <!-- no translation found for controls_favorite_back_to_editing (184125114090062713) --> - <skip /> + <string name="controls_favorite_rearrange_button" msgid="2942788904364641185">"Hlela kabusha"</string> + <string name="controls_favorite_add_controls" msgid="1221420435546694004">"Engeza Izilawuli"</string> + <string name="controls_favorite_back_to_editing" msgid="184125114090062713">"Buyela emuva ekuhleleni"</string> <string name="controls_favorite_load_error" msgid="5126216176144877419">"Izilawuli azikwazanga ukulayishwa. Hlola uhlelo lokusebenza le-<xliff:g id="APP">%s</xliff:g> ukuqinisekisa ukuthi amasethingi wohlelo lokusebenza awashintshile."</string> <string name="controls_favorite_load_none" msgid="7687593026725357775">"Izilawuli ezihambelanayo azitholakali"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Okunye"</string> @@ -1123,7 +1122,8 @@ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Inqubomgomo yakho yomsebenzi ikuvumela ukuthi wenze amakholi wefoni kuphela ngephrofayela yomsebenzi"</string> <string name="call_from_work_profile_action" msgid="2937701298133010724">"Shintshela kuphrofayela yomsebenzi"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Vala"</string> - <string name="lock_screen_settings" msgid="9197175446592718435">"Amasethingi okukhiya isikrini"</string> + <!-- no translation found for lock_screen_settings (6152703934761402399) --> + <skip /> <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"I-Wi-Fi ayitholakali"</string> <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ikhamera ivinjiwe"</string> <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ikhamera nemakrofoni zivinjiwe"</string> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 96e6d4e1a234..cb8c2a73c15d 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -231,9 +231,6 @@ <color name="people_tile_background">@color/material_dynamic_secondary95</color> - <!-- Chipbar --> - <color name="chipbar_text_and_icon_color">@android:color/system_accent2_900</color> - <!-- Internet Dialog --> <!-- Material next state on color--> <color name="settingslib_state_on_color">@color/settingslib_state_on</color> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 714d495af762..9cb8aa0142bf 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1110,6 +1110,7 @@ <!-- Chipbar --> <!-- (Used for media tap-to-transfer chip for sender device and active unlock) --> <dimen name="chipbar_outer_padding">16dp</dimen> + <dimen name="chipbar_outer_padding_half">8dp</dimen> <dimen name="chipbar_text_size">16sp</dimen> <dimen name="chipbar_start_icon_size">24dp</dimen> <dimen name="chipbar_end_icon_size">20dp</dimen> @@ -1198,19 +1199,17 @@ <dimen name="controls_top_margin">48dp</dimen> <dimen name="controls_content_margin_horizontal">0dp</dimen> <dimen name="control_header_text_size">24sp</dimen> - <dimen name="control_item_text_size">16sp</dimen> + <dimen name="control_item_text_size">14sp</dimen> <dimen name="control_menu_item_text_size">16sp</dimen> - <dimen name="control_menu_item_min_height">56dp</dimen> + <dimen name="control_menu_item_height">54dp</dimen> <dimen name="control_menu_vertical_padding">12dp</dimen> - <dimen name="control_menu_horizontal_padding">16dp</dimen> - <dimen name="control_popup_item_corner_radius">4dp</dimen> - <dimen name="control_popup_item_height">56dp</dimen> - <dimen name="control_popup_item_padding">16dp</dimen> - <dimen name="control_popup_items_divider_height">1dp</dimen> + <dimen name="control_menu_horizontal_padding">@dimen/notification_side_paddings</dimen> + <dimen name="control_apps_popup_item_height">56dp</dimen> + <dimen name="control_popup_item_corner_radius">@dimen/notification_corner_radius_small</dimen> + <dimen name="control_popup_items_divider_height">@dimen/controls_app_divider_height</dimen> <dimen name="control_popup_max_width">380dp</dimen> - <dimen name="control_popup_corner_radius">28dp</dimen> + <dimen name="control_popup_corner_radius">@dimen/notification_corner_radius</dimen> <dimen name="control_popup_horizontal_margin">16dp</dimen> - <dimen name="control_spinner_padding_vertical">24dp</dimen> <dimen name="control_spinner_padding_horizontal">20dp</dimen> <dimen name="control_text_size">14sp</dimen> <dimen name="control_icon_size">24dp</dimen> @@ -1774,13 +1773,6 @@ <dimen name="rear_display_title_top_padding">24dp</dimen> <dimen name="rear_display_title_bottom_padding">16dp</dimen> - <!-- - Vertical distance between the pointer and the popup menu that shows up on the lock screen when - it is long-pressed. - --> - <dimen name="keyguard_long_press_settings_popup_vertical_offset">96dp</dimen> - - <!-- Bouncer user switcher margins --> <dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">0dp</dimen> <dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">0dp</dimen> diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml index befbfab7dbc3..675ae326b5a2 100644 --- a/packages/SystemUI/res/values/integers.xml +++ b/packages/SystemUI/res/values/integers.xml @@ -36,7 +36,7 @@ fade_out_complete_frame --> <dimen name="percent_displacement_at_fade_out" format="float">0.1066</dimen> - <integer name="qs_carrier_max_em">7</integer> + <integer name="shade_carrier_max_em">7</integer> <!-- Maximum number of notification icons shown on the Always on Display (excluding overflow dot) --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index f1777f84cd6d..26502f1c1752 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3057,13 +3057,20 @@ <string name="call_from_work_profile_close">Close</string> <!-- - Label for a menu item in a menu that is shown when the user wishes to configure the lock screen. + Label for a menu item in a menu that is shown when the user wishes to customize the lock screen. Clicking on this menu item takes the user to a screen where they can modify the settings of the lock screen. + It is critical that this text is as short as possible. If needed, translators should feel free + to drop "lock screen" from their translation and keep just "Customize" or "Customization", in + cases when that verb is not available in their target language. + [CHAR LIMIT=32] --> - <string name="lock_screen_settings">Lock screen settings</string> + <string name="lock_screen_settings">Customize lock screen</string> + + <!-- Title of security view when we want to authenticate before customizing the lockscreen. [CHAR LIMIT=NONE] --> + <string name="keyguard_unlock_to_customize_ls">Unlock to customize lock screen</string> <!-- Content description for Wi-Fi not available icon on dream [CHAR LIMIT=NONE]--> <string name="wifi_unavailable_dream_overlay_content_description">Wi-Fi not available</string> @@ -3082,4 +3089,7 @@ <!-- Content description for when assistant attention is active [CHAR LIMIT=NONE] --> <string name="assistant_attention_content_description">Assistant attention on</string> + + <!--- Content of toast triggered when the notes app entry point is triggered without setting a default notes app. [CHAR LIMIT=NONE] --> + <string name="set_default_notes_app_toast_content">Set default notes app in Settings</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 064cea112b5a..9d0cc11c93c2 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -70,6 +70,15 @@ <item name="android:fontWeight">700</item> </style> + <style name="Chipbar" /> + + <style name="Chipbar.Text" parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title"> + <!-- Text size should be kept in sync with the notification conversation header size. (The + conversation header doesn't have a defined style, so the size must be copied here.) + See notification_template_conversation_header.xml. --> + <item name="android:textSize">16sp</item> + </style> + <style name="TextAppearance" /> <style name="TextAppearance.QS"> @@ -886,7 +895,7 @@ <item name="android:textColor">@color/control_primary_text</item> <item name="android:singleLine">true</item> <item name="android:gravity">center_vertical</item> - <item name="android:minHeight">@dimen/control_menu_item_min_height</item> + <item name="android:minHeight">@dimen/control_menu_item_height</item> </style> <style name="Control.Spinner"> @@ -1399,4 +1408,9 @@ <style name="ShortcutItemBackground"> <item name="android:background">@color/ksh_key_item_new_background</item> </style> + + <style name="LongPressLockScreenAnimation"> + <item name="android:windowEnterAnimation">@anim/long_press_lock_screen_popup_enter</item> + <item name="android:windowExitAnimation">@anim/long_press_lock_screen_popup_exit</item> + </style> </resources> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 4d7d0ea264a4..3c447a8eb6d8 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -124,6 +124,8 @@ public class QuickStepContract { public static final int SYSUI_STATE_WAKEFULNESS_TRANSITION = 1 << 29; // The notification panel expansion fraction is > 0 public static final int SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE = 1 << 30; + // When keyguard will be dismissed but didn't start animation yet + public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY = 1 << 31; // Mask for SystemUiStateFlags to isolate SYSUI_STATE_AWAKE and // SYSUI_STATE_WAKEFULNESS_TRANSITION, to match WAKEFULNESS_* constants @@ -172,6 +174,7 @@ public class QuickStepContract { SYSUI_STATE_AWAKE, SYSUI_STATE_WAKEFULNESS_TRANSITION, SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, + SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY, }) public @interface SystemUiStateFlags {} @@ -270,6 +273,9 @@ public class QuickStepContract { if ((flags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0) { str.add("notif_visible"); } + if ((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY) != 0) { + str.add("keygrd_going_away"); + } return str.toString(); } diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java index 7971e84769a2..b15378570358 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java @@ -21,7 +21,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.net.wifi.WifiManager; +import android.os.Trace; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener; @@ -37,6 +37,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository; import com.android.systemui.telephony.TelephonyListenerManager; import java.util.List; @@ -50,7 +51,10 @@ import javax.inject.Inject; * Controller that generates text including the carrier names and/or the status of all the SIM * interfaces in the device. Through a callback, the updates can be retrieved either as a list or * separated by a given separator {@link CharSequence}. + * + * @deprecated use {@link com.android.systemui.statusbar.pipeline.wifi} instead */ +@Deprecated public class CarrierTextManager { private static final boolean DEBUG = KeyguardConstants.DEBUG; private static final String TAG = "CarrierTextController"; @@ -64,7 +68,7 @@ public class CarrierTextManager { private final AtomicBoolean mNetworkSupported = new AtomicBoolean(); @VisibleForTesting protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; - private final WifiManager mWifiManager; + private final WifiRepository mWifiRepository; private final boolean[] mSimErrorState; private final int mSimSlotsNumber; @Nullable // Check for nullability before dispatching @@ -165,7 +169,7 @@ public class CarrierTextManager { CharSequence separator, boolean showAirplaneMode, boolean showMissingSim, - @Nullable WifiManager wifiManager, + WifiRepository wifiRepository, TelephonyManager telephonyManager, TelephonyListenerManager telephonyListenerManager, WakefulnessLifecycle wakefulnessLifecycle, @@ -177,8 +181,7 @@ public class CarrierTextManager { mShowAirplaneMode = showAirplaneMode; mShowMissingSim = showMissingSim; - - mWifiManager = wifiManager; + mWifiRepository = wifiRepository; mTelephonyManager = telephonyManager; mSeparator = separator; mTelephonyListenerManager = telephonyListenerManager; @@ -297,6 +300,7 @@ public class CarrierTextManager { } protected void updateCarrierText() { + Trace.beginSection("CarrierTextManager#updateCarrierText"); boolean allSimsMissing = true; boolean anySimReadyAndInService = false; CharSequence displayText = null; @@ -329,20 +333,20 @@ public class CarrierTextManager { carrierNames[i] = carrierTextForSimState; } if (simState == TelephonyManager.SIM_STATE_READY) { + Trace.beginSection("WFC check"); ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); if (ss != null && ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) { // hack for WFC (IWLAN) not turning off immediately once // Wi-Fi is disassociated or disabled if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN - || (mWifiManager != null && mWifiManager.isWifiEnabled() - && mWifiManager.getConnectionInfo() != null - && mWifiManager.getConnectionInfo().getBSSID() != null)) { + || mWifiRepository.isWifiConnectedWithValidSsid()) { if (DEBUG) { Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss); } anySimReadyAndInService = true; } } + Trace.endSection(); } } // Only create "No SIM card" if no cards with CarrierName && no wifi when some sim is READY @@ -406,6 +410,7 @@ public class CarrierTextManager { subsIds, airplaneMode); postToCallback(info); + Trace.endSection(); } @VisibleForTesting @@ -633,7 +638,7 @@ public class CarrierTextManager { public static class Builder { private final Context mContext; private final String mSeparator; - private final WifiManager mWifiManager; + private final WifiRepository mWifiRepository; private final TelephonyManager mTelephonyManager; private final TelephonyListenerManager mTelephonyListenerManager; private final WakefulnessLifecycle mWakefulnessLifecycle; @@ -647,7 +652,7 @@ public class CarrierTextManager { public Builder( Context context, @Main Resources resources, - @Nullable WifiManager wifiManager, + @Nullable WifiRepository wifiRepository, TelephonyManager telephonyManager, TelephonyListenerManager telephonyListenerManager, WakefulnessLifecycle wakefulnessLifecycle, @@ -657,7 +662,7 @@ public class CarrierTextManager { mContext = context; mSeparator = resources.getString( com.android.internal.R.string.kg_text_message_separator); - mWifiManager = wifiManager; + mWifiRepository = wifiRepository; mTelephonyManager = telephonyManager; mTelephonyListenerManager = telephonyListenerManager; mWakefulnessLifecycle = wakefulnessLifecycle; @@ -681,7 +686,7 @@ public class CarrierTextManager { /** Create a CarrierTextManager. */ public CarrierTextManager build() { return new CarrierTextManager( - mContext, mSeparator, mShowAirplaneMode, mShowMissingSim, mWifiManager, + mContext, mSeparator, mShowAirplaneMode, mShowMissingSim, mWifiRepository, mTelephonyManager, mTelephonyListenerManager, mWakefulnessLifecycle, mMainExecutor, mBgExecutor, mKeyguardUpdateMonitor); } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 0779653430b2..7262a736c433 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -25,6 +25,7 @@ import android.graphics.Rect import android.text.format.DateFormat import android.util.TypedValue import android.view.View +import android.view.View.OnAttachStateChangeListener import android.view.ViewTreeObserver import android.widget.FrameLayout import androidx.annotation.VisibleForTesting @@ -105,6 +106,24 @@ constructor( } updateFontSizes() updateTimeListeners() + value.smallClock.view.addOnAttachStateChangeListener( + object : OnAttachStateChangeListener { + override fun onViewAttachedToWindow(p0: View?) { + value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) + } + + override fun onViewDetachedFromWindow(p0: View?) { + } + }) + value.largeClock.view.addOnAttachStateChangeListener( + object : OnAttachStateChangeListener { + override fun onViewAttachedToWindow(p0: View?) { + value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) + } + + override fun onViewDetachedFromWindow(p0: View?) { + } + }) } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 1980f70d63a4..510fcbfd8bee 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -116,7 +116,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey } @Override - public void showMessage(CharSequence message, ColorStateList colorState) { + public void showMessage(CharSequence message, ColorStateList colorState, boolean animated) { if (mMessageAreaController == null) { return; } @@ -124,7 +124,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey if (colorState != null) { mMessageAreaController.setNextMessageColor(colorState); } - mMessageAreaController.setMessage(message); + mMessageAreaController.setMessage(message, animated); } // Allow subclasses to override this behavior diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardActiveUnlockModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardActiveUnlockModel.kt index 3a89c13ddd64..40f6f48288dc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardActiveUnlockModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardActiveUnlockModel.kt @@ -17,9 +17,9 @@ package com.android.keyguard import android.annotation.CurrentTimeMillisLong +import com.android.systemui.common.buffer.RingBuffer import com.android.systemui.dump.DumpsysTableLogger import com.android.systemui.dump.Row -import com.android.systemui.plugins.util.RingBuffer /** Verbose debug information. */ data class KeyguardActiveUnlockModel( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 0326b6d3edca..5ba0ad62e9fb 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -294,11 +294,11 @@ public class KeyguardClockSwitch extends RelativeLayout { public void dump(PrintWriter pw, String[] args) { pw.println("KeyguardClockSwitch:"); - pw.println(" mSmallClockFrame: " + mSmallClockFrame); - pw.println(" mSmallClockFrame.alpha: " + mSmallClockFrame.getAlpha()); - pw.println(" mLargeClockFrame: " + mLargeClockFrame); - pw.println(" mLargeClockFrame.alpha: " + mLargeClockFrame.getAlpha()); - pw.println(" mStatusArea: " + mStatusArea); - pw.println(" mDisplayedClockSize: " + mDisplayedClockSize); + pw.println(" mSmallClockFrame = " + mSmallClockFrame); + pw.println(" mSmallClockFrame.alpha = " + mSmallClockFrame.getAlpha()); + pw.println(" mLargeClockFrame = " + mLargeClockFrame); + pw.println(" mLargeClockFrame.alpha = " + mLargeClockFrame.getAlpha()); + pw.println(" mStatusArea = " + mStatusArea); + pw.println(" mDisplayedClockSize = " + mDisplayedClockSize); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 9290220b8698..ad333b7bfbb6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -109,7 +109,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS private final ContentObserver mShowWeatherObserver = new ContentObserver(null) { @Override public void onChange(boolean change) { - setDateWeatherVisibility(); + setWeatherVisibility(); } }; @@ -236,6 +236,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS updateDoubleLineClock(); setDateWeatherVisibility(); + setWeatherVisibility(); mKeyguardUnlockAnimationController.addKeyguardUnlockAnimationListener( mKeyguardUnlockAnimationListener); @@ -266,6 +267,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mStatusArea.removeView(mDateWeatherView); addDateWeatherView(index); } + setDateWeatherVisibility(); + setWeatherVisibility(); } int index = mStatusArea.indexOfChild(mSmartspaceView); if (index >= 0) { @@ -487,16 +490,19 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } private void setDateWeatherVisibility() { - if (mDateWeatherView != null || mWeatherView != null) { + if (mDateWeatherView != null) { mUiExecutor.execute(() -> { - if (mDateWeatherView != null) { - mDateWeatherView.setVisibility( - clockHasCustomWeatherDataDisplay() ? View.GONE : View.VISIBLE); - } - if (mWeatherView != null) { - mWeatherView.setVisibility( - mSmartspaceController.isWeatherEnabled() ? View.VISIBLE : View.GONE); - } + mDateWeatherView.setVisibility( + clockHasCustomWeatherDataDisplay() ? View.INVISIBLE : View.VISIBLE); + }); + } + } + + private void setWeatherVisibility() { + if (mWeatherView != null) { + mUiExecutor.execute(() -> { + mWeatherView.setVisibility( + mSmartspaceController.isWeatherEnabled() ? View.VISIBLE : View.GONE); }); } } @@ -513,9 +519,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { - pw.println("currentClockSizeLarge=" + (mCurrentClockSize == LARGE)); - pw.println("mCanShowDoubleLineClock=" + mCanShowDoubleLineClock); + pw.println("currentClockSizeLarge: " + (mCurrentClockSize == LARGE)); + pw.println("mCanShowDoubleLineClock: " + mCanShowDoubleLineClock); mView.dump(pw, args); + mClockRegistry.dump(pw, args); ClockController clock = getClock(); if (clock != null) { clock.dump(pw); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt index c98e9b40e7ab..5b0e29005d82 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt @@ -17,9 +17,9 @@ package com.android.keyguard import android.annotation.CurrentTimeMillisLong +import com.android.systemui.common.buffer.RingBuffer import com.android.systemui.dump.DumpsysTableLogger import com.android.systemui.dump.Row -import com.android.systemui.plugins.util.RingBuffer /** Verbose debug information associated. */ data class KeyguardFaceListenModel( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt index 57130ed80d26..b8c0ccbd8aaa 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt @@ -17,9 +17,9 @@ package com.android.keyguard import android.annotation.CurrentTimeMillisLong +import com.android.systemui.common.buffer.RingBuffer import com.android.systemui.dump.DumpsysTableLogger import com.android.systemui.dump.Row -import com.android.systemui.plugins.util.RingBuffer /** Verbose debug information. */ data class KeyguardFingerprintListenModel( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index bec854777919..a0f5f3451e94 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -121,7 +121,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> } @Override - public void showMessage(CharSequence message, ColorStateList colorState) { + public void showMessage(CharSequence message, ColorStateList colorState, boolean animated) { } public void startAppearAnimation() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 5c56aab9a611..39225fb03939 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -333,14 +333,14 @@ public class KeyguardPatternViewController } @Override - public void showMessage(CharSequence message, ColorStateList colorState) { + public void showMessage(CharSequence message, ColorStateList colorState, boolean animated) { if (mMessageAreaController == null) { return; } if (colorState != null) { mMessageAreaController.setNextMessageColor(colorState); } - mMessageAreaController.setMessage(message); + mMessageAreaController.setMessage(message, animated); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 87a775866faf..76e051ea25f3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -65,7 +65,6 @@ import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent; import com.android.keyguard.KeyguardSecurityContainer.SwipeListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.dagger.KeyguardBouncerScope; -import com.android.settingslib.Utils; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; @@ -75,6 +74,7 @@ import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; @@ -115,6 +115,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final SessionTracker mSessionTracker; private final Optional<SideFpsController> mSideFpsController; private final FalsingA11yDelegate mFalsingA11yDelegate; + private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; private int mTranslationY; // Whether the volume keys should be handled by keyguard. If true, then // they will be handled here for specific media types such as music, otherwise @@ -300,11 +301,12 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard @Override public void onSwipeUp() { if (!mUpdateMonitor.isFaceDetectionRunning()) { + mKeyguardFaceAuthInteractor.onSwipeUpOnBouncer(); boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth( FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER); mKeyguardSecurityCallback.userActivity(); if (didFaceAuthRun) { - showMessage(null, null); + showMessage(/* message= */ null, /* colorState= */ null, /* animated= */ true); } } if (mUpdateMonitor.isFaceEnrolled()) { @@ -389,7 +391,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard FalsingA11yDelegate falsingA11yDelegate, TelephonyManager telephonyManager, ViewMediatorCallback viewMediatorCallback, - AudioManager audioManager + AudioManager audioManager, + KeyguardFaceAuthInteractor keyguardFaceAuthInteractor ) { super(view); mLockPatternUtils = lockPatternUtils; @@ -414,6 +417,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mTelephonyManager = telephonyManager; mViewMediatorCallback = viewMediatorCallback; mAudioManager = audioManager; + mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor; } @Override @@ -454,7 +458,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard showPrimarySecurityScreen(true); mAdminSecondaryLockScreenController.hide(); if (mCurrentSecurityMode != SecurityMode.None) { - getCurrentSecurityController().onPause(); + getCurrentSecurityController(controller -> controller.onPause()); } mView.onPause(); mView.clearFocus(); @@ -508,13 +512,15 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (reason != PROMPT_REASON_NONE) { Log.i(TAG, "Strong auth required, reason: " + reason); } - getCurrentSecurityController().showPromptReason(reason); + getCurrentSecurityController(controller -> controller.showPromptReason(reason)); } } - public void showMessage(CharSequence message, ColorStateList colorState) { + /** Set message of bouncer title. */ + public void showMessage(CharSequence message, ColorStateList colorState, boolean animated) { if (mCurrentSecurityMode != SecurityMode.None) { - getCurrentSecurityController().showMessage(message, colorState); + getCurrentSecurityController( + controller -> controller.showMessage(message, colorState, animated)); } } @@ -629,7 +635,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, state); - getCurrentSecurityController().onResume(reason); + + getCurrentSecurityController(controller -> controller.onResume(reason)); } mView.onResume( mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()), @@ -640,7 +647,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard public void setInitialMessage() { CharSequence customMessage = mViewMediatorCallback.consumeCustomMessage(); if (!TextUtils.isEmpty(customMessage)) { - showMessage(customMessage, Utils.getColorError(getContext())); + showMessage(customMessage, /* colorState= */ null, /* animated= */ false); return; } showPromptReason(mViewMediatorCallback.getBouncerPromptReason()); @@ -669,7 +676,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (mCurrentSecurityMode != SecurityMode.None) { setAlpha(1f); mView.startAppearAnimation(mCurrentSecurityMode); - getCurrentSecurityController().startAppearAnimation(); + getCurrentSecurityController(controller -> controller.startAppearAnimation()); } } @@ -679,24 +686,23 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } public boolean startDisappearAnimation(Runnable onFinishRunnable) { - boolean didRunAnimation = false; - if (mCurrentSecurityMode != SecurityMode.None) { mView.startDisappearAnimation(mCurrentSecurityMode); - didRunAnimation = getCurrentSecurityController().startDisappearAnimation( - onFinishRunnable); - } - - if (!didRunAnimation && onFinishRunnable != null) { - onFinishRunnable.run(); + getCurrentSecurityController( + controller -> { + boolean didRunAnimation = controller.startDisappearAnimation( + onFinishRunnable); + if (!didRunAnimation && onFinishRunnable != null) { + onFinishRunnable.run(); + } + }); } - - return didRunAnimation; + return true; } public void onStartingToHide() { if (mCurrentSecurityMode != SecurityMode.None) { - getCurrentSecurityController().onStartingToHide(); + getCurrentSecurityController(controller -> controller.onStartingToHide()); } } @@ -804,8 +810,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard return finish; } + @Override public boolean needsInput() { - return getCurrentSecurityController().needsInput(); + return false; } /** @@ -933,22 +940,19 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard return; } - KeyguardInputViewController<KeyguardInputView> oldView = getCurrentSecurityController(); + getCurrentSecurityController(oldView -> oldView.onPause()); - // Emulate Activity life cycle - if (oldView != null) { - oldView.onPause(); - } + mCurrentSecurityMode = securityMode; - KeyguardInputViewController<KeyguardInputView> newView = changeSecurityMode(securityMode); - if (newView != null) { - newView.onResume(KeyguardSecurityView.VIEW_REVEALED); - mSecurityViewFlipperController.show(newView); - configureMode(); - } + getCurrentSecurityController( + newView -> { + newView.onResume(KeyguardSecurityView.VIEW_REVEALED); + mSecurityViewFlipperController.show(newView); + configureMode(); + mKeyguardSecurityCallback.onSecurityModeChanged( + securityMode, newView != null && newView.needsInput()); - mKeyguardSecurityCallback.onSecurityModeChanged( - securityMode, newView != null && newView.needsInput()); + }); } /** @@ -981,7 +985,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController, () -> showMessage(getContext().getString(R.string.keyguard_unlock_to_continue), - null), mFalsingA11yDelegate); + /* colorState= */ null, /* animated= */ true), mFalsingA11yDelegate); } public void reportFailedUnlockAttempt(int userId, int timeoutMs) { @@ -1028,15 +1032,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } } - private KeyguardInputViewController<KeyguardInputView> getCurrentSecurityController() { - return mSecurityViewFlipperController - .getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback); - } - - private KeyguardInputViewController<KeyguardInputView> changeSecurityMode( - SecurityMode securityMode) { - mCurrentSecurityMode = securityMode; - return getCurrentSecurityController(); + private void getCurrentSecurityController( + KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback) { + mSecurityViewFlipperController + .getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback, + onViewInflatedCallback); } /** @@ -1086,28 +1086,22 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } private void reloadColors() { - reinflateViewFlipper(() -> mView.reloadColors()); + reinflateViewFlipper(controller -> mView.reloadColors()); } /** Handles density or font scale changes. */ private void onDensityOrFontScaleChanged() { - reinflateViewFlipper(() -> mView.onDensityOrFontScaleChanged()); + reinflateViewFlipper(controller -> mView.onDensityOrFontScaleChanged()); } /** * Reinflate the view flipper child view. */ public void reinflateViewFlipper( - KeyguardSecurityViewFlipperController.OnViewInflatedListener onViewInflatedListener) { + KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedListener) { mSecurityViewFlipperController.clearViews(); - if (mFeatureFlags.isEnabled(Flags.ASYNC_INFLATE_BOUNCER)) { - mSecurityViewFlipperController.asynchronouslyInflateView(mCurrentSecurityMode, - mKeyguardSecurityCallback, onViewInflatedListener); - } else { - mSecurityViewFlipperController.getSecurityView(mCurrentSecurityMode, - mKeyguardSecurityCallback); - onViewInflatedListener.onViewInflated(); - } + mSecurityViewFlipperController.asynchronouslyInflateView(mCurrentSecurityMode, + mKeyguardSecurityCallback, onViewInflatedListener); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java index 67d77e53738a..22ad725faaa2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java @@ -106,7 +106,7 @@ public interface KeyguardSecurityView { * @param message the message to show * @param colorState the color to use */ - void showMessage(CharSequence message, ColorStateList colorState); + void showMessage(CharSequence message, ColorStateList colorState, boolean animated); /** * Starts the animation which should run when the security view appears. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java index ddf11997d3a7..fbacd6818648 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java @@ -28,7 +28,6 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.systemui.R; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.util.ViewController; import java.util.ArrayList; @@ -54,23 +53,19 @@ 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, - ViewMediatorCallback viewMediatorCallback) { + FeatureFlags featureFlags) { super(view); mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; mLayoutInflater = layoutInflater; mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; mAsyncLayoutInflater = asyncLayoutInflater; mFeatureFlags = featureFlags; - mViewMediatorCallback = viewMediatorCallback; } @Override @@ -97,40 +92,17 @@ public class KeyguardSecurityViewFlipperController @VisibleForTesting - KeyguardInputViewController<KeyguardInputView> getSecurityView(SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback) { - KeyguardInputViewController<KeyguardInputView> childController = null; + void getSecurityView(SecurityMode securityMode, + KeyguardSecurityCallback keyguardSecurityCallback, + OnViewInflatedCallback onViewInflatedCallback) { for (KeyguardInputViewController<KeyguardInputView> child : mChildren) { if (child.getSecurityMode() == securityMode) { - childController = child; - break; - } - } - - if (!mFeatureFlags.isEnabled(Flags.ASYNC_INFLATE_BOUNCER) && childController == null - && securityMode != SecurityMode.None && securityMode != SecurityMode.Invalid) { - int layoutId = getLayoutIdFor(securityMode); - KeyguardInputView view = null; - if (layoutId != 0) { - if (DEBUG) Log.v(TAG, "inflating on main thread id = " + layoutId); - view = (KeyguardInputView) mLayoutInflater.inflate( - layoutId, mView, false); - mView.addView(view); - childController = mKeyguardSecurityViewControllerFactory.create( - view, securityMode, keyguardSecurityCallback); - childController.init(); - - mChildren.add(childController); + onViewInflatedCallback.onViewInflated(child); + return; } } - if (childController == null) { - childController = new NullKeyguardInputViewController( - securityMode, keyguardSecurityCallback, - mEmergencyButtonControllerFactory.create(null)); - } - - return childController; + asynchronouslyInflateView(securityMode, keyguardSecurityCallback, onViewInflatedCallback); } /** @@ -143,7 +115,7 @@ public class KeyguardSecurityViewFlipperController */ public void asynchronouslyInflateView(SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback, - @Nullable OnViewInflatedListener onViewInflatedListener) { + @Nullable OnViewInflatedCallback onViewInflatedListener) { int layoutId = getLayoutIdFor(securityMode); if (layoutId != 0) { if (DEBUG) Log.v(TAG, "inflating on bg thread id = " + layoutId); @@ -156,9 +128,8 @@ public class KeyguardSecurityViewFlipperController keyguardSecurityCallback); childController.init(); mChildren.add(childController); - mViewMediatorCallback.setNeedsInput(childController.needsInput()); if (onViewInflatedListener != null) { - onViewInflatedListener.onViewInflated(); + onViewInflatedListener.onViewInflated(childController); } }); } @@ -184,33 +155,9 @@ public class KeyguardSecurityViewFlipperController } } - private static class NullKeyguardInputViewController - extends KeyguardInputViewController<KeyguardInputView> { - protected NullKeyguardInputViewController(SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback, - EmergencyButtonController emergencyButtonController) { - super(null, securityMode, keyguardSecurityCallback, emergencyButtonController, - null); - } - - @Override - public boolean needsInput() { - return false; - } - - @Override - public void onStartingToHide() { - } - - @Override - protected int getInitialMessageResId() { - return 0; - } - } - /** Listener to when view has finished inflation. */ - public interface OnViewInflatedListener { + public interface OnViewInflatedCallback { /** Notifies that view has been inflated */ - void onViewInflated(); + void onViewInflated(KeyguardInputViewController<KeyguardInputView> controller); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index b8e196fb8787..d8e1eb0f0860 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -19,10 +19,12 @@ package com.android.keyguard; import static java.util.Collections.emptySet; import android.content.Context; +import android.os.Build; import android.os.Trace; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; +import android.view.ViewPropertyAnimator; import android.widget.GridLayout; import com.android.systemui.R; @@ -118,6 +120,16 @@ public class KeyguardStatusView extends GridLayout { } @Override + public ViewPropertyAnimator animate() { + if (Build.IS_DEBUGGABLE) { + throw new IllegalArgumentException( + "KeyguardStatusView does not support ViewPropertyAnimator. " + + "Use PropertyAnimator instead."); + } + return super.animate(); + } + + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Trace.beginSection("KeyguardStatusView#onMeasure"); super.onMeasure(widthMeasureSpec, heightMeasureSpec); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index c4df836e401f..0cdef4d63639 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -16,12 +16,37 @@ package com.android.keyguard; +import static androidx.constraintlayout.widget.ConstraintSet.END; +import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID; + +import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION; + +import android.animation.Animator; +import android.animation.ValueAnimator; import android.annotation.Nullable; import android.graphics.Rect; +import android.transition.ChangeBounds; +import android.transition.Transition; +import android.transition.TransitionListenerAdapter; +import android.transition.TransitionManager; +import android.transition.TransitionSet; +import android.transition.TransitionValues; import android.util.Slog; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import androidx.annotation.VisibleForTesting; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.constraintlayout.widget.ConstraintSet; + +import com.android.internal.jank.InteractionJankMonitor; import com.android.keyguard.KeyguardClockSwitch.ClockSize; import com.android.keyguard.logging.KeyguardLogger; +import com.android.systemui.R; +import com.android.systemui.animation.Interpolators; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.ClockController; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; @@ -42,7 +67,13 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV private static final boolean DEBUG = KeyguardConstants.DEBUG; private static final String TAG = "KeyguardStatusViewController"; - private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = + /** + * Duration to use for the animator when the keyguard status view alignment changes, and a + * custom clock animation is in use. + */ + private static final int KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION = 1000; + + public static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); private final KeyguardSliceViewController mKeyguardSliceViewController; @@ -50,8 +81,25 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final ConfigurationController mConfigurationController; private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; + private final FeatureFlags mFeatureFlags; + private final InteractionJankMonitor mInteractionJankMonitor; private final Rect mClipBounds = new Rect(); + private Boolean mStatusViewCentered = true; + + private final TransitionListenerAdapter mKeyguardStatusAlignmentTransitionListener = + new TransitionListenerAdapter() { + @Override + public void onTransitionCancel(Transition transition) { + mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); + } + + @Override + public void onTransitionEnd(Transition transition) { + mInteractionJankMonitor.end(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); + } + }; + @Inject public KeyguardStatusViewController( KeyguardStatusView keyguardStatusView, @@ -62,7 +110,9 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV ConfigurationController configurationController, DozeParameters dozeParameters, ScreenOffAnimationController screenOffAnimationController, - KeyguardLogger logger) { + KeyguardLogger logger, + FeatureFlags featureFlags, + InteractionJankMonitor interactionJankMonitor) { super(keyguardStatusView); mKeyguardSliceViewController = keyguardSliceViewController; mKeyguardClockSwitchController = keyguardClockSwitchController; @@ -71,6 +121,8 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController, dozeParameters, screenOffAnimationController, /* animateYPos= */ true, logger.getBuffer()); + mInteractionJankMonitor = interactionJankMonitor; + mFeatureFlags = featureFlags; } @Override @@ -169,16 +221,32 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV mView.setImportantForAccessibility(mode); } + @VisibleForTesting + void setProperty(AnimatableProperty property, float value, boolean animate) { + PropertyAnimator.setProperty(mView, property, value, CLOCK_ANIMATION_PROPERTIES, animate); + } + /** * Update position of the view with an optional animation */ public void updatePosition(int x, int y, float scale, boolean animate) { float oldY = mView.getY(); - PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, CLOCK_ANIMATION_PROPERTIES, - animate); + setProperty(AnimatableProperty.Y, y, animate); + + ClockController clock = mKeyguardClockSwitchController.getClock(); + if (clock != null && clock.getConfig().getUseAlternateSmartspaceAODTransition()) { + // If requested, scale the entire view instead of just the clock view + mKeyguardClockSwitchController.updatePosition(x, 1f /* scale */, + CLOCK_ANIMATION_PROPERTIES, animate); + setProperty(AnimatableProperty.SCALE_X, scale, animate); + setProperty(AnimatableProperty.SCALE_Y, scale, animate); + } else { + mKeyguardClockSwitchController.updatePosition(x, scale, + CLOCK_ANIMATION_PROPERTIES, animate); + setProperty(AnimatableProperty.SCALE_X, 1f, animate); + setProperty(AnimatableProperty.SCALE_Y, 1f, animate); + } - mKeyguardClockSwitchController.updatePosition(x, scale, CLOCK_ANIMATION_PROPERTIES, - animate); if (oldY != y) { mKeyguardClockSwitchController.updateKeyguardStatusViewOffset(); } @@ -242,9 +310,141 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } } - /** Gets the current clock controller. */ - @Nullable - public ClockController getClockController() { - return mKeyguardClockSwitchController.getClock(); + /** + * Updates the alignment of the KeyguardStatusView and animates the transition if requested. + */ + public void updateAlignment( + ConstraintLayout notifContainerParent, + boolean splitShadeEnabled, + boolean shouldBeCentered, + boolean animate) { + if (mStatusViewCentered == shouldBeCentered) { + return; + } + + mStatusViewCentered = shouldBeCentered; + if (notifContainerParent == null) { + return; + } + + ConstraintSet constraintSet = new ConstraintSet(); + constraintSet.clone(notifContainerParent); + int statusConstraint = shouldBeCentered ? PARENT_ID : R.id.qs_edge_guideline; + constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END); + if (!animate) { + constraintSet.applyTo(notifContainerParent); + return; + } + + mInteractionJankMonitor.begin(mView, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); + ChangeBounds transition = new ChangeBounds(); + if (splitShadeEnabled) { + // Excluding media from the transition on split-shade, as it doesn't transition + // horizontally properly. + transition.excludeTarget(R.id.status_view_media_container, true); + } + + transition.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + + ClockController clock = mKeyguardClockSwitchController.getClock(); + boolean customClockAnimation = clock != null + && clock.getConfig().getHasCustomPositionUpdatedAnimation(); + + if (mFeatureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION) && customClockAnimation) { + // Find the clock, so we can exclude it from this transition. + FrameLayout clockContainerView = mView.findViewById(R.id.lockscreen_clock_view_large); + + // The clock container can sometimes be null. If it is, just fall back to the + // old animation rather than setting up the custom animations. + if (clockContainerView == null || clockContainerView.getChildCount() == 0) { + transition.addListener(mKeyguardStatusAlignmentTransitionListener); + TransitionManager.beginDelayedTransition(notifContainerParent, transition); + } else { + View clockView = clockContainerView.getChildAt(0); + + transition.excludeTarget(clockView, /* exclude= */ true); + + TransitionSet set = new TransitionSet(); + set.addTransition(transition); + + SplitShadeTransitionAdapter adapter = + new SplitShadeTransitionAdapter(mKeyguardClockSwitchController); + + // Use linear here, so the actual clock can pick its own interpolator. + adapter.setInterpolator(Interpolators.LINEAR); + adapter.setDuration(KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION); + adapter.addTarget(clockView); + set.addTransition(adapter); + set.addListener(mKeyguardStatusAlignmentTransitionListener); + TransitionManager.beginDelayedTransition(notifContainerParent, set); + } + } else { + transition.addListener(mKeyguardStatusAlignmentTransitionListener); + TransitionManager.beginDelayedTransition(notifContainerParent, transition); + } + + constraintSet.applyTo(notifContainerParent); + } + + @VisibleForTesting + static class SplitShadeTransitionAdapter extends Transition { + private static final String PROP_BOUNDS = "splitShadeTransitionAdapter:bounds"; + private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS }; + + private final KeyguardClockSwitchController mController; + + @VisibleForTesting + SplitShadeTransitionAdapter(KeyguardClockSwitchController controller) { + mController = controller; + } + + private void captureValues(TransitionValues transitionValues) { + Rect boundsRect = new Rect(); + boundsRect.left = transitionValues.view.getLeft(); + boundsRect.top = transitionValues.view.getTop(); + boundsRect.right = transitionValues.view.getRight(); + boundsRect.bottom = transitionValues.view.getBottom(); + transitionValues.values.put(PROP_BOUNDS, boundsRect); + } + + @Override + public void captureEndValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + @Override + public void captureStartValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + @Nullable + @Override + public Animator createAnimator(ViewGroup sceneRoot, @Nullable TransitionValues startValues, + @Nullable TransitionValues endValues) { + if (startValues == null || endValues == null) { + return null; + } + ValueAnimator anim = ValueAnimator.ofFloat(0, 1); + + Rect from = (Rect) startValues.values.get(PROP_BOUNDS); + Rect to = (Rect) endValues.values.get(PROP_BOUNDS); + + anim.addUpdateListener(animation -> { + ClockController clock = mController.getClock(); + if (clock == null) { + return; + } + + clock.getAnimations().onPositionUpdated(from, to, animation.getAnimatedFraction()); + }); + + return anim; + } + + @Override + public String[] getTransitionProperties() { + return TRANSITION_PROPERTIES; + } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index e1bca89091b2..c48aaf451e62 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -96,6 +96,7 @@ import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.SensorProperties; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; @@ -153,6 +154,16 @@ import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpsysTableLogger; +import com.android.systemui.keyguard.domain.interactor.FaceAuthenticationListener; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; +import com.android.systemui.keyguard.shared.constants.TrustAgentUiEvent; +import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.AuthenticationStatus; +import com.android.systemui.keyguard.shared.model.DetectionStatus; +import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus; +import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus; import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions; import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.WeatherData; @@ -371,6 +382,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final FingerprintManager mFpm; @Nullable private final FaceManager mFaceManager; + @Nullable + private KeyguardFaceAuthInteractor mFaceAuthInteractor; private final LockPatternUtils mLockPatternUtils; @VisibleForTesting @DevicePostureInt @@ -525,6 +538,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mLogger.logTrustGrantedWithFlags(flags, newlyUnlocked, userId, message); if (userId == getCurrentUser()) { + if (newlyUnlocked) { + // if this callback is ever removed, this should then be logged in + // TrustRepository + mUiEventLogger.log( + TrustAgentUiEvent.TRUST_AGENT_NEWLY_UNLOCKED, + getKeyguardSessionId() + ); + } final TrustGrantFlags trustGrantFlags = new TrustGrantFlags(flags); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1164,8 +1185,21 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab Trace.endSection(); } + /** + * @deprecated This is being migrated to use modern architecture, this method is visible purely + * for bridging the gap while the migration is active. + */ private void handleFaceAuthFailed() { Assert.isMainThread(); + String reason = + mKeyguardBypassController.canBypass() ? "bypass" + : mAlternateBouncerShowing ? "alternateBouncer" + : mPrimaryBouncerFullyShown ? "bouncer" + : "udfpsFpDown"; + requestActiveUnlock( + ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL, + "faceFailure-" + reason); + mLogger.d("onFaceAuthFailed"); mFaceCancelSignal = null; setFaceRunningState(BIOMETRIC_STATE_STOPPED); @@ -1179,6 +1213,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mContext.getString(R.string.kg_face_not_recognized)); } + /** + * @deprecated This is being migrated to use modern architecture, this method is visible purely + * for bridging the gap while the migration is active. + */ private void handleFaceAcquired(int acquireInfo) { Assert.isMainThread(); mLogger.logFaceAcquired(acquireInfo); @@ -1188,8 +1226,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab cb.onBiometricAcquired(FACE, acquireInfo); } } + + if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo( + acquireInfo)) { + requestActiveUnlock( + ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL, + "faceAcquireInfo-" + acquireInfo); + } } + /** + * @deprecated This is being migrated to use modern architecture, this method is visible purely + * for bridging the gap while the migration is active. + */ private void handleFaceAuthenticated(int authUserId, boolean isStrongBiometric) { Trace.beginSection("KeyGuardUpdateMonitor#handlerFaceAuthenticated"); try { @@ -1202,7 +1251,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mLogger.logFaceAuthForWrongUser(authUserId); return; } - if (isFaceDisabled(userId)) { + if (!isFaceAuthInteractorEnabled() && isFaceDisabled(userId)) { mLogger.logFaceAuthDisabledForUser(userId); return; } @@ -1214,7 +1263,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab Trace.endSection(); } + /** + * @deprecated This is being migrated to use modern architecture, this method is visible purely + * for bridging the gap while the migration is active. + */ private void handleFaceHelp(int msgId, String helpString) { + if (mFaceAcquiredInfoIgnoreList.contains(msgId)) { + return; + } Assert.isMainThread(); mLogger.logFaceAuthHelpMsg(msgId, helpString); for (int i = 0; i < mCallbacks.size(); i++) { @@ -1225,22 +1281,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - private final Runnable mRetryFaceAuthentication = new Runnable() { - @Override - public void run() { - mLogger.logRetryingAfterFaceHwUnavailable(mHardwareFaceUnavailableRetryCount); - updateFaceListeningState(BIOMETRIC_ACTION_UPDATE, - FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE); - } - }; - - private void onFaceCancelNotReceived() { - mLogger.e("Face cancellation not received, transitioning to STOPPED"); - mFaceRunningState = BIOMETRIC_STATE_STOPPED; - KeyguardUpdateMonitor.this.updateFaceListeningState(BIOMETRIC_ACTION_STOP, - FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED); - } - + /** + * @deprecated This is being migrated to use modern architecture, this method is visible purely + * for bridging the gap while the migration is active. + */ private void handleFaceError(int msgId, final String originalErrMsg) { Assert.isMainThread(); String errString = originalErrMsg; @@ -1278,6 +1322,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) { lockedOutStateChanged = !mFaceLockedOutPermanent; mFaceLockedOutPermanent = true; + if (isFaceClass3()) { + updateFingerprintListeningState(BIOMETRIC_ACTION_STOP); + } } if (isHwUnavailable && cameraPrivacyEnabled) { @@ -1295,6 +1342,28 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (lockedOutStateChanged) { notifyLockedOutStateChanged(FACE); } + + if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(msgId)) { + requestActiveUnlock( + ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL, + "faceError-" + msgId); + } + } + + private final Runnable mRetryFaceAuthentication = new Runnable() { + @Override + public void run() { + mLogger.logRetryingAfterFaceHwUnavailable(mHardwareFaceUnavailableRetryCount); + updateFaceListeningState(BIOMETRIC_ACTION_UPDATE, + FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE); + } + }; + + private void onFaceCancelNotReceived() { + mLogger.e("Face cancellation not received, transitioning to STOPPED"); + mFaceRunningState = BIOMETRIC_STATE_STOPPED; + KeyguardUpdateMonitor.this.updateFaceListeningState(BIOMETRIC_ACTION_STOP, + FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED); } private void handleFaceLockoutReset(@LockoutMode int mode) { @@ -1339,10 +1408,61 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return mFingerprintRunningState == BIOMETRIC_STATE_RUNNING; } + /** + * @deprecated This is being migrated to use modern architecture. + */ + @Deprecated public boolean isFaceDetectionRunning() { + if (isFaceAuthInteractorEnabled()) { + return getFaceAuthInteractor().isRunning(); + } return mFaceRunningState == BIOMETRIC_STATE_RUNNING; } + private boolean isFaceAuthInteractorEnabled() { + return mFaceAuthInteractor != null && mFaceAuthInteractor.isEnabled(); + } + + private @Nullable KeyguardFaceAuthInteractor getFaceAuthInteractor() { + return mFaceAuthInteractor; + } + + /** + * Set the face auth interactor that should be used for initiating face authentication. + */ + public void setFaceAuthInteractor(@Nullable KeyguardFaceAuthInteractor faceAuthInteractor) { + mFaceAuthInteractor = faceAuthInteractor; + mFaceAuthInteractor.registerListener(mFaceAuthenticationListener); + } + + private FaceAuthenticationListener mFaceAuthenticationListener = + new FaceAuthenticationListener() { + @Override + public void onAuthenticationStatusChanged(@NonNull AuthenticationStatus status) { + if (status instanceof AcquiredAuthenticationStatus) { + handleFaceAcquired( + ((AcquiredAuthenticationStatus) status).getAcquiredInfo()); + } else if (status instanceof ErrorAuthenticationStatus) { + ErrorAuthenticationStatus error = (ErrorAuthenticationStatus) status; + handleFaceError(error.getMsgId(), error.getMsg()); + } else if (status instanceof FailedAuthenticationStatus) { + handleFaceAuthFailed(); + } else if (status instanceof HelpAuthenticationStatus) { + HelpAuthenticationStatus helpMsg = (HelpAuthenticationStatus) status; + handleFaceHelp(helpMsg.getMsgId(), helpMsg.getMsg()); + } else if (status instanceof SuccessAuthenticationStatus) { + FaceManager.AuthenticationResult result = + ((SuccessAuthenticationStatus) status).getSuccessResult(); + handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric()); + } + } + + @Override + public void onDetectionStatusChanged(@NonNull DetectionStatus status) { + handleFaceAuthenticated(status.getUserId(), status.isStrongBiometric()); + } + }; + private boolean isTrustDisabled() { // Don't allow trust agent if device is secured with a SIM PIN. This is here // mainly because there's no other way to prompt the user to enter their SIM PIN @@ -1356,6 +1476,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || isSimPinSecure(); } + /** + * @deprecated This method is not needed anymore with the new face auth system. + */ + @Deprecated private boolean isFaceDisabled(int userId) { // TODO(b/140035044) return whitelistIpcs(() -> @@ -1367,7 +1491,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab /** * @return whether the current user has been authenticated with face. This may be true * on the lockscreen if the user doesn't have bypass enabled. + * + * @deprecated This is being migrated to use modern architecture. */ + @Deprecated public boolean getIsFaceAuthenticated() { boolean faceAuthenticated = false; BiometricAuthenticated bioFaceAuthenticated = mUserFaceAuthenticated.get(getCurrentUser()); @@ -1487,8 +1614,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // STRONG_AUTH_REQUIRED_AFTER_LOCKOUT which is the same as mFingerprintLockedOutPermanent; // however the strong auth tracker does not include the temporary lockout // mFingerprintLockedOut. + // Class 3 biometric lockout will lockout ALL biometrics return mStrongAuthTracker.isUnlockingWithBiometricAllowed(isStrongBiometric) - && !mFingerprintLockedOut; + && (!isFingerprintClass3() || !isFingerprintLockedOut()) + && (!isFaceClass3() || !mFaceLockedOutPermanent); } /** @@ -1506,9 +1635,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @NonNull BiometricSourceType biometricSourceType) { switch (biometricSourceType) { case FINGERPRINT: - return isUnlockingWithBiometricAllowed(true); + return isUnlockingWithBiometricAllowed(isFingerprintClass3()); case FACE: - return isUnlockingWithBiometricAllowed(false); + return isUnlockingWithBiometricAllowed(isFaceClass3()); default: return false; } @@ -1613,6 +1742,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab void setAssistantVisible(boolean assistantVisible) { mAssistantVisible = assistantVisible; mLogger.logAssistantVisible(mAssistantVisible); + if (isFaceAuthInteractorEnabled()) { + mFaceAuthInteractor.onAssistantTriggeredOnLockScreen(); + } updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED); if (mAssistantVisible) { @@ -1826,54 +1958,27 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onAuthenticationFailed() { - String reason = - mKeyguardBypassController.canBypass() ? "bypass" - : mAlternateBouncerShowing ? "alternateBouncer" - : mPrimaryBouncerFullyShown ? "bouncer" - : "udfpsFpDown"; - requestActiveUnlock( - ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL, - "faceFailure-" + reason); - handleFaceAuthFailed(); } @Override public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) { - Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded"); handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric()); - Trace.endSection(); } @Override public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { - if (mFaceAcquiredInfoIgnoreList.contains(helpMsgId)) { - return; - } handleFaceHelp(helpMsgId, helpString.toString()); } @Override public void onAuthenticationError(int errMsgId, CharSequence errString) { handleFaceError(errMsgId, errString.toString()); - - if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(errMsgId)) { - requestActiveUnlock( - ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL, - "faceError-" + errMsgId); - } } @Override public void onAuthenticationAcquired(int acquireInfo) { handleFaceAcquired(acquireInfo); - - if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo( - acquireInfo)) { - requestActiveUnlock( - ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL, - "faceAcquireInfo-" + acquireInfo); - } } }; @@ -2473,7 +2578,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void updateFaceEnrolled(int userId) { - Boolean isFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty() + final Boolean isFaceEnrolled = isFaceSupported() && mBiometricEnabledForUser.get(userId) && mAuthController.isFaceAuthEnrolled(userId); if (mIsFaceEnrolled != isFaceEnrolled) { @@ -2482,10 +2587,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mIsFaceEnrolled = isFaceEnrolled; } - public boolean isFaceSupported() { + private boolean isFaceSupported() { return mFaceManager != null && !mFaceSensorProperties.isEmpty(); } + private boolean isFingerprintSupported() { + return mFpm != null && !mFingerprintSensorProperties.isEmpty(); + } + /** * @return true if there's at least one udfps enrolled for the current user. */ @@ -2618,7 +2727,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * @param reason One of the reasons {@link FaceAuthApiRequestReason} on why this API is being * invoked. * @return current face auth detection state, true if it is running. + * @deprecated This is being migrated to use modern architecture. */ + @Deprecated public boolean requestFaceAuth(@FaceAuthApiRequestReason String reason) { mLogger.logFaceAuthRequested(reason); updateFaceListeningState(BIOMETRIC_ACTION_START, apiRequestReasonToUiEvent(reason)); @@ -2633,6 +2744,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void updateFaceListeningState(int action, @NonNull FaceAuthUiEvent faceAuthUiEvent) { + if (isFaceAuthInteractorEnabled()) return; // If this message exists, we should not authenticate again until this message is // consumed by the handler if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) { @@ -2792,10 +2904,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || !mLockPatternUtils.isSecure(user); // Don't trigger active unlock if fp is locked out - final boolean fpLockedOut = mFingerprintLockedOut || mFingerprintLockedOutPermanent; + final boolean fpLockedOut = isFingerprintLockedOut(); // Don't trigger active unlock if primary auth is required - final boolean primaryAuthRequired = !isUnlockingWithBiometricAllowed(true); + final boolean primaryAuthRequired = !isUnlockingWithTrustAgentAllowed(); final boolean shouldTriggerActiveUnlock = (mAuthInterruptActive || triggerActiveUnlockForAssistant || awakeKeyguard) @@ -2857,7 +2969,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || mGoingToSleep || shouldListenForFingerprintAssistant || (mKeyguardOccluded && mIsDreaming) - || (mKeyguardOccluded && userDoesNotHaveTrust + || (mKeyguardOccluded && userDoesNotHaveTrust && mKeyguardShowing && (mOccludingAppRequestingFp || isUdfps || mAlternateBouncerShowing)); // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an @@ -2949,7 +3061,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // allow face detection to happen even if stronger auth is required. When face is detected, // we show the bouncer. However, if the user manually locked down the device themselves, // never attempt to detect face. - final boolean supportsDetect = !mFaceSensorProperties.isEmpty() + final boolean supportsDetect = isFaceSupported() && mFaceSensorProperties.get(0).supportsFaceDetection && canBypass && !mPrimaryBouncerIsOrWillBeShowing && !isUserInLockdown(user); @@ -3104,7 +3216,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab : WAKE_REASON_UNKNOWN ).toFaceAuthenticateOptions(); // This would need to be updated for multi-sensor devices - final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty() + final boolean supportsFaceDetection = isFaceSupported() && mFaceSensorProperties.get(0).supportsFaceDetection; if (!isUnlockingWithBiometricAllowed(FACE)) { final boolean udfpsFingerprintAuthRunning = isUdfpsSupported() @@ -3144,6 +3256,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } public boolean isFaceLockedOut() { + if (isFaceAuthInteractorEnabled()) { + return getFaceAuthInteractor().isLockedOut(); + } return mFaceLockedOutPermanent; } @@ -3166,21 +3281,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * @return {@code true} if possible. */ public boolean isUnlockingWithNonStrongBiometricsPossible(int userId) { - // This assumes that there is at most one face and at most one fingerprint sensor - return (mFaceManager != null && !mFaceSensorProperties.isEmpty() - && (mFaceSensorProperties.get(0).sensorStrength != SensorProperties.STRENGTH_STRONG) - && isUnlockWithFacePossible(userId)) - || (mFpm != null && !mFingerprintSensorProperties.isEmpty() - && (mFingerprintSensorProperties.get(0).sensorStrength - != SensorProperties.STRENGTH_STRONG) && isUnlockWithFingerprintPossible(userId)); + return (!isFaceClass3() && isUnlockWithFacePossible(userId)) + || (isFingerprintClass3() && isUnlockWithFingerprintPossible(userId)); } @SuppressLint("MissingPermission") @VisibleForTesting boolean isUnlockWithFingerprintPossible(int userId) { // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once. - boolean newFpEnrolled = mFpm != null - && !mFingerprintSensorProperties.isEmpty() + boolean newFpEnrolled = isFingerprintSupported() && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId); Boolean oldFpEnrolled = mIsUnlockWithFingerprintPossible.getOrDefault(userId, false); if (oldFpEnrolled != newFpEnrolled) { @@ -3198,13 +3307,23 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return mIsUnlockWithFingerprintPossible.getOrDefault(userId, false); } + /** + * @deprecated This is being migrated to use modern architecture. + */ + @Deprecated private boolean isUnlockWithFacePossible(int userId) { + if (isFaceAuthInteractorEnabled()) { + return getFaceAuthInteractor().canFaceAuthRun(); + } return isFaceAuthEnabledForUser(userId) && !isFaceDisabled(userId); } /** * If face hardware is available, user has enrolled and enabled auth via setting. + * + * @deprecated This is being migrated to use modern architecture. */ + @Deprecated public boolean isFaceAuthEnabledForUser(int userId) { // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once. updateFaceEnrolled(userId); @@ -3228,6 +3347,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void stopListeningForFace(@NonNull FaceAuthUiEvent faceAuthUiEvent) { + if (isFaceAuthInteractorEnabled()) return; mLogger.v("stopListeningForFace()"); mLogger.logStoppedListeningForFace(mFaceRunningState, faceAuthUiEvent.getReason()); mUiEventLogger.log(faceAuthUiEvent, getKeyguardSessionId()); @@ -3330,12 +3450,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // Immediately stop previous biometric listening states. // Resetting lockout states updates the biometric listening states. - if (mFaceManager != null && !mFaceSensorProperties.isEmpty()) { + if (isFaceSupported()) { stopListeningForFace(FACE_AUTH_UPDATED_USER_SWITCHING); handleFaceLockoutReset(mFaceManager.getLockoutModeForUser( mFaceSensorProperties.get(0).sensorId, userId)); } - if (mFpm != null && !mFingerprintSensorProperties.isEmpty()) { + if (isFingerprintSupported()) { stopListeningForFingerprint(); handleFingerprintLockoutReset(mFpm.getLockoutModeForUser( mFingerprintSensorProperties.get(0).sensorId, userId)); @@ -4071,6 +4191,22 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return BIOMETRIC_LOCKOUT_RESET_DELAY_MS; } + @VisibleForTesting + protected boolean isFingerprintClass3() { + // This assumes that there is at most one fingerprint sensor property + return isFingerprintSupported() && isClass3Biometric(mFingerprintSensorProperties.get(0)); + } + + @VisibleForTesting + protected boolean isFaceClass3() { + // This assumes that there is at most one face sensor property + return isFaceSupported() && isClass3Biometric(mFaceSensorProperties.get(0)); + } + + private boolean isClass3Biometric(SensorPropertiesInternal sensorProperties) { + return sensorProperties.sensorStrength == SensorProperties.STRENGTH_STRONG; + } + /** * Unregister all listeners. */ @@ -4078,6 +4214,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mStatusBarStateController.removeCallback(mStatusBarStateControllerListener); mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener); mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener); + if (isFaceAuthInteractorEnabled()) { + mFaceAuthInteractor.unregisterListener(mFaceAuthenticationListener); + } if (mDeviceProvisionedObserver != null) { mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver); @@ -4107,6 +4246,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab pw.println(" getUserHasTrust()=" + getUserHasTrust(getCurrentUser())); pw.println(" getUserUnlockedWithBiometric()=" + getUserUnlockedWithBiometric(getCurrentUser())); + pw.println(" isFaceAuthInteractorEnabled: " + isFaceAuthInteractorEnabled()); pw.println(" SIM States:"); for (SimData data : mSimDatas.values()) { pw.println(" " + data.toString()); @@ -4122,11 +4262,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab for (int subId : mServiceStates.keySet()) { pw.println(" " + subId + "=" + mServiceStates.get(subId)); } - if (mFpm != null && !mFingerprintSensorProperties.isEmpty()) { + if (isFingerprintSupported()) { final int userId = mUserTracker.getUserId(); final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId); BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId); pw.println(" Fingerprint state (user=" + userId + ")"); + pw.println(" isFingerprintClass3=" + isFingerprintClass3()); pw.println(" areAllFpAuthenticatorsRegistered=" + mAuthController.areAllFingerprintAuthenticatorsRegistered()); pw.println(" allowed=" @@ -4184,11 +4325,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mFingerprintListenBuffer.toList() ).printTableData(pw); } - if (mFaceManager != null && !mFaceSensorProperties.isEmpty()) { + if (isFaceSupported()) { final int userId = mUserTracker.getUserId(); final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId); BiometricAuthenticated face = mUserFaceAuthenticated.get(userId); pw.println(" Face authentication state (user=" + userId + ")"); + pw.println(" isFaceClass3=" + isFaceClass3()); pw.println(" allowed=" + (face != null && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric))); pw.println(" auth'd=" @@ -4240,7 +4382,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Cancels all operations in the scheduler if it is hung for 10 seconds. */ public void startBiometricWatchdog() { - if (mFaceManager != null) { + if (mFaceManager != null && !isFaceAuthInteractorEnabled()) { mFaceManager.scheduleWatchdog(); } if (mFpm != null) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java index ac0a3fd8dbc4..651c9796140e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java @@ -18,8 +18,8 @@ package com.android.keyguard; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; +import android.util.Property; import android.view.View; -import android.view.ViewPropertyAnimator; import com.android.systemui.animation.Interpolators; import com.android.systemui.plugins.log.LogBuffer; @@ -28,13 +28,14 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; -import com.android.systemui.statusbar.phone.AnimatorHandle; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.google.errorprone.annotations.CompileTimeConstant; +import java.util.function.Consumer; + /** * Helper class for updating visibility of keyguard views based on keyguard and status bar state. * This logic is shared by both the keyguard status view and the keyguard user switcher. @@ -48,7 +49,6 @@ public class KeyguardVisibilityHelper { private final ScreenOffAnimationController mScreenOffAnimationController; private boolean mAnimateYPos; private boolean mKeyguardViewVisibilityAnimating; - private AnimatorHandle mKeyguardAnimatorHandle; private boolean mLastOccludedState = false; private final AnimationProperties mAnimationProperties = new AnimationProperties(); private final LogBuffer mLogBuffer; @@ -85,51 +85,49 @@ public class KeyguardVisibilityHelper { boolean keyguardFadingAway, boolean goingToFullShade, int oldStatusBarState) { - if (mKeyguardAnimatorHandle != null) { - mKeyguardAnimatorHandle.cancel(); - mKeyguardAnimatorHandle = null; - } - mView.animate().cancel(); + PropertyAnimator.cancelAnimation(mView, AnimatableProperty.ALPHA); boolean isOccluded = mKeyguardStateController.isOccluded(); mKeyguardViewVisibilityAnimating = false; if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD && statusBarState != KEYGUARD) || goingToFullShade) { mKeyguardViewVisibilityAnimating = true; - mView.animate() - .alpha(0f) - .setStartDelay(0) - .setDuration(160) - .setInterpolator(Interpolators.ALPHA_OUT) - .withEndAction( - mAnimateKeyguardStatusViewGoneEndRunnable); + + AnimationProperties animProps = new AnimationProperties() + .setCustomInterpolator(View.ALPHA, Interpolators.ALPHA_OUT) + .setAnimationEndAction(mSetGoneEndAction); if (keyguardFadingAway) { - mView.animate() - .setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay()) - .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration()) - .start(); + animProps + .setDelay(mKeyguardStateController.getKeyguardFadingAwayDelay()) + .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration()); log("goingToFullShade && keyguardFadingAway"); } else { + animProps.setDelay(0).setDuration(160); log("goingToFullShade && !keyguardFadingAway"); } + PropertyAnimator.setProperty( + mView, AnimatableProperty.ALPHA, 0f, animProps, true /* animate */); } else if (oldStatusBarState == StatusBarState.SHADE_LOCKED && statusBarState == KEYGUARD) { mView.setVisibility(View.VISIBLE); mKeyguardViewVisibilityAnimating = true; mView.setAlpha(0f); - mView.animate() - .alpha(1f) - .setStartDelay(0) - .setDuration(320) - .setInterpolator(Interpolators.ALPHA_IN) - .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable); - log("keyguardFadingAway transition w/ Y Animation"); + PropertyAnimator.setProperty( + mView, AnimatableProperty.ALPHA, 1f, + new AnimationProperties() + .setDelay(0) + .setDuration(320) + .setCustomInterpolator(View.ALPHA, Interpolators.ALPHA_IN) + .setAnimationEndAction( + property -> mSetVisibleEndRunnable.run()), + true /* animate */); + log("keyguardFadingAway transition w/ Y Aniamtion"); } else if (statusBarState == KEYGUARD) { if (keyguardFadingAway) { mKeyguardViewVisibilityAnimating = true; - ViewPropertyAnimator animator = mView.animate() - .alpha(0) - .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN) - .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable); + AnimationProperties animProps = new AnimationProperties() + .setDelay(0) + .setCustomInterpolator(View.ALPHA, Interpolators.FAST_OUT_LINEAR_IN) + .setAnimationEndAction(mSetInvisibleEndAction); if (mAnimateYPos) { float target = mView.getY() - mView.getHeight() * 0.05f; int delay = 0; @@ -141,21 +139,24 @@ public class KeyguardVisibilityHelper { PropertyAnimator.setProperty(mView, AnimatableProperty.Y, target, mAnimationProperties, true /* animate */); - animator.setDuration(duration) - .setStartDelay(delay); + animProps.setDuration(duration) + .setDelay(delay); log("keyguardFadingAway transition w/ Y Aniamtion"); } else { log("keyguardFadingAway transition w/o Y Animation"); } - animator.start(); + PropertyAnimator.setProperty( + mView, AnimatableProperty.ALPHA, 0f, + animProps, + true /* animate */); } else if (mScreenOffAnimationController.shouldAnimateInKeyguard()) { log("ScreenOff transition"); mKeyguardViewVisibilityAnimating = true; // Ask the screen off animation controller to animate the keyguard visibility for us // since it may need to be cancelled due to keyguard lifecycle events. - mKeyguardAnimatorHandle = mScreenOffAnimationController.animateInKeyguard( - mView, mAnimateKeyguardStatusViewVisibleEndRunnable); + mScreenOffAnimationController.animateInKeyguard( + mView, mSetVisibleEndRunnable); } else { log("Direct set Visibility to VISIBLE"); mView.setVisibility(View.VISIBLE); @@ -169,19 +170,25 @@ public class KeyguardVisibilityHelper { mLastOccludedState = isOccluded; } - private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = () -> { - mKeyguardViewVisibilityAnimating = false; - mView.setVisibility(View.INVISIBLE); - log("Callback Set Visibility to INVISIBLE"); + private final Consumer<Property> mSetInvisibleEndAction = new Consumer<>() { + @Override + public void accept(Property property) { + mKeyguardViewVisibilityAnimating = false; + mView.setVisibility(View.INVISIBLE); + log("Callback Set Visibility to INVISIBLE"); + } }; - private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = () -> { - mKeyguardViewVisibilityAnimating = false; - mView.setVisibility(View.GONE); - log("CallbackSet Visibility to GONE"); + private final Consumer<Property> mSetGoneEndAction = new Consumer<>() { + @Override + public void accept(Property property) { + mKeyguardViewVisibilityAnimating = false; + mView.setVisibility(View.GONE); + log("CallbackSet Visibility to GONE"); + } }; - private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> { + private final Runnable mSetVisibleEndRunnable = () -> { mKeyguardViewVisibilityAnimating = false; mView.setVisibility(View.VISIBLE); log("Callback Set Visibility to VISIBLE"); diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 235a8bca6d1e..5f2afe8f755d 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -294,6 +294,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme final CharSequence prevContentDescription = mView.getContentDescription(); if (mShowLockIcon) { + if (wasShowingFpIcon) { + // fp icon was shown by UdfpsView, and now we still want to animate the transition + // in this drawable + mView.updateIcon(ICON_FINGERPRINT, false); + } mView.updateIcon(ICON_LOCK, false); mView.setContentDescription(mLockedLabel); mView.setVisibility(View.VISIBLE); diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java index 6a6e81e9cb46..14810d9baf02 100644 --- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java +++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java @@ -30,7 +30,6 @@ import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; -import android.view.animation.Animation; import android.widget.ImageView; import android.widget.LinearLayout; @@ -50,7 +49,7 @@ public class PinShapeNonHintingView extends LinearLayout implements PinShapeInpu android.R.attr.textColorPrimary).getDefaultColor(); private int mPosition = 0; private final PinShapeAdapter mPinShapeAdapter; - private Animation mCurrentPlayingAnimation; + private ValueAnimator mValueAnimator = ValueAnimator.ofFloat(1f, 0f); public PinShapeNonHintingView(Context context, AttributeSet attrs) { super(context, attrs); mPinShapeAdapter = new PinShapeAdapter(context); @@ -80,15 +79,17 @@ public class PinShapeNonHintingView extends LinearLayout implements PinShapeInpu Log.e(getClass().getName(), "Trying to delete a non-existent char"); return; } + if (mValueAnimator.isRunning()) { + mValueAnimator.end(); + } mPosition--; ImageView pinDot = (ImageView) getChildAt(mPosition); - ValueAnimator animator = ValueAnimator.ofFloat(1f, 0f); - animator.addUpdateListener(valueAnimator -> { + mValueAnimator.addUpdateListener(valueAnimator -> { float value = (float) valueAnimator.getAnimatedValue(); pinDot.setScaleX(value); pinDot.setScaleY(value); }); - animator.addListener(new AnimatorListenerAdapter() { + mValueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); @@ -96,11 +97,10 @@ public class PinShapeNonHintingView extends LinearLayout implements PinShapeInpu PinShapeNonHintingView.this, new PinShapeViewTransition()); removeView(pinDot); - mCurrentPlayingAnimation = null; } }); - animator.setDuration(PasswordTextView.DISAPPEAR_DURATION); - animator.start(); + mValueAnimator.setDuration(PasswordTextView.DISAPPEAR_DURATION); + mValueAnimator.start(); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java index 334bb1ec12cb..9308773858e3 100644 --- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java @@ -96,6 +96,11 @@ public interface ViewMediatorCallback { CharSequence consumeCustomMessage(); /** + * Sets a message to be consumed the next time the bouncer shows up. + */ + void setCustomMessage(CharSequence customMessage); + + /** * Call when cancel button is pressed in bouncer. */ void onCancelClicked(); diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java index 6e98a1805d62..cde8ff78c620 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java @@ -33,6 +33,7 @@ import com.android.systemui.shared.clocks.DefaultClockProvider; import dagger.Module; import dagger.Provides; + import kotlinx.coroutines.CoroutineDispatcher; import kotlinx.coroutines.CoroutineScope; diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java index 7af6f6677f3f..401f6c9c747d 100644 --- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java @@ -26,12 +26,12 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.phone.CentralSurfaces; +import dagger.Lazy; + import java.util.Optional; import javax.inject.Inject; -import dagger.Lazy; - /** * Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but * delegates to an actual implementation (CentralSurfaces). @@ -142,6 +142,14 @@ public class ActivityStarterDelegate implements ActivityStarter { } @Override + public void postStartActivityDismissingKeyguard(Intent intent, int delay, + @Nullable ActivityLaunchAnimator.Controller animationController, String customMessage) { + mActualStarterOptionalLazy.get().ifPresent( + starter -> starter.postStartActivityDismissingKeyguard(intent, delay, + animationController, customMessage)); + } + + @Override public void postStartActivityDismissingKeyguard(PendingIntent intent, ActivityLaunchAnimator.Controller animationController) { mActualStarterOptionalLazy.get().ifPresent( @@ -161,4 +169,12 @@ public class ActivityStarterDelegate implements ActivityStarter { mActualStarterOptionalLazy.get().ifPresent( starter -> starter.dismissKeyguardThenExecute(action, cancel, afterKeyguardGone)); } + + @Override + public void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel, + boolean afterKeyguardGone, String customMessage) { + mActualStarterOptionalLazy.get().ifPresent( + starter -> starter.dismissKeyguardThenExecute(action, cancel, afterKeyguardGone, + customMessage)); + } } diff --git a/packages/SystemUI/src/com/android/systemui/ChooserPinMigration.kt b/packages/SystemUI/src/com/android/systemui/ChooserPinMigration.kt deleted file mode 100644 index 2f03259766c0..000000000000 --- a/packages/SystemUI/src/com/android/systemui/ChooserPinMigration.kt +++ /dev/null @@ -1,140 +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.systemui - -import android.content.ComponentName -import android.content.Context -import android.content.Context.MODE_PRIVATE -import android.content.Intent -import android.content.SharedPreferences -import android.os.Bundle -import android.os.Environment -import android.os.storage.StorageManager -import android.util.Log -import androidx.core.util.Supplier -import com.android.internal.R -import com.android.systemui.broadcast.BroadcastSender -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags -import java.io.File -import javax.inject.Inject - -/** - * Performs a migration of pinned targets to the unbundled chooser if legacy data exists. - * - * Sends an explicit broadcast with the contents of the legacy pin preferences. The broadcast is - * protected by the RECEIVE_CHOOSER_PIN_MIGRATION permission. This class requires the - * ADD_CHOOSER_PINS permission in order to be able to send this broadcast. - */ -class ChooserPinMigration -@Inject -constructor( - private val context: Context, - private val featureFlags: FeatureFlags, - private val broadcastSender: BroadcastSender, - legacyPinPrefsFileSupplier: LegacyPinPrefsFileSupplier, -) : CoreStartable { - - private val legacyPinPrefsFile = legacyPinPrefsFileSupplier.get() - private val chooserComponent = - ComponentName.unflattenFromString( - context.resources.getString(R.string.config_chooserActivity) - ) - - override fun start() { - if (migrationIsRequired()) { - doMigration() - } - } - - private fun migrationIsRequired(): Boolean { - return featureFlags.isEnabled(Flags.CHOOSER_MIGRATION_ENABLED) && - legacyPinPrefsFile.exists() && - chooserComponent?.packageName != null - } - - private fun doMigration() { - Log.i(TAG, "Beginning migration") - - val legacyPinPrefs = context.getSharedPreferences(legacyPinPrefsFile, MODE_PRIVATE) - - if (legacyPinPrefs.all.isEmpty()) { - Log.i(TAG, "No data to migrate, deleting legacy file") - } else { - sendSharedPreferences(legacyPinPrefs) - Log.i(TAG, "Legacy data sent, deleting legacy preferences") - - val legacyPinPrefsEditor = legacyPinPrefs.edit() - legacyPinPrefsEditor.clear() - if (!legacyPinPrefsEditor.commit()) { - Log.e(TAG, "Failed to delete legacy preferences") - return - } - } - - if (!legacyPinPrefsFile.delete()) { - Log.e(TAG, "Legacy preferences deleted, but failed to delete legacy preferences file") - return - } - - Log.i(TAG, "Legacy preference deletion complete") - } - - private fun sendSharedPreferences(sharedPreferences: SharedPreferences) { - val bundle = Bundle() - - sharedPreferences.all.entries.forEach { (key, value) -> - when (value) { - is Boolean -> bundle.putBoolean(key, value) - else -> Log.e(TAG, "Unsupported preference type for $key: ${value?.javaClass}") - } - } - - sendBundle(bundle) - } - - private fun sendBundle(bundle: Bundle) { - val intent = - Intent().apply { - `package` = chooserComponent?.packageName!! - action = BROADCAST_ACTION - putExtras(bundle) - } - broadcastSender.sendBroadcast(intent, BROADCAST_PERMISSION) - } - - companion object { - private const val TAG = "PinnedShareTargetMigration" - private const val BROADCAST_ACTION = "android.intent.action.CHOOSER_PIN_MIGRATION" - private const val BROADCAST_PERMISSION = "android.permission.RECEIVE_CHOOSER_PIN_MIGRATION" - - class LegacyPinPrefsFileSupplier @Inject constructor(private val context: Context) : - Supplier<File> { - - override fun get(): File { - val packageDirectory = - Environment.getDataUserCePackageDirectory( - StorageManager.UUID_PRIVATE_INTERNAL, - context.userId, - context.packageName, - ) - val sharedPrefsDirectory = File(packageDirectory, "shared_prefs") - return File(sharedPrefsDirectory, "chooser_pin_settings.xml") - } - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt index 179eb391af4e..a3e7d71a92f6 100644 --- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt @@ -35,6 +35,7 @@ import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.settingslib.Utils import com.android.systemui.animation.Interpolators +import com.android.systemui.biometrics.AuthController import com.android.systemui.log.ScreenDecorationsLogger import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.util.asIndenting @@ -52,6 +53,7 @@ class FaceScanningOverlay( val keyguardUpdateMonitor: KeyguardUpdateMonitor, val mainExecutor: Executor, val logger: ScreenDecorationsLogger, + val authController: AuthController, ) : ScreenDecorations.DisplayCutoutView(context, pos) { private var showScanningAnim = false private val rimPaint = Paint() @@ -102,7 +104,9 @@ class FaceScanningOverlay( } override fun enableShowProtection(show: Boolean) { - val showScanningAnimNow = keyguardUpdateMonitor.isFaceDetectionRunning && show + val animationRequired = + keyguardUpdateMonitor.isFaceDetectionRunning || authController.isShowing + val showScanningAnimNow = animationRequired && show if (showScanningAnimNow == showScanningAnim) { return } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index 12b5705190d9..f3c71da63594 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -210,8 +210,8 @@ public class SystemActions implements CoreStartable { // Saving in instance variable since to prevent GC since // NotificationShadeWindowController.registerCallback() only keeps weak references. mNotificationShadeCallback = - (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded, - isDreaming) -> + (keyguardShowing, keyguardOccluded, keyguardGoingAway, bouncerShowing, mDozing, + panelExpanded, isDreaming) -> registerOrUnregisterDismissNotificationShadeAction(); mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index e42f051bf3bb..517f94fbe938 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -637,6 +637,7 @@ public class AuthContainerView extends LinearLayout @Override public void onDetachedFromWindow() { + mPanelInteractionDetector.disable(); OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher(); if (dispatcher != null) { findOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mBackCallback); @@ -674,7 +675,6 @@ public class AuthContainerView extends LinearLayout @Override public void dismissWithoutCallback(boolean animate) { - mPanelInteractionDetector.disable(); if (animate) { animateAway(false /* sendReason */, 0 /* reason */); } else { @@ -685,7 +685,6 @@ public class AuthContainerView extends LinearLayout @Override public void dismissFromSystemServer() { - mPanelInteractionDetector.disable(); animateAway(false /* sendReason */, 0 /* reason */); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 92344dbbfe15..09992290a9ad 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -1005,9 +1005,11 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, * 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; + if (mFpProps != null) { + for (FingerprintSensorPropertiesInternal prop: mFpProps) { + if (prop.sensorType == TYPE_REAR) { + return true; + } } } return false; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt index d15a2afa0d4a..b72801d3b5fe 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt @@ -30,6 +30,7 @@ constructor( @MainThread fun disable() { if (action != null) { + Log.i(TAG, "Disable dectector") action = null shadeExpansionStateManager.removeExpansionListener(this::onPanelExpansionChanged) } @@ -39,8 +40,8 @@ constructor( private fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) = mainExecutor.execute { action?.let { - if (event.tracking || event.expanded) { - Log.v(TAG, "Detected panel interaction, event: $event") + if (event.tracking || (event.expanded && event.fraction > 0)) { + Log.i(TAG, "Detected panel interaction, event: $event") it.onPanelInteraction.run() disable() } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt index eb5d23a23abb..4319f01bed14 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt @@ -144,8 +144,7 @@ constructor( orientationListener.enable() } } - @VisibleForTesting - internal var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT + @VisibleForTesting var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT private val overlayViewParams = WindowManager.LayoutParams( @@ -297,7 +296,7 @@ constructor( } @VisibleForTesting - internal fun updateOverlayParams(display: Display, bounds: Rect) { + fun updateOverlayParams(display: Display, bounds: Rect) { val isNaturalOrientation = display.isNaturalOrientation() val isDefaultOrientation = if (isReverseDefaultRotation) !isNaturalOrientation else isNaturalOrientation diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index ac30311e1f96..7a237591a212 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -83,6 +83,7 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.FalsingManager; @@ -151,6 +152,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { @NonNull private final DumpManager mDumpManager; @NonNull private final SystemUIDialogManager mDialogManager; @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @NonNull private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; @NonNull private final VibratorHelper mVibrator; @NonNull private final FeatureFlags mFeatureFlags; @NonNull private final FalsingManager mFalsingManager; @@ -563,6 +565,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { (TouchProcessorResult.ProcessedTouch) result; final NormalizedTouchData data = processedTouch.getTouchData(); + boolean shouldPilfer = false; mActivePointerId = processedTouch.getPointerOnSensorId(); switch (processedTouch.getEvent()) { case DOWN: @@ -581,8 +584,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { mStatusBarStateController.isDozing()); // Pilfer if valid overlap, don't allow following events to reach keyguard - mInputManager.pilferPointers( - mOverlay.getOverlayView().getViewRootImpl().getInputToken()); + shouldPilfer = true; break; case UP: @@ -621,6 +623,12 @@ public class UdfpsController implements DozeReceiver, Dumpable { // Always pilfer pointers that are within sensor area or when alternate bouncer is showing if (isWithinSensorArea(mOverlay.getOverlayView(), event.getRawX(), event.getRawY(), true) || mAlternateBouncerInteractor.isVisibleState()) { + shouldPilfer = true; + } + + // Execute the pilfer, never pilfer if a vertical swipe is in progress + if (shouldPilfer && mLockscreenShadeTransitionController.getQSDragProgress() == 0f + && !mPrimaryBouncerInteractor.isInTransit()) { mInputManager.pilferPointers( mOverlay.getOverlayView().getViewRootImpl().getInputToken()); } @@ -812,7 +820,8 @@ public class UdfpsController implements DozeReceiver, Dumpable { @NonNull AlternateBouncerInteractor alternateBouncerInteractor, @NonNull SecureSettings secureSettings, @NonNull InputManager inputManager, - @NonNull UdfpsUtils udfpsUtils) { + @NonNull UdfpsUtils udfpsUtils, + @NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor) { mContext = context; mExecution = execution; mVibrator = vibrator; @@ -876,6 +885,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { } return Unit.INSTANCE; }); + mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor; final UdfpsOverlayController mUdfpsOverlayController = new UdfpsOverlayController(); mFingerprintManager.setUdfpsOverlayController(mUdfpsOverlayController); @@ -1135,6 +1145,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { if (!mOnFingerDown) { playStartHaptic(); + mKeyguardFaceAuthInteractor.onUdfpsSensorTouched(); if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) { mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt index 5101ad4c94bc..3b50bbcd9251 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt @@ -257,7 +257,7 @@ constructor( } @VisibleForTesting - internal suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job { + suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job { return scope.launch { primaryBouncerInteractor.bouncerExpansion.collect { bouncerExpansion: Float -> inputBouncerExpansion = bouncerExpansion @@ -268,7 +268,7 @@ constructor( } @VisibleForTesting - internal suspend fun listenForAlternateBouncerVisibility(scope: CoroutineScope): Job { + suspend fun listenForAlternateBouncerVisibility(scope: CoroutineScope): Job { return scope.launch { alternateBouncerInteractor.isVisible.collect { isVisible: Boolean -> showUdfpsBouncer(isVisible) diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java index 25b1e3a8eed2..83e61d69e4f3 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java @@ -155,8 +155,7 @@ public class BroadcastDialog extends SystemUIDialog { } @Override - public void onStart() { - super.onStart(); + public void start() { registerBroadcastCallBack(mExecutor, mBroadcastCallback); } @@ -200,8 +199,7 @@ public class BroadcastDialog extends SystemUIDialog { } @Override - public void onStop() { - super.onStop(); + public void stop() { unregisterBroadcastCallBack(mBroadcastCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt index f9613d505d87..f47275f8f850 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt @@ -24,16 +24,13 @@ class BroadcastSender @Inject constructor( @Background private val bgExecutor: Executor ) { - private val WAKE_LOCK_TAG = "SysUI:BroadcastSender" - private val WAKE_LOCK_SEND_REASON = "sendInBackground" - /** * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking * synchronous binder call. */ @AnyThread fun sendBroadcast(intent: Intent) { - sendInBackground { + sendInBackground("$intent") { context.sendBroadcast(intent) } } @@ -44,7 +41,7 @@ class BroadcastSender @Inject constructor( */ @AnyThread fun sendBroadcast(intent: Intent, receiverPermission: String?) { - sendInBackground { + sendInBackground("$intent") { context.sendBroadcast(intent, receiverPermission) } } @@ -55,7 +52,7 @@ class BroadcastSender @Inject constructor( */ @AnyThread fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle) { - sendInBackground { + sendInBackground("$intent") { context.sendBroadcastAsUser(intent, userHandle) } } @@ -66,7 +63,7 @@ class BroadcastSender @Inject constructor( */ @AnyThread fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle, receiverPermission: String?) { - sendInBackground { + sendInBackground("$intent") { context.sendBroadcastAsUser(intent, userHandle, receiverPermission) } } @@ -82,7 +79,7 @@ class BroadcastSender @Inject constructor( receiverPermission: String?, options: Bundle? ) { - sendInBackground { + sendInBackground("$intent") { context.sendBroadcastAsUser(intent, userHandle, receiverPermission, options) } } @@ -98,7 +95,7 @@ class BroadcastSender @Inject constructor( receiverPermission: String?, appOp: Int ) { - sendInBackground { + sendInBackground("$intent") { context.sendBroadcastAsUser(intent, userHandle, receiverPermission, appOp) } } @@ -108,7 +105,7 @@ class BroadcastSender @Inject constructor( */ @AnyThread fun closeSystemDialogs() { - sendInBackground { + sendInBackground("closeSystemDialogs") { context.closeSystemDialogs() } } @@ -116,17 +113,21 @@ class BroadcastSender @Inject constructor( /** * Dispatches parameter on background executor while holding a wakelock. */ - private fun sendInBackground(callable: () -> Unit) { + private fun sendInBackground(reason: String, callable: () -> Unit) { val broadcastWakelock = wakeLockBuilder.setTag(WAKE_LOCK_TAG) .setMaxTimeout(5000) .build() - broadcastWakelock.acquire(WAKE_LOCK_SEND_REASON) + broadcastWakelock.acquire(reason) bgExecutor.execute { try { callable.invoke() } finally { - broadcastWakelock.release(WAKE_LOCK_SEND_REASON) + broadcastWakelock.release(reason) } } } + + companion object { + private const val WAKE_LOCK_TAG = "SysUI:BroadcastSender" + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index f6b71336675f..691017b220f8 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -324,10 +324,6 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseLongTap(@Penalty int penalty) { - if (!mFeatureFlags.isEnabled(Flags.FALSING_FOR_LONG_TAPS)) { - return false; - } - checkDestroyed(); if (skipFalsing(GENERIC)) { diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java index edda87527b1d..63b4288ce055 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java @@ -21,7 +21,6 @@ import static android.content.ClipDescription.CLASSIFICATION_COMPLETE; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN; -import static com.android.systemui.flags.Flags.CLIPBOARD_MINIMIZED_LAYOUT; import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE; @@ -36,7 +35,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.flags.FeatureFlags; import javax.inject.Inject; import javax.inject.Provider; @@ -59,7 +57,6 @@ public class ClipboardListener implements private final Provider<ClipboardOverlayController> mOverlayProvider; private final ClipboardToast mClipboardToast; private final ClipboardManager mClipboardManager; - private final FeatureFlags mFeatureFlags; private final UiEventLogger mUiEventLogger; private ClipboardOverlay mClipboardOverlay; @@ -68,13 +65,11 @@ public class ClipboardListener implements Provider<ClipboardOverlayController> clipboardOverlayControllerProvider, ClipboardToast clipboardToast, ClipboardManager clipboardManager, - FeatureFlags featureFlags, UiEventLogger uiEventLogger) { mContext = context; mOverlayProvider = clipboardOverlayControllerProvider; mClipboardToast = clipboardToast; mClipboardManager = clipboardManager; - mFeatureFlags = featureFlags; mUiEventLogger = uiEventLogger; } @@ -113,11 +108,7 @@ public class ClipboardListener implements } else { mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource); } - if (mFeatureFlags.isEnabled(CLIPBOARD_MINIMIZED_LAYOUT)) { - mClipboardOverlay.setClipData(clipData, clipSource); - } else { - mClipboardOverlay.setClipDataLegacy(clipData, clipSource); - } + mClipboardOverlay.setClipData(clipData, clipSource); mClipboardOverlay.setOnSessionCompleteListener(() -> { // Session is complete, free memory until it's needed again. mClipboardOverlay = null; @@ -160,8 +151,6 @@ public class ClipboardListener implements } interface ClipboardOverlay { - void setClipDataLegacy(ClipData clipData, String clipSource); - void setClipData(ClipData clipData, String clipSource); void setOnSessionCompleteListener(Runnable runnable); diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java index e6affb06cacc..5230159aaef4 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java @@ -32,7 +32,6 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT; -import static com.android.systemui.flags.Flags.CLIPBOARD_MINIMIZED_LAYOUT; import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR; import android.animation.Animator; @@ -40,20 +39,14 @@ import android.animation.AnimatorListenerAdapter; import android.app.RemoteAction; import android.content.BroadcastReceiver; import android.content.ClipData; -import android.content.ClipDescription; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.graphics.Bitmap; import android.hardware.input.InputManager; import android.net.Uri; import android.os.Looper; import android.provider.DeviceConfig; -import android.text.TextUtils; -import android.util.Log; -import android.util.Size; import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.InputMonitor; @@ -72,7 +65,6 @@ import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.screenshot.TimeoutHandler; -import java.io.IOException; import java.util.Optional; import java.util.concurrent.Executor; @@ -170,9 +162,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv @Override public void onMinimizedViewTapped() { - if (mFeatureFlags.isEnabled(CLIPBOARD_MINIMIZED_LAYOUT)) { - animateFromMinimized(); - } + animateFromMinimized(); } }; @@ -255,11 +245,9 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv @VisibleForTesting void onInsetsChanged(WindowInsets insets, int orientation) { mView.setInsets(insets, orientation); - if (mFeatureFlags.isEnabled(CLIPBOARD_MINIMIZED_LAYOUT)) { - if (shouldShowMinimized(insets) && !mIsMinimized) { - mIsMinimized = true; - mView.setMinimized(true); - } + if (shouldShowMinimized(insets) && !mIsMinimized) { + mIsMinimized = true; + mView.setMinimized(true); } } @@ -401,61 +389,6 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv }); } - @Override // ClipboardListener.ClipboardOverlay - public void setClipDataLegacy(ClipData clipData, String clipSource) { - if (mExitAnimator != null && mExitAnimator.isRunning()) { - mExitAnimator.cancel(); - } - reset(); - mClipboardLogger.setClipSource(clipSource); - String accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied); - - boolean isSensitive = clipData != null && clipData.getDescription().getExtras() != null - && clipData.getDescription().getExtras() - .getBoolean(ClipDescription.EXTRA_IS_SENSITIVE); - boolean isRemote = mFeatureFlags.isEnabled(CLIPBOARD_REMOTE_BEHAVIOR) - && mClipboardUtils.isRemoteCopy(mContext, clipData, clipSource); - if (clipData == null || clipData.getItemCount() == 0) { - mView.showDefaultTextPreview(); - } else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) { - ClipData.Item item = clipData.getItemAt(0); - if (isRemote || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) { - if (item.getTextLinks() != null) { - classifyText(clipData.getItemAt(0), clipSource); - } - } - if (isSensitive) { - showEditableText(mContext.getString(R.string.clipboard_asterisks), true); - } else { - showEditableText(item.getText(), false); - } - mOnShareTapped = () -> shareContent(clipData); - mView.showShareChip(); - accessibilityAnnouncement = mContext.getString(R.string.clipboard_text_copied); - } else if (clipData.getItemAt(0).getUri() != null) { - if (tryShowEditableImage(clipData.getItemAt(0).getUri(), isSensitive)) { - accessibilityAnnouncement = mContext.getString(R.string.clipboard_image_copied); - } - mOnShareTapped = () -> shareContent(clipData); - mView.showShareChip(); - } else { - mView.showDefaultTextPreview(); - } - if (!isRemote) { - maybeShowRemoteCopy(clipData); - } - animateIn(); - mView.announceForAccessibility(accessibilityAnnouncement); - if (isRemote) { - mTimeoutHandler.cancelTimeout(); - mOnUiUpdate = null; - } else { - mOnUiUpdate = mTimeoutHandler::resetTimeout; - mOnUiUpdate.run(); - } - } - private void maybeShowRemoteCopy(ClipData clipData) { Intent remoteCopyIntent = IntentCreator.getRemoteCopyIntent(clipData, mContext); // Only show remote copy if it's available. @@ -478,22 +411,6 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv mOnSessionCompleteListener = runnable; } - private void classifyText(ClipData.Item item, String source) { - mBgExecutor.execute(() -> { - Optional<RemoteAction> action = mClipboardUtils.getAction(item, source); - mView.post(() -> { - mView.resetActionChips(); - action.ifPresent(remoteAction -> { - mView.setActionChip(remoteAction, () -> { - mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED); - animateOut(); - }); - mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN); - }); - }); - }); - } - private void monitorOutsideTouches() { InputManager inputManager = mContext.getSystemService(InputManager.class); mInputMonitor = inputManager.monitorGestureInput("clipboard overlay", 0); @@ -534,43 +451,6 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv animateOut(); } - private void showEditableText(CharSequence text, boolean hidden) { - mView.showTextPreview(text.toString(), hidden); - mView.setEditAccessibilityAction(true); - mOnPreviewTapped = this::editText; - } - - private boolean tryShowEditableImage(Uri uri, boolean isSensitive) { - Runnable listener = () -> editImage(uri); - ContentResolver resolver = mContext.getContentResolver(); - String mimeType = resolver.getType(uri); - boolean isEditableImage = mimeType != null && mimeType.startsWith("image"); - if (isSensitive) { - mView.showImagePreview(null); - if (isEditableImage) { - mOnPreviewTapped = listener; - mView.setEditAccessibilityAction(true); - } - } else if (isEditableImage) { // if the MIMEtype is image, try to load - try { - int size = mContext.getResources().getDimensionPixelSize(R.dimen.overlay_x_scale); - // The width of the view is capped, height maintains aspect ratio, so allow it to be - // taller if needed. - Bitmap thumbnail = resolver.loadThumbnail(uri, new Size(size, size * 4), null); - mView.showImagePreview(thumbnail); - mView.setEditAccessibilityAction(true); - mOnPreviewTapped = listener; - } catch (IOException e) { - Log.e(TAG, "Thumbnail loading failed", e); - mView.showDefaultTextPreview(); - isEditableImage = false; - } - } else { - mView.showDefaultTextPreview(); - } - return isEditableImage; - } - private void animateIn() { if (mEnterAnimator != null && mEnterAnimator.isRunning()) { return; diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java index 25caaeac2c38..758a6563323e 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java @@ -88,25 +88,4 @@ class ClipboardOverlayUtils { } return actions; } - - public Optional<RemoteAction> getAction(ClipData.Item item, String source) { - return getActions(item).stream().filter(remoteAction -> { - ComponentName component = remoteAction.getActionIntent().getIntent().getComponent(); - return component != null && !TextUtils.equals(source, component.getPackageName()); - }).findFirst(); - } - - private ArrayList<RemoteAction> getActions(ClipData.Item item) { - ArrayList<RemoteAction> actions = new ArrayList<>(); - for (TextLinks.TextLink link : item.getTextLinks().getLinks()) { - // skip classification for incidental entities - if (link.getEnd() - link.getStart() - >= item.getText().length() * MINIMUM_ENTITY_PROPORTION) { - TextClassification classification = mTextClassifier.classifyText( - item.getText(), link.getStart(), link.getEnd(), null); - actions.addAll(classification.getActions()); - } - } - return actions; - } } diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt index 6a6c3eb05399..0869351e727b 100644 --- a/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt +++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt @@ -16,10 +16,10 @@ package com.android.systemui.common.shared.model -import androidx.annotation.ColorRes +import androidx.annotation.AttrRes /** Models an icon with a specific tint. */ data class TintedIcon( val icon: Icon, - @ColorRes val tint: Int?, + @AttrRes val tint: Int?, ) diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/TintedIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TintedIconViewBinder.kt index bcc5932dcf30..5c5723fa0a5e 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/TintedIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TintedIconViewBinder.kt @@ -17,6 +17,7 @@ package com.android.systemui.common.ui.binder import android.widget.ImageView +import com.android.settingslib.Utils import com.android.systemui.common.shared.model.TintedIcon object TintedIconViewBinder { @@ -33,7 +34,7 @@ object TintedIconViewBinder { IconViewBinder.bind(tintedIcon.icon, view) view.imageTintList = if (tintedIcon.tint != null) { - view.resources.getColorStateList(tintedIcon.tint, view.context.theme) + Utils.getColorAttr(view.context, tintedIcon.tint) } else { null } diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/MotionEventExt.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/MotionEventExt.kt new file mode 100644 index 000000000000..81ed07653f26 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/MotionEventExt.kt @@ -0,0 +1,36 @@ +/* + * 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.common.ui.view + +import android.util.MathUtils +import android.view.MotionEvent + +/** + * Returns the distance from the raw position of this [MotionEvent] and the given coordinates. + * Because this is all expected to be in the coordinate space of the display and not the view, + * applying mutations to the view (such as scaling animations) does not affect the distance + * measured. + * @param xOnDisplay the x coordinate relative to the display + * @param yOnDisplay the y coordinate relative to the display + * @return distance from the raw position of this [MotionEvent] and the given coordinates + */ +fun MotionEvent.rawDistanceFrom( + xOnDisplay: Float, + yOnDisplay: Float, +): Float { + return MathUtils.dist(this.rawX, this.rawY, xOnDisplay, yOnDisplay) +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java b/packages/SystemUI/src/com/android/systemui/complication/Complication.java index b07efdfff5f2..6b0675204506 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java +++ b/packages/SystemUI/src/com/android/systemui/complication/Complication.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import android.annotation.IntDef; import android.view.View; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationCollectionLiveData.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationCollectionLiveData.java index f6fe8d2e579c..ac38b8dcc2c5 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationCollectionLiveData.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationCollectionLiveData.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import androidx.lifecycle.LiveData; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationCollectionViewModel.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationCollectionViewModel.java index 7190d7a0190a..5e3b14e72e90 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationCollectionViewModel.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationCollectionViewModel.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import androidx.lifecycle.LiveData; import androidx.lifecycle.Transformations; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationHostViewController.java index aad209090a21..8527dcb3794f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationHostViewController.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; -import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT; -import static com.android.systemui.dreams.complication.dagger.ComplicationModule.SCOPED_COMPLICATIONS_MODEL; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT; +import static com.android.systemui.complication.dagger.ComplicationModule.SCOPED_COMPLICATIONS_MODEL; import android.graphics.Rect; import android.graphics.Region; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationId.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationId.java index 420359c46b54..d7bdce3bbe2e 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationId.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationId.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; /** * A {@link ComplicationId} is a value to uniquely identify a complication during the current diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java index 3e9b0103470c..e82564dc8a89 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; -import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_IN_DURATION; -import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DURATION; -import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_DEFAULT; -import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_IN_DURATION; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DURATION; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_DEFAULT; +import static com.android.systemui.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT; import android.util.Log; import android.view.View; @@ -29,8 +29,8 @@ import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.Constraints; import com.android.systemui.R; -import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position; -import com.android.systemui.dreams.complication.dagger.ComplicationModule; +import com.android.systemui.complication.ComplicationLayoutParams.Position; +import com.android.systemui.complication.dagger.ComplicationModule; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.touch.TouchInsetManager; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutParams.java index 99e19fc96d8f..71ba720a9589 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutParams.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import android.annotation.IntDef; import android.view.ViewGroup; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationTypesUpdater.java index 1702eac6d02a..016891df4b3b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationTypesUpdater.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationUtils.java index 18aacd21bd12..183053a1bb1c 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationUtils.java @@ -14,17 +14,17 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_AIR_QUALITY; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_CAST_INFO; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_DATE; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_HOME_CONTROLS; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_MEDIA_ENTRY; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_NONE; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_SMARTSPACE; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_TIME; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_WEATHER; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_AIR_QUALITY; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_CAST_INFO; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_DATE; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_HOME_CONTROLS; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_MEDIA_ENTRY; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_NONE; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_SMARTSPACE; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_TIME; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_WEATHER; import com.android.settingslib.dream.DreamBackend; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationViewModel.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationViewModel.java index 00cf58c0c665..61b948e1cce5 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationViewModel.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationViewModel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import androidx.lifecycle.ViewModel; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationViewModelProvider.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationViewModelProvider.java index cc17ea1ee7b9..2287171015fb 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationViewModelProvider.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationViewModelProvider.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelStore; -import com.android.systemui.dreams.complication.dagger.DaggerViewModelProviderFactory; +import com.android.systemui.complication.dagger.DaggerViewModelProviderFactory; import javax.inject.Inject; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationViewModelTransformer.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationViewModelTransformer.java index 5d113dde624e..482bbec067e2 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationViewModelTransformer.java +++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationViewModelTransformer.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; -import com.android.systemui.dreams.complication.dagger.ComplicationViewModelComponent; +import com.android.systemui.complication.dagger.ComplicationViewModelComponent; import java.util.HashMap; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamClockTimeComplication.java index bb1e6e2ef06d..5020480f8d60 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java +++ b/packages/SystemUI/src/com/android/systemui/complication/DreamClockTimeComplication.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; -import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW; -import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS; +import static com.android.systemui.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW; +import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.view.View; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java index 82a885892b75..8f192de8c4a5 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java +++ b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; +import static com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent.DreamHomeControlsModule.DREAM_HOME_CONTROLS_CHIP_VIEW; +import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS; import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE; import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK; import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.UNAVAILABLE; -import static com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent.DreamHomeControlsModule.DREAM_HOME_CONTROLS_CHIP_VIEW; -import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.content.Context; @@ -34,13 +34,13 @@ import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.systemui.CoreStartable; import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.controls.ControlsServiceInfo; import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.controls.management.ControlsListingController; import com.android.systemui.controls.ui.ControlsActivity; import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.shared.condition.Monitor; import com.android.systemui.util.ViewController; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamMediaEntryComplication.java index deff0608bedd..6a7278529a54 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java +++ b/packages/SystemUI/src/com/android/systemui/complication/DreamMediaEntryComplication.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; -import static com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent.DreamMediaEntryModule.DREAM_MEDIA_ENTRY_VIEW; -import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_ENTRY_LAYOUT_PARAMS; +import static com.android.systemui.complication.dagger.DreamMediaEntryComplicationComponent.DreamMediaEntryModule.DREAM_MEDIA_ENTRY_VIEW; +import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_ENTRY_LAYOUT_PARAMS; import static com.android.systemui.flags.Flags.DREAM_MEDIA_TAP_TO_OPEN; import android.app.PendingIntent; @@ -25,8 +25,8 @@ import android.util.Log; import android.view.View; import com.android.systemui.ActivityIntentHelper; +import com.android.systemui.complication.dagger.DreamMediaEntryComplicationComponent; import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.controls.ui.MediaCarouselController; import com.android.systemui.media.dream.MediaDreamComplication; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/complication/SmartSpaceComplication.java index ff1f31245570..2f5ef6da6912 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java +++ b/packages/SystemUI/src/com/android/systemui/complication/SmartSpaceComplication.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; -import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_SMARTSPACE_LAYOUT_PARAMS; +import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_SMARTSPACE_LAYOUT_PARAMS; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.content.Context; diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationComponent.kt b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationComponent.kt new file mode 100644 index 000000000000..018914772f57 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationComponent.kt @@ -0,0 +1,29 @@ +package com.android.systemui.complication.dagger + +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ViewModelStore +import com.android.systemui.complication.Complication +import com.android.systemui.complication.ComplicationHostViewController +import com.android.systemui.complication.ComplicationLayoutEngine +import com.android.systemui.touch.TouchInsetManager +import dagger.BindsInstance +import dagger.Subcomponent + +@Subcomponent(modules = [ComplicationModule::class]) +@ComplicationModule.ComplicationScope +interface ComplicationComponent { + /** Factory for generating [ComplicationComponent]. */ + @Subcomponent.Factory + interface Factory { + fun create( + @BindsInstance lifecycleOwner: LifecycleOwner, + @BindsInstance host: Complication.Host, + @BindsInstance viewModelStore: ViewModelStore, + @BindsInstance touchInsetManager: TouchInsetManager + ): ComplicationComponent + } + + fun getComplicationHostViewController(): ComplicationHostViewController + + fun getVisibilityController(): ComplicationLayoutEngine +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java index 797906fbaf8e..1158565b9c37 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication.dagger; +package com.android.systemui.complication.dagger; import android.content.res.Resources; import android.view.LayoutInflater; @@ -44,7 +44,7 @@ public abstract class ComplicationHostViewModule { /** * Generates a {@link ConstraintLayout}, which can host - * {@link com.android.systemui.dreams.complication.Complication} instances. + * {@link com.android.systemui.complication.Complication} instances. */ @Provides @Named(SCOPED_COMPLICATIONS_LAYOUT) diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationModule.java index dbf5ab000a8a..57841af28c09 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationModule.java @@ -14,16 +14,16 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication.dagger; +package com.android.systemui.complication.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelStore; -import com.android.systemui.dreams.complication.Complication; -import com.android.systemui.dreams.complication.ComplicationCollectionViewModel; -import com.android.systemui.dreams.complication.ComplicationLayoutEngine; +import com.android.systemui.complication.Complication; +import com.android.systemui.complication.ComplicationCollectionViewModel; +import com.android.systemui.complication.ComplicationLayoutEngine; import com.android.systemui.touch.TouchInsetManager; import dagger.Module; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationViewModelComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationViewModelComponent.java index 703cd28a3c25..d2d36985e478 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationViewModelComponent.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationViewModelComponent.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication.dagger; +package com.android.systemui.complication.dagger; -import com.android.systemui.dreams.complication.Complication; -import com.android.systemui.dreams.complication.ComplicationId; -import com.android.systemui.dreams.complication.ComplicationViewModelProvider; +import com.android.systemui.complication.Complication; +import com.android.systemui.complication.ComplicationId; +import com.android.systemui.complication.ComplicationViewModelProvider; import dagger.BindsInstance; import dagger.Subcomponent; /** * The {@link ComplicationViewModelComponent} allows for a - * {@link com.android.systemui.dreams.complication.ComplicationViewModel} for a particular + * {@link com.android.systemui.complication.ComplicationViewModel} for a particular * {@link Complication}. This component binds these instance specific values to allow injection with * values provided at the wider scope. */ diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DaggerViewModelProviderFactory.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DaggerViewModelProviderFactory.java index 8ffedec9b492..b4ec40fc7761 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DaggerViewModelProviderFactory.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DaggerViewModelProviderFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication.dagger; +package com.android.systemui.complication.dagger; import androidx.annotation.NonNull; import androidx.lifecycle.ViewModel; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamClockTimeComplicationModule.java index 5290e44aa7fb..fd711eed53b8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamClockTimeComplicationModule.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication.dagger; +package com.android.systemui.complication.dagger; import android.view.LayoutInflater; @@ -23,13 +23,13 @@ import android.widget.TextClock; import com.android.internal.util.Preconditions; import com.android.systemui.R; -import com.android.systemui.dreams.complication.DreamClockTimeComplication; - -import javax.inject.Named; +import com.android.systemui.complication.DreamClockTimeComplication; import dagger.Module; import dagger.Provides; +import javax.inject.Named; + /** * Module for providing {@link DreamClockTimeComplication}. */ diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java index cf05d2d9cda0..ef18d660ef36 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication.dagger; +package com.android.systemui.complication.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -22,7 +22,12 @@ import android.view.LayoutInflater; import android.widget.ImageView; import com.android.systemui.R; -import com.android.systemui.dreams.complication.DreamHomeControlsComplication; +import com.android.systemui.complication.DreamHomeControlsComplication; + +import dagger.Module; +import dagger.Provides; +import dagger.Subcomponent; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -30,10 +35,6 @@ import java.lang.annotation.Retention; import javax.inject.Named; import javax.inject.Scope; -import dagger.Module; -import dagger.Provides; -import dagger.Subcomponent; - /** * Responsible for generating dependencies for the {@link DreamHomeControlsComplication}. */ diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamMediaEntryComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamMediaEntryComplicationComponent.java index ed05daf35ed9..f15a5862104f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamMediaEntryComplicationComponent.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamMediaEntryComplicationComponent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication.dagger; +package com.android.systemui.complication.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -22,7 +22,11 @@ import android.view.LayoutInflater; import android.view.View; import com.android.systemui.R; -import com.android.systemui.dreams.complication.DreamMediaEntryComplication; +import com.android.systemui.complication.DreamMediaEntryComplication; + +import dagger.Module; +import dagger.Provides; +import dagger.Subcomponent; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -30,10 +34,6 @@ import java.lang.annotation.Retention; import javax.inject.Named; import javax.inject.Scope; -import dagger.Module; -import dagger.Provides; -import dagger.Subcomponent; - /** * Responsible for generating dependencies for the {@link DreamMediaEntryComplication}. */ diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java index 3be42cb58f11..98975fbdfce2 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java @@ -14,23 +14,23 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication.dagger; +package com.android.systemui.complication.dagger; import android.content.res.Resources; import android.view.ViewGroup; import com.android.systemui.R; +import com.android.systemui.complication.ComplicationLayoutParams; import com.android.systemui.dagger.SystemUIBinder; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dreams.complication.ComplicationLayoutParams; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; -import javax.inject.Named; - import dagger.Module; import dagger.Provides; +import javax.inject.Named; + /** * Module for all components with corresponding dream layer complications registered in * {@link SystemUIBinder}. diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt index 9e15c7e31127..f17d0f307473 100644 --- a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt @@ -86,13 +86,11 @@ class ContrastDialog( highlightContrast(toContrastLevel(initialContrast)) } - override fun onStart() { - super.onStart() + override fun start() { uiModeManager.addContrastChangeListener(mainExecutor, this) } - override fun onStop() { - super.onStop() + override fun stop() { uiModeManager.removeContrastChangeListener(this) } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsPopupMenu.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsPopupMenu.kt index d08bc48e945d..f7c8e9652e4e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsPopupMenu.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsPopupMenu.kt @@ -20,11 +20,18 @@ import android.content.Context import android.content.res.Resources import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable -import android.view.Gravity +import android.view.Gravity.END +import android.view.Gravity.GravityFlags +import android.view.Gravity.NO_GRAVITY +import android.view.Gravity.START import android.view.View +import android.view.View.MeasureSpec +import android.view.ViewGroup import android.widget.ListPopupWindow +import android.widget.ListView import android.widget.PopupWindow import com.android.systemui.R +import kotlin.math.max class ControlsPopupMenu(context: Context) : ListPopupWindow(context) { @@ -40,13 +47,13 @@ class ControlsPopupMenu(context: Context) : ListPopupWindow(context) { private val dimDrawable: Drawable = ColorDrawable(resources.getColor(R.color.control_popup_dim)) private var dismissListener: PopupWindow.OnDismissListener? = null + @GravityFlags private var dropDownGravity: Int = NO_GRAVITY init { setBackgroundDrawable(dialogBackground) inputMethodMode = INPUT_METHOD_NOT_NEEDED isModal = true - setDropDownGravity(Gravity.START) // dismiss method isn't called when popup is hidden by outside touch. So we need to // override a listener to remove a dimming foreground @@ -59,30 +66,68 @@ class ControlsPopupMenu(context: Context) : ListPopupWindow(context) { override fun show() { // need to call show() first in order to construct the listView super.show() - - val paddedWidth = resources.displayMetrics.widthPixels - 2 * horizontalMargin - width = maxWidth.coerceAtMost(paddedWidth) + updateWidth() anchorView?.let { - horizontalOffset = -width / 2 + it.width / 2 - verticalOffset = -it.height / 2 - if (it.layoutDirection == View.LAYOUT_DIRECTION_RTL) { - horizontalOffset = -horizontalOffset - } - + positionPopup(it) it.rootView.foreground = dimDrawable } - with(listView!!) { clipToOutline = true background = dialogBackground dividerHeight = listDividerHeight } - // actual show takes into account updated ListView specs super.show() } + override fun setDropDownGravity(@GravityFlags gravity: Int) { + super.setDropDownGravity(gravity) + dropDownGravity = gravity + } + override fun setOnDismissListener(listener: PopupWindow.OnDismissListener?) { dismissListener = listener } + + private fun updateWidth() { + val paddedWidth = resources.displayMetrics.widthPixels - 2 * horizontalMargin + val maxWidth = maxWidth.coerceAtMost(paddedWidth) + when (width) { + ViewGroup.LayoutParams.MATCH_PARENT -> { + width = maxWidth + } + ViewGroup.LayoutParams.WRAP_CONTENT -> { + width = listView!!.measureDesiredWidth(maxWidth).coerceAtMost(maxWidth) + } + } + } + + private fun positionPopup(anchorView: View) { + when (dropDownGravity) { + NO_GRAVITY -> { + horizontalOffset = (-width + anchorView.width) / 2 + if (anchorView.layoutDirection == View.LAYOUT_DIRECTION_RTL) { + horizontalOffset = -horizontalOffset + } + } + END, + START -> { + horizontalOffset = 0 + } + } + verticalOffset = -anchorView.height / 2 + } + + private fun ListView.measureDesiredWidth(maxWidth: Int): Int { + var maxItemWidth = 0 + repeat(adapter.count) { + val view = adapter.getView(it, null, listView) + view.measure( + MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST), + MeasureSpec.UNSPECIFIED + ) + maxItemWidth = max(maxItemWidth, view.measuredWidth) + } + return maxItemWidth + } } 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 d4ce9b699619..92607c6101af 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -34,6 +34,7 @@ import android.service.controls.Control import android.service.controls.ControlsProviderService import android.util.Log import android.view.ContextThemeWrapper +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -72,7 +73,6 @@ 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.globalactions.GlobalActionsPopupMenu import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.KeyguardStateController @@ -540,12 +540,12 @@ class ControlsUiControllerImpl @Inject constructor ( val anchor = parent.requireViewById<ImageView>(R.id.controls_more) anchor.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View) { - popup = GlobalActionsPopupMenu( - popupThemedContext, - false /* isDropDownMode */ - ).apply { - setAnchorView(anchor) + popup = ControlsPopupMenu(popupThemedContext).apply { + width = ViewGroup.LayoutParams.WRAP_CONTENT + anchorView = anchor + setDropDownGravity(Gravity.END) setAdapter(adapter) + setOnItemClickListener(object : AdapterView.OnItemClickListener { override fun onItemClick( parent: AdapterView<*>, @@ -618,7 +618,8 @@ class ControlsUiControllerImpl @Inject constructor ( anchor.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View) { popup = ControlsPopupMenu(popupThemedContext).apply { - setAnchorView(anchor) + anchorView = anchor + width = ViewGroup.LayoutParams.MATCH_PARENT setAdapter(adapter) setOnItemClickListener(object : AdapterView.OnItemClickListener { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index df236e7f9c8f..20d690e209af 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -17,7 +17,6 @@ package com.android.systemui.dagger import com.android.keyguard.KeyguardBiometricLockoutLogger -import com.android.systemui.ChooserPinMigration import com.android.systemui.ChooserSelector import com.android.systemui.CoreStartable import com.android.systemui.LatencyTester @@ -49,6 +48,7 @@ import com.android.systemui.settings.dagger.MultiUserUtilsModule import com.android.systemui.shortcut.ShortcutKeyDispatcher import com.android.systemui.statusbar.notification.InstantAppNotifier import com.android.systemui.statusbar.phone.KeyguardLiftController +import com.android.systemui.statusbar.phone.LetterboxModule import com.android.systemui.stylus.StylusUsiPowerStartable import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import com.android.systemui.theme.ThemeOverlayController @@ -67,7 +67,8 @@ import dagger.multibindings.IntoMap */ @Module(includes = [ MultiUserUtilsModule::class, - StartControlsStartableModule::class + StartControlsStartableModule::class, + LetterboxModule::class, ]) abstract class SystemUICoreStartableModule { /** Inject into AuthController. */ @@ -76,13 +77,6 @@ abstract class SystemUICoreStartableModule { @ClassKey(AuthController::class) abstract fun bindAuthController(service: AuthController): CoreStartable - /** Inject into ChooserPinMigration. */ - @Binds - @IntoMap - @ClassKey(ChooserPinMigration::class) - @PerUser - abstract fun bindChooserPinMigration(sysui: ChooserPinMigration): CoreStartable - /** Inject into ChooserCoreStartable. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 63a4fd2189d8..ac916651b9f3 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -38,11 +38,11 @@ import com.android.systemui.biometrics.dagger.BiometricsModule; import com.android.systemui.biometrics.dagger.UdfpsModule; import com.android.systemui.classifier.FalsingModule; import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule; +import com.android.systemui.complication.dagger.ComplicationComponent; import com.android.systemui.controls.dagger.ControlsModule; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.demomode.dagger.DemoModeModule; import com.android.systemui.doze.dagger.DozeComponent; -import com.android.systemui.dreams.complication.dagger.ComplicationComponent; import com.android.systemui.dreams.dagger.DreamModule; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; @@ -85,6 +85,8 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper; +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider; import com.android.systemui.statusbar.notification.people.PeopleHubModule; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; @@ -116,16 +118,16 @@ import com.android.systemui.wallet.dagger.WalletModule; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubbles; -import java.util.Optional; -import java.util.concurrent.Executor; - -import javax.inject.Named; - import dagger.Binds; import dagger.BindsOptionalOf; import dagger.Module; import dagger.Provides; +import java.util.Optional; +import java.util.concurrent.Executor; + +import javax.inject.Named; + /** * A dagger module for injecting components of System UI that are required by System UI. * @@ -315,4 +317,11 @@ public abstract class SystemUIModule { @Binds abstract LargeScreenShadeInterpolator largeScreensShadeInterpolator( LargeScreenShadeInterpolatorImpl impl); + + @SysUISingleton + @Provides + static VisualInterruptionDecisionProvider provideVisualInterruptionDecisionProvider( + NotificationInterruptStateProvider innerProvider) { + return new NotificationInterruptStateProviderWrapper(innerProvider); + } } diff --git a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt index 88c0c50d09a5..4e62104034ee 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt @@ -98,7 +98,8 @@ class FaceScanningProviderFactory @Inject constructor( } fun shouldShowFaceScanningAnim(): Boolean { - return canShowFaceScanningAnim() && keyguardUpdateMonitor.isFaceDetectionRunning + return canShowFaceScanningAnim() && + (keyguardUpdateMonitor.isFaceDetectionRunning || authController.isShowing) } } @@ -142,6 +143,7 @@ class FaceScanningOverlayProviderImpl( keyguardUpdateMonitor, mainExecutor, logger, + authController, ) view.id = viewId view.setColor(tintColor) diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt index d0a92f0846d0..5b56c04ae8aa 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt @@ -26,11 +26,11 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.R import com.android.systemui.animation.Interpolators -import com.android.systemui.dreams.complication.ComplicationHostViewController -import com.android.systemui.dreams.complication.ComplicationLayoutParams -import com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_BOTTOM -import com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_TOP -import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position +import com.android.systemui.complication.ComplicationHostViewController +import com.android.systemui.complication.ComplicationLayoutParams +import com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM +import com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP +import com.android.systemui.complication.ComplicationLayoutParams.Position import com.android.systemui.dreams.dagger.DreamOverlayModule import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.DREAM_ANIMATION_DURATION diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java index 7c6a74864664..15a32d21213f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java @@ -19,9 +19,9 @@ package com.android.systemui.dreams; import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress; import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamAlphaScaledExpansion; import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamYPositionScaledExpansion; +import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM; +import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; -import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_BOTTOM; -import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_TOP; import android.animation.Animator; import android.content.res.Resources; @@ -36,8 +36,8 @@ import androidx.annotation.NonNull; import com.android.dream.lowlight.LowLightTransitionCoordinator; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; +import com.android.systemui.complication.ComplicationHostViewController; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dreams.complication.ComplicationHostViewController; import com.android.systemui.dreams.dagger.DreamOverlayComponent; import com.android.systemui.dreams.dagger.DreamOverlayModule; import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 471c44574893..1da7900e985b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -32,7 +32,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleRegistry; import androidx.lifecycle.ViewModelStore; @@ -42,9 +41,9 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.policy.PhoneWindow; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.systemui.complication.Complication; +import com.android.systemui.complication.dagger.ComplicationComponent; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dreams.complication.Complication; -import com.android.systemui.dreams.complication.dagger.ComplicationComponent; import com.android.systemui.dreams.dagger.DreamOverlayComponent; import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor; import com.android.systemui.touch.TouchInsetManager; @@ -91,7 +90,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ private final ComplicationComponent mComplicationComponent; - private final com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent + private final com.android.systemui.dreams.complication.dagger.ComplicationComponent mDreamComplicationComponent; private final DreamOverlayComponent mDreamOverlayComponent; @@ -145,7 +144,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ @Main DelayableExecutor executor, WindowManager windowManager, ComplicationComponent.Factory complicationComponentFactory, - com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent.Factory + com.android.systemui.dreams.complication.dagger.ComplicationComponent.Factory dreamComplicationComponentFactory, DreamOverlayComponent.Factory dreamOverlayComponentFactory, DreamOverlayStateController stateController, diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java index 779098656ce3..0f370ac62b1f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java @@ -24,9 +24,9 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.complication.Complication; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dreams.complication.Complication; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.policy.CallbackController; @@ -184,6 +184,10 @@ public class DreamOverlayStateController implements * Returns collection of present {@link Complication}. */ public Collection<Complication> getComplications(boolean filterByAvailability) { + if (isLowLightActive()) { + // Don't show complications on low light. + return Collections.emptyList(); + } return Collections.unmodifiableCollection(filterByAvailability ? mComplications .stream() diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/HideComplicationTouchHandler.java index 3a4578b6f744..410a0c53a492 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/HideComplicationTouchHandler.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.systemui.dreams.dreamcomplication; +package com.android.systemui.dreams.complication; -import static com.android.systemui.dreams.dreamcomplication.dagger.ComplicationModule.COMPLICATIONS_FADE_OUT_DELAY; -import static com.android.systemui.dreams.dreamcomplication.dagger.ComplicationModule.COMPLICATIONS_RESTORE_TIMEOUT; +import static com.android.systemui.dreams.complication.dagger.ComplicationModule.COMPLICATIONS_FADE_OUT_DELAY; +import static com.android.systemui.dreams.complication.dagger.ComplicationModule.COMPLICATIONS_RESTORE_TIMEOUT; import android.util.Log; import android.view.MotionEvent; @@ -25,9 +25,9 @@ import android.view.View; import androidx.annotation.Nullable; +import com.android.systemui.complication.Complication; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.dreams.complication.Complication; import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor; import com.android.systemui.dreams.touch.DreamTouchHandler; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt index 8d133bd25275..492c50255b18 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt @@ -1,29 +1,21 @@ package com.android.systemui.dreams.complication.dagger -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.ViewModelStore -import com.android.systemui.dreams.complication.Complication -import com.android.systemui.dreams.complication.ComplicationHostViewController -import com.android.systemui.dreams.complication.ComplicationLayoutEngine +import com.android.systemui.complication.Complication +import com.android.systemui.dreams.complication.HideComplicationTouchHandler import com.android.systemui.touch.TouchInsetManager import dagger.BindsInstance import dagger.Subcomponent @Subcomponent(modules = [ComplicationModule::class]) -@ComplicationModule.ComplicationScope interface ComplicationComponent { /** Factory for generating [ComplicationComponent]. */ @Subcomponent.Factory interface Factory { fun create( - @BindsInstance lifecycleOwner: LifecycleOwner, - @BindsInstance host: Complication.Host, - @BindsInstance viewModelStore: ViewModelStore, + @BindsInstance visibilityController: Complication.VisibilityController, @BindsInstance touchInsetManager: TouchInsetManager ): ComplicationComponent } - fun getComplicationHostViewController(): ComplicationHostViewController - - fun getVisibilityController(): ComplicationLayoutEngine + fun getHideComplicationTouchHandler(): HideComplicationTouchHandler } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationModule.kt b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.kt index ef75ce173e94..95c225de9598 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.kt @@ -1,4 +1,4 @@ -package com.android.systemui.dreams.dreamcomplication.dagger +package com.android.systemui.dreams.complication.dagger import android.content.res.Resources import com.android.systemui.R diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java index f130026b76b4..1271645dac4e 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java @@ -24,12 +24,12 @@ import android.content.res.Resources; import com.android.dream.lowlight.dagger.LowLightDreamModule; import com.android.settingslib.dream.DreamBackend; import com.android.systemui.R; +import com.android.systemui.complication.dagger.RegisteredComplicationsModule; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.DreamOverlayNotificationCountProvider; import com.android.systemui.dreams.DreamOverlayService; -import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule; -import com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent; +import com.android.systemui.dreams.complication.dagger.ComplicationComponent; import com.android.systemui.dreams.touch.scrim.dagger.ScrimModule; import com.android.systemui.process.condition.SystemProcessCondition; import com.android.systemui.shared.condition.Condition; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java index 0332f888c866..cb587c2f96c7 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java @@ -24,8 +24,8 @@ import android.annotation.Nullable; import androidx.lifecycle.LifecycleOwner; +import com.android.systemui.complication.ComplicationHostViewController; import com.android.systemui.dreams.DreamOverlayContainerViewController; -import com.android.systemui.dreams.complication.ComplicationHostViewController; import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor; import com.android.systemui.dreams.touch.DreamTouchHandler; import com.android.systemui.dreams.touch.dagger.DreamTouchModule; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationComponent.kt b/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationComponent.kt deleted file mode 100644 index f2fb48d6240d..000000000000 --- a/packages/SystemUI/src/com/android/systemui/dreams/dreamcomplication/dagger/ComplicationComponent.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.android.systemui.dreams.dreamcomplication.dagger - -import com.android.systemui.dreams.complication.Complication -import com.android.systemui.dreams.dreamcomplication.HideComplicationTouchHandler -import com.android.systemui.touch.TouchInsetManager -import dagger.BindsInstance -import dagger.Subcomponent - -@Subcomponent(modules = [ComplicationModule::class]) -interface ComplicationComponent { - /** Factory for generating [ComplicationComponent]. */ - @Subcomponent.Factory - interface Factory { - fun create( - @BindsInstance visibilityController: Complication.VisibilityController, - @BindsInstance touchInsetManager: TouchInsetManager - ): ComplicationComponent - } - - fun getHideComplicationTouchHandler(): HideComplicationTouchHandler -} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java index 2ea7bce66452..570132e111eb 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java @@ -303,10 +303,6 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { } flingToExpansion(verticalVelocity, expansion); - - if (expansion == KeyguardBouncerConstants.EXPANSION_HIDDEN) { - mCurrentScrimController.reset(); - } break; default: mVelocityTracker.addMovement(motionEvent); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java index 7f44463f1191..aca621bd9e55 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java @@ -41,6 +41,7 @@ import com.google.common.util.concurrent.ListenableFuture; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -195,7 +196,14 @@ public class DreamOverlayTouchMonitor { * Called by the monitor when this session is removed. */ private void onRemoved() { - mCallbacks.forEach(callback -> callback.onRemoved()); + mEventListeners.clear(); + mGestureListeners.clear(); + final Iterator<Callback> iter = mCallbacks.iterator(); + while (iter.hasNext()) { + final Callback callback = iter.next(); + callback.onRemoved(); + iter.remove(); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt index 276a290e22ca..7d1ffca88d9f 100644 --- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt +++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt @@ -39,6 +39,11 @@ open class DumpManager @Inject constructor() { private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap() private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap() + /** See [registerCriticalDumpable]. */ + fun registerCriticalDumpable(module: Dumpable) { + registerCriticalDumpable(module::class.java.simpleName, module) + } + /** * Registers a dumpable to be called during the CRITICAL section of the bug report. * diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 0bc8506f272d..bd982c65369d 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -65,11 +65,7 @@ object Flags { val FSI_ON_DND_UPDATE = releasedFlag(259130119, "fsi_on_dnd_update") // TODO(b/254512538): Tracking Bug - val INSTANT_VOICE_REPLY = releasedFlag(111, "instant_voice_reply") - - // TODO(b/254512425): Tracking Bug - val NOTIFICATION_MEMORY_MONITOR_ENABLED = - releasedFlag(112, "notification_memory_monitor_enabled") + val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply") /** * This flag is server-controlled and should stay as [unreleasedFlag] since we never want to @@ -103,10 +99,10 @@ object Flags { val FILTER_UNSEEN_NOTIFS_ON_KEYGUARD = releasedFlag(254647461, "filter_unseen_notifs_on_keyguard") - // TODO(b/263414400): Tracking Bug + // TODO(b/277338665): Tracking Bug @JvmField - val NOTIFICATION_ANIMATE_BIG_PICTURE = - releasedFlag(120, "notification_animate_big_picture") + val NOTIFICATION_SHELF_REFACTOR = + unreleasedFlag(271161129, "notification_shelf_refactor") @JvmField val ANIMATED_NOTIFICATION_SHADE_INSETS = @@ -132,6 +128,11 @@ object Flags { // TODO(b/254512676): Tracking Bug @JvmField val LOCKSCREEN_CUSTOM_CLOCKS = releasedFlag(207, "lockscreen_custom_clocks") + // TODO(b/275694445): Tracking Bug + @JvmField + val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = unreleasedFlag(208, + "lockscreen_without_secure_lock_when_dreaming") + /** * Whether the clock on a wide lock screen should use the new "stepping" animation for moving * the digits when the clock moves. @@ -230,6 +231,12 @@ object Flags { @JvmField val REFACTOR_KEYGUARD_DISMISS_INTENT = unreleasedFlag(231, "refactor_keyguard_dismiss_intent") + /** Whether to allow long-press on the lock screen to directly open wallpaper picker. */ + // TODO(b/277220285): Tracking bug. + @JvmField + val LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP = + unreleasedFlag(232, "lock_screen_long_press_directly_opens_wallpaper_picker") + // 300 - power menu // TODO(b/254512600): Tracking Bug @JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite") @@ -270,6 +277,10 @@ object Flags { @JvmField val QS_PIPELINE_NEW_HOST = unreleasedFlag(504, "qs_pipeline_new_host", teamfood = false) + // TODO(b/278068252): Tracking Bug + @JvmField + val QS_PIPELINE_AUTO_ADD = unreleasedFlag(505, "qs_pipeline_auto_add", teamfood = false) + // TODO(b/254512383): Tracking Bug @JvmField val FULL_SCREEN_USER_SWITCHER = @@ -395,7 +406,7 @@ object Flags { val MEDIA_RETAIN_RECOMMENDATIONS = releasedFlag(916, "media_retain_recommendations") // TODO(b/270437894): Tracking Bug - val MEDIA_REMOTE_RESUME = unreleasedFlag(917, "media_remote_resume") + val MEDIA_REMOTE_RESUME = unreleasedFlag(917, "media_remote_resume", teamfood = true) // 1000 - dock val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging") @@ -403,9 +414,6 @@ object Flags { // TODO(b/254512758): Tracking Bug @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple") - // TODO(b/270882464): Tracking Bug - val ENABLE_DOCK_SETUP_V2 = releasedFlag(1005, "enable_dock_setup_v2") - // TODO(b/265045965): Tracking Bug val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot") @@ -592,9 +600,6 @@ object Flags { // TODO(b/254512507): Tracking Bug val CHOOSER_UNBUNDLED = releasedFlag(1500, "chooser_unbundled") - // TODO(b/266983432) Tracking Bug - val SHARESHEET_CUSTOM_ACTIONS = releasedFlag(1501, "sharesheet_custom_actions") - // TODO(b/266982749) Tracking Bug val SHARESHEET_RESELECTION_ACTION = releasedFlag(1502, "sharesheet_reselection_action") @@ -605,13 +610,8 @@ object Flags { val SHARESHEET_SCROLLABLE_IMAGE_PREVIEW = releasedFlag(1504, "sharesheet_scrollable_image_preview") - // TODO(b/274137694) Tracking Bug - val CHOOSER_MIGRATION_ENABLED = unreleasedFlag(1505, "chooser_migration_enabled") - // 1700 - clipboard @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior") - // TODO(b/267162944): Tracking bug - @JvmField val CLIPBOARD_MINIMIZED_LAYOUT = releasedFlag(1702, "clipboard_data_model") // 1800 - shade container @JvmField @@ -639,9 +639,6 @@ object Flags { val APP_PANELS_REMOVE_APPS_ALLOWED = unreleasedFlag(2003, "app_panels_remove_apps_allowed", teamfood = true) - // 2100 - Falsing Manager - @JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps") - // 2200 - udfps // TODO(b/259264861): Tracking Bug @JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag(2200, "udfps_new_touch_detection") @@ -696,6 +693,11 @@ object Flags { val KEYBOARD_BACKLIGHT_INDICATOR = unreleasedFlag(2601, "keyboard_backlight_indicator", teamfood = true) + // TODO(b/277192623): Tracking Bug + @JvmField + val KEYBOARD_EDUCATION = + unreleasedFlag(2603, "keyboard_education", teamfood = false) + // TODO(b/272036292): Tracking Bug @JvmField val LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION = diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index 07753ca1e6dc..4be47ecb42d9 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -2477,8 +2477,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene } @Override - protected void onStart() { - super.onStart(); + protected void start() { mGlobalActionsLayout.updateList(); if (mBackgroundDrawable instanceof ScrimDrawable) { @@ -2509,8 +2508,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene } @Override - protected void onStop() { - super.onStop(); + protected void stop() { mColorExtractor.removeOnColorsChangedListener(this); } diff --git a/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt b/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt index 801b1652e487..c41b5e4d319b 100644 --- a/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt +++ b/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt @@ -1,3 +1,19 @@ +/* + * Copyright 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.graphics import android.annotation.AnyThread @@ -20,6 +36,7 @@ import android.util.Log import android.util.Size import androidx.core.content.res.ResourcesCompat import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import java.io.IOException import javax.inject.Inject @@ -35,7 +52,7 @@ import kotlinx.coroutines.withContext class ImageLoader @Inject constructor( - private val defaultContext: Context, + @Application private val defaultContext: Context, @Background private val backgroundDispatcher: CoroutineDispatcher ) { diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt index a173f8b914db..2ef5e19bf382 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt @@ -90,9 +90,9 @@ class KeyboardBacklightDialog( private fun updateResources() { context.resources.apply { - filledRectangleColor = getColor(R.color.backlight_indicator_step_filled) - emptyRectangleColor = getColor(R.color.backlight_indicator_step_empty) - backgroundColor = getColor(R.color.backlight_indicator_background) + filledRectangleColor = getColor(R.color.backlight_indicator_step_filled, context.theme) + emptyRectangleColor = getColor(R.color.backlight_indicator_step_empty, context.theme) + backgroundColor = getColor(R.color.backlight_indicator_background, context.theme) rootProperties = RootProperties( cornerRadius = @@ -224,7 +224,6 @@ class KeyboardBacklightDialog( private fun setWindowTitle() { val attrs = window.attributes - // TODO(b/271796169): check if title needs to be a translatable resource. attrs.title = "KeyboardBacklightDialog" attrs?.y = dialogBottomMargin window.attributes = attrs diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index bafd2e70a676..573de9737eb8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -60,6 +60,7 @@ import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.wakelock.SettableWakeLock; import com.android.systemui.util.wakelock.WakeLock; +import com.android.systemui.util.wakelock.WakeLockLogger; import java.util.Date; import java.util.Locale; @@ -148,6 +149,8 @@ public class KeyguardSliceProvider extends SliceProvider implements private int mStatusBarState; private boolean mMediaIsVisible; private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback; + @Inject + WakeLockLogger mWakeLockLogger; /** * Receiver responsible for time ticking and updating the date format. @@ -305,8 +308,8 @@ public class KeyguardSliceProvider extends SliceProvider implements @Override public boolean onCreateSliceProvider() { mContextAvailableCallback.onContextAvailable(getContext()); - mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"), - "media"); + mMediaWakeLock = new SettableWakeLock( + WakeLock.createPartial(getContext(), mWakeLockLogger, "media"), "media"); synchronized (KeyguardSliceProvider.sInstanceLock) { KeyguardSliceProvider oldInstance = KeyguardSliceProvider.sInstance; if (oldInstance != null) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index c102c5b57375..0fd479afcf48 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -128,6 +128,8 @@ import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -855,6 +857,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mCustomMessage = null; return message; } + + @Override + public void setCustomMessage(CharSequence customMessage) { + mCustomMessage = customMessage; + } }; /** @@ -1184,6 +1191,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private Lazy<ActivityLaunchAnimator> mActivityLaunchAnimator; private Lazy<ScrimController> mScrimControllerLazy; + private FeatureFlags mFeatureFlags; + /** * Injected constructor. See {@link KeyguardModule}. */ @@ -1214,7 +1223,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, Lazy<ShadeController> shadeControllerLazy, Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy, Lazy<ActivityLaunchAnimator> activityLaunchAnimator, - Lazy<ScrimController> scrimControllerLazy) { + Lazy<ScrimController> scrimControllerLazy, + FeatureFlags featureFlags) { mContext = context; mUserTracker = userTracker; mFalsingCollector = falsingCollector; @@ -1269,6 +1279,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS; mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS; + + mFeatureFlags = featureFlags; } public void userActivity() { @@ -1682,14 +1694,17 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } /** - * A dream started. We should lock after the usual screen-off lock timeout but only - * if there is a secure lock pattern. + * A dream started. We should lock after the usual screen-off lock timeout regardless if + * there is a secure lock pattern or not */ public void onDreamingStarted() { mUpdateMonitor.dispatchDreamingStarted(); synchronized (this) { + final boolean alwaysShowKeyguard = + mFeatureFlags.isEnabled(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING); if (mDeviceInteractive - && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) { + && (alwaysShowKeyguard || + mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()))) { doKeyguardLaterLocked(); } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardFaceAuthNotSupportedModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardFaceAuthNotSupportedModule.kt new file mode 100644 index 000000000000..a44df7e11fa1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardFaceAuthNotSupportedModule.kt @@ -0,0 +1,35 @@ +/* + * 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.keyguard.dagger + +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor +import com.android.systemui.keyguard.domain.interactor.NoopKeyguardFaceAuthInteractor +import dagger.Binds +import dagger.Module + +/** + * Module that provides bindings for face auth classes that are injected into SysUI components that + * are used across different SysUI variants, where face auth is not supported. + * + * Some variants that do not support face authentication can install this module to provide a no-op + * implementation of the interactor. + */ +@Module +interface KeyguardFaceAuthNotSupportedModule { + @Binds + fun keyguardFaceAuthInteractor(impl: NoopKeyguardFaceAuthInteractor): KeyguardFaceAuthInteractor +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 6ac51cd52b49..5e71458c8bb4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -39,6 +39,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -119,7 +120,8 @@ public class KeyguardModule { Lazy<ShadeController> shadeController, Lazy<NotificationShadeWindowController> notificationShadeWindowController, Lazy<ActivityLaunchAnimator> activityLaunchAnimator, - Lazy<ScrimController> scrimControllerLazy) { + Lazy<ScrimController> scrimControllerLazy, + FeatureFlags featureFlags) { return new KeyguardViewMediator( context, userTracker, @@ -149,7 +151,8 @@ public class KeyguardModule { shadeController, notificationShadeWindowController, activityLaunchAnimator, - scrimControllerLazy); + scrimControllerLazy, + featureFlags); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt index 56e73980079d..5f6098b8758f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt @@ -34,6 +34,7 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus import com.android.systemui.keyguard.shared.model.AuthenticationStatus import com.android.systemui.keyguard.shared.model.DetectionStatus @@ -44,6 +45,8 @@ import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.log.SessionTracker +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.user.data.repository.UserRepository import java.io.PrintWriter @@ -78,7 +81,7 @@ interface DeviceEntryFaceAuthRepository { val isAuthenticated: Flow<Boolean> /** Whether face auth can run at this point. */ - val canRunFaceAuth: Flow<Boolean> + val canRunFaceAuth: StateFlow<Boolean> /** Provide the current status of face authentication. */ val authenticationStatus: Flow<AuthenticationStatus> @@ -87,10 +90,13 @@ interface DeviceEntryFaceAuthRepository { val detectionStatus: Flow<DetectionStatus> /** Current state of whether face authentication is locked out or not. */ - val isLockedOut: Flow<Boolean> + val isLockedOut: StateFlow<Boolean> /** Current state of whether face authentication is running. */ - val isAuthRunning: Flow<Boolean> + val isAuthRunning: StateFlow<Boolean> + + /** Whether bypass is currently enabled */ + val isBypassEnabled: Flow<Boolean> /** * Trigger face authentication. @@ -126,6 +132,9 @@ constructor( private val keyguardRepository: KeyguardRepository, private val keyguardInteractor: KeyguardInteractor, private val alternateBouncerInteractor: AlternateBouncerInteractor, + @FaceDetectTableLog private val faceDetectLog: TableLogBuffer, + @FaceAuthTableLog private val faceAuthLog: TableLogBuffer, + private val keyguardTransitionInteractor: KeyguardTransitionInteractor, dumpManager: DumpManager, ) : DeviceEntryFaceAuthRepository, Dumpable { private var authCancellationSignal: CancellationSignal? = null @@ -166,7 +175,7 @@ constructor( override val isAuthenticated: Flow<Boolean> get() = _isAuthenticated - private val bypassEnabled: Flow<Boolean> = + override val isBypassEnabled: Flow<Boolean> = keyguardBypassController?.let { conflatedCallbackFlow { val callback = @@ -204,6 +213,13 @@ constructor( observeFaceAuthGatingChecks() observeFaceDetectGatingChecks() observeFaceAuthResettingConditions() + listenForSchedulingWatchdog() + } + + private fun listenForSchedulingWatchdog() { + keyguardTransitionInteractor.anyStateToGoneTransition + .onEach { faceManager?.scheduleWatchdog() } + .launchIn(applicationScope) } private fun observeFaceAuthResettingConditions() { @@ -221,17 +237,19 @@ constructor( // Face detection can run only when lockscreen bypass is enabled // & detection is supported & biometric unlock is not allowed. listOf( - canFaceAuthOrDetectRun(), - logAndObserve(bypassEnabled, "bypassEnabled"), + canFaceAuthOrDetectRun(faceDetectLog), + logAndObserve(isBypassEnabled, "isBypassEnabled", faceDetectLog), logAndObserve( biometricSettingsRepository.isNonStrongBiometricAllowed.isFalse(), - "nonStrongBiometricIsNotAllowed" + "nonStrongBiometricIsNotAllowed", + faceDetectLog ), // We don't want to run face detect if it's not possible to authenticate with FP // from the bouncer. UDFPS is the only fp sensor type that won't support this. logAndObserve( and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning).isFalse(), - "udfpsAuthIsNotPossibleAnymore" + "udfpsAuthIsNotPossibleAnymore", + faceDetectLog ) ) .reduce(::and) @@ -243,6 +261,7 @@ constructor( cancelDetection() } } + .logDiffsForTable(faceDetectLog, "", "canFaceDetectRun", false) .launchIn(applicationScope) } @@ -251,26 +270,34 @@ constructor( it == BiometricType.UNDER_DISPLAY_FINGERPRINT } - private fun canFaceAuthOrDetectRun(): Flow<Boolean> { + private fun canFaceAuthOrDetectRun(tableLogBuffer: TableLogBuffer): Flow<Boolean> { return listOf( - logAndObserve(biometricSettingsRepository.isFaceEnrolled, "isFaceEnrolled"), + logAndObserve( + biometricSettingsRepository.isFaceEnrolled, + "isFaceEnrolled", + tableLogBuffer + ), logAndObserve( biometricSettingsRepository.isFaceAuthenticationEnabled, - "isFaceAuthenticationEnabled" + "isFaceAuthenticationEnabled", + tableLogBuffer ), logAndObserve( userRepository.userSwitchingInProgress.isFalse(), - "userSwitchingNotInProgress" + "userSwitchingNotInProgress", + tableLogBuffer ), logAndObserve( keyguardRepository.isKeyguardGoingAway.isFalse(), - "keyguardNotGoingAway" + "keyguardNotGoingAway", + tableLogBuffer ), logAndObserve( keyguardRepository.wakefulness .map { WakefulnessModel.isSleepingOrStartingToSleep(it) } .isFalse(), - "deviceNotSleepingOrNotStartingToSleep" + "deviceNotSleepingOrNotStartingToSleep", + tableLogBuffer ), logAndObserve( combine( @@ -279,15 +306,18 @@ constructor( ) { a, b -> !a || b }, - "secureCameraNotActiveOrAltBouncerIsShowing" + "secureCameraNotActiveOrAltBouncerIsShowing", + tableLogBuffer ), logAndObserve( biometricSettingsRepository.isFaceAuthSupportedInCurrentPosture, - "isFaceAuthSupportedInCurrentPosture" + "isFaceAuthSupportedInCurrentPosture", + tableLogBuffer ), logAndObserve( biometricSettingsRepository.isCurrentUserInLockdown.isFalse(), - "userHasNotLockedDownDevice" + "userHasNotLockedDownDevice", + tableLogBuffer ) ) .reduce(::and) @@ -296,20 +326,27 @@ constructor( private fun observeFaceAuthGatingChecks() { // Face auth can run only if all of the gating conditions are true. listOf( - canFaceAuthOrDetectRun(), - logAndObserve(isLockedOut.isFalse(), "isNotLocked"), + canFaceAuthOrDetectRun(faceAuthLog), + logAndObserve(isLockedOut.isFalse(), "isNotInLockOutState", faceAuthLog), logAndObserve( deviceEntryFingerprintAuthRepository.isLockedOut.isFalse(), - "fpLockedOut" + "fpLockedOut", + faceAuthLog + ), + logAndObserve( + trustRepository.isCurrentUserTrusted.isFalse(), + "currentUserTrusted", + faceAuthLog ), - logAndObserve(trustRepository.isCurrentUserTrusted.isFalse(), "currentUserTrusted"), logAndObserve( biometricSettingsRepository.isNonStrongBiometricAllowed, - "nonStrongBiometricIsAllowed" + "nonStrongBiometricIsAllowed", + faceAuthLog ), logAndObserve( userRepository.selectedUserInfo.map { it.isPrimary }, - "userIsPrimaryUser" + "userIsPrimaryUser", + faceAuthLog ), ) .reduce(::and) @@ -323,6 +360,7 @@ constructor( cancel() } } + .logDiffsForTable(faceAuthLog, "", "canFaceAuthRun", false) .launchIn(applicationScope) } @@ -337,7 +375,6 @@ constructor( override fun onAuthenticationAcquired(acquireInfo: Int) { _authenticationStatus.value = AcquiredAuthenticationStatus(acquireInfo) - faceAuthLogger.authenticationAcquired(acquireInfo) } override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) { @@ -398,7 +435,7 @@ constructor( override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) { if (_isAuthRunning.value) { - faceAuthLogger.ignoredFaceAuthTrigger(uiEvent) + faceAuthLogger.ignoredFaceAuthTrigger(uiEvent, "face auth is currently running") return } @@ -435,7 +472,16 @@ constructor( ) } } else if (fallbackToDetection && canRunDetection.value) { + faceAuthLogger.ignoredFaceAuthTrigger( + uiEvent, + "face auth gating check is false, falling back to detection." + ) detect() + } else { + faceAuthLogger.ignoredFaceAuthTrigger( + uiEvent, + "face auth & detect gating check is false" + ) } } @@ -464,7 +510,7 @@ constructor( private val currentUserId: Int get() = userRepository.getSelectedUserInfo().id - fun cancelDetection() { + private fun cancelDetection() { detectCancellationSignal?.cancel() detectCancellationSignal = null } @@ -488,10 +534,20 @@ constructor( _isAuthRunning.value = false } - private fun logAndObserve(cond: Flow<Boolean>, loggingContext: String): Flow<Boolean> { - return cond.distinctUntilChanged().onEach { - faceAuthLogger.observedConditionChanged(it, loggingContext) - } + private fun logAndObserve( + cond: Flow<Boolean>, + conditionName: String, + logBuffer: TableLogBuffer + ): Flow<Boolean> { + return cond + .distinctUntilChanged() + .logDiffsForTable( + logBuffer, + columnName = conditionName, + columnPrefix = "", + initialValue = false + ) + .onEach { faceAuthLogger.observedConditionChanged(it, conditionName) } } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/FaceAuthTableLog.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/FaceAuthTableLog.kt new file mode 100644 index 000000000000..6c23032143c1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/FaceAuthTableLog.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.data.repository + +import javax.inject.Qualifier + +/** Face auth logs in table format. */ +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class FaceAuthTableLog diff --git a/keystore/java/android/security/GenerateRkpKeyException.java b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/FaceDetectTableLog.kt index a2d65e4e7119..342064f02ef2 100644 --- a/keystore/java/android/security/GenerateRkpKeyException.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/FaceDetectTableLog.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 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,18 +14,12 @@ * limitations under the License. */ -package android.security; +package com.android.systemui.keyguard.data.repository -/** - * Thrown on problems in attempting to attest to a key using a remotely provisioned key. - * - * @hide - */ -public class GenerateRkpKeyException extends Exception { +import javax.inject.Qualifier - /** - * Constructs a new {@code GenerateRkpKeyException}. - */ - public GenerateRkpKeyException() { - } -} +/** Face detect logs in table format. */ +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class FaceDetectTableLog diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt index 3c66f2424c7b..ef8b40191149 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt @@ -17,8 +17,17 @@ package com.android.systemui.keyguard.data.repository +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor +import com.android.systemui.keyguard.domain.interactor.SystemUIKeyguardFaceAuthInteractor +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.TableLogBufferFactory import dagger.Binds import dagger.Module +import dagger.Provides +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap @Module interface KeyguardFaceAuthModule { @@ -27,5 +36,31 @@ interface KeyguardFaceAuthModule { impl: DeviceEntryFaceAuthRepositoryImpl ): DeviceEntryFaceAuthRepository + @Binds + @IntoMap + @ClassKey(SystemUIKeyguardFaceAuthInteractor::class) + fun bind(impl: SystemUIKeyguardFaceAuthInteractor): CoreStartable + + @Binds + fun keyguardFaceAuthInteractor( + impl: SystemUIKeyguardFaceAuthInteractor + ): KeyguardFaceAuthInteractor + @Binds fun trustRepository(impl: TrustRepositoryImpl): TrustRepository + + companion object { + @Provides + @SysUISingleton + @FaceAuthTableLog + fun provideFaceAuthTableLog(factory: TableLogBufferFactory): TableLogBuffer { + return factory.create("FaceAuthTableLog", 100) + } + + @Provides + @SysUISingleton + @FaceDetectTableLog + fun provideFaceDetectTableLog(factory: TableLogBufferFactory): TableLogBuffer { + return factory.create("FaceDetectTableLog", 100) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt index 8ece3183fd56..ab4abbf3d575 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.data.repository import android.content.Context import android.os.UserHandle +import android.util.LayoutDirection import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging @@ -113,30 +114,6 @@ constructor( initialValue = emptyMap(), ) - private val _slotPickerRepresentations: List<KeyguardSlotPickerRepresentation> by lazy { - fun parseSlot(unparsedSlot: String): Pair<String, Int> { - val split = unparsedSlot.split(SLOT_CONFIG_DELIMITER) - check(split.size == 2) - val slotId = split[0] - val slotCapacity = split[1].toInt() - return slotId to slotCapacity - } - - val unparsedSlots = - appContext.resources.getStringArray(R.array.config_keyguardQuickAffordanceSlots) - - val seenSlotIds = mutableSetOf<String>() - unparsedSlots.mapNotNull { unparsedSlot -> - val (slotId, slotCapacity) = parseSlot(unparsedSlot) - check(!seenSlotIds.contains(slotId)) { "Duplicate slot \"$slotId\"!" } - seenSlotIds.add(slotId) - KeyguardSlotPickerRepresentation( - id = slotId, - maxSelectedAffordances = slotCapacity, - ) - } - } - init { legacySettingSyncer.startSyncing() dumpManager.registerDumpable("KeyguardQuickAffordances", Dumpster()) @@ -211,7 +188,30 @@ constructor( * each slot and select which affordance(s) is/are installed in each slot on the keyguard. */ fun getSlotPickerRepresentations(): List<KeyguardSlotPickerRepresentation> { - return _slotPickerRepresentations + fun parseSlot(unparsedSlot: String): Pair<String, Int> { + val split = unparsedSlot.split(SLOT_CONFIG_DELIMITER) + check(split.size == 2) + val slotId = split[0] + val slotCapacity = split[1].toInt() + return slotId to slotCapacity + } + + val unparsedSlots = + appContext.resources.getStringArray(R.array.config_keyguardQuickAffordanceSlots) + if (appContext.resources.configuration.layoutDirection == LayoutDirection.RTL) { + unparsedSlots.reverse() + } + + val seenSlotIds = mutableSetOf<String>() + return unparsedSlots.mapNotNull { unparsedSlot -> + val (slotId, slotCapacity) = parseSlot(unparsedSlot) + check(!seenSlotIds.contains(slotId)) { "Duplicate slot \"$slotId\"!" } + seenSlotIds.add(slotId) + KeyguardSlotPickerRepresentation( + id = slotId, + maxSelectedAffordances = slotCapacity, + ) + } } private inner class Dumpster : Dumpable { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt new file mode 100644 index 000000000000..06ae11fe810c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt @@ -0,0 +1,78 @@ +/* + * 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.keyguard.domain.interactor + +import com.android.systemui.keyguard.shared.model.AuthenticationStatus +import com.android.systemui.keyguard.shared.model.DetectionStatus +import kotlinx.coroutines.flow.Flow + +/** + * Interactor that exposes API to get the face authentication status and handle any events that can + * cause face authentication to run. + */ +interface KeyguardFaceAuthInteractor { + + /** Current authentication status */ + val authenticationStatus: Flow<AuthenticationStatus> + + /** Current detection status */ + val detectionStatus: Flow<DetectionStatus> + + /** Can face auth be run right now */ + fun canFaceAuthRun(): Boolean + + /** Whether face auth is currently running or not. */ + fun isRunning(): Boolean + + /** Whether face auth is in lock out state. */ + fun isLockedOut(): Boolean + + /** + * Register listener for use from code that cannot use [authenticationStatus] or + * [detectionStatus] + */ + fun registerListener(listener: FaceAuthenticationListener) + + /** Unregister previously registered listener */ + fun unregisterListener(listener: FaceAuthenticationListener) + + /** Whether the face auth interactor is enabled or not. */ + fun isEnabled(): Boolean + + fun onUdfpsSensorTouched() + fun onAssistantTriggeredOnLockScreen() + fun onDeviceLifted() + fun onQsExpansionStared() + fun onNotificationPanelClicked() + fun onSwipeUpOnBouncer() +} + +/** + * Listener that can be registered with the [KeyguardFaceAuthInteractor] to receive updates about + * face authentication & detection updates. + * + * This is present to make it easier for use the new face auth API for code that cannot use + * [KeyguardFaceAuthInteractor.authenticationStatus] or [KeyguardFaceAuthInteractor.detectionStatus] + * flows. + */ +interface FaceAuthenticationListener { + /** Receive face authentication status updates */ + fun onAuthenticationStatusChanged(status: AuthenticationStatus) + + /** Receive status updates whenever face detection runs */ + fun onDetectionStatusChanged(status: DetectionStatus) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt index 6525a13fc44f..ea6700e92731 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt @@ -17,29 +17,29 @@ package com.android.systemui.keyguard.domain.interactor -import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.view.accessibility.AccessibilityManager +import androidx.annotation.VisibleForTesting import com.android.internal.logging.UiEvent import com.android.internal.logging.UiEventLogger -import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.common.shared.model.Position 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.keyguard.data.repository.KeyguardRepository -import com.android.systemui.keyguard.domain.model.KeyguardSettingsPopupMenuModel import com.android.systemui.keyguard.shared.model.KeyguardState -import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf @@ -47,6 +47,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch /** Business logic for use-cases related to the keyguard long-press feature. */ @OptIn(ExperimentalCoroutinesApi::class) @@ -54,18 +55,16 @@ import kotlinx.coroutines.flow.stateIn class KeyguardLongPressInteractor @Inject constructor( - @Application unsafeContext: Context, - @Application scope: CoroutineScope, + @Application private val scope: CoroutineScope, transitionInteractor: KeyguardTransitionInteractor, repository: KeyguardRepository, - private val activityStarter: ActivityStarter, private val logger: UiEventLogger, private val featureFlags: FeatureFlags, broadcastDispatcher: BroadcastDispatcher, + private val accessibilityManager: AccessibilityManagerWrapper, ) { - private val appContext = unsafeContext.applicationContext - - private val _isLongPressHandlingEnabled: StateFlow<Boolean> = + /** Whether the long-press handling feature should be enabled. */ + val isLongPressHandlingEnabled: StateFlow<Boolean> = if (isFeatureEnabled()) { combine( transitionInteractor.finishedKeyguardState.map { @@ -84,19 +83,35 @@ constructor( initialValue = false, ) - /** Whether the long-press handling feature should be enabled. */ - val isLongPressHandlingEnabled: Flow<Boolean> = _isLongPressHandlingEnabled - - private val _menu = MutableStateFlow<KeyguardSettingsPopupMenuModel?>(null) - /** Model for a menu that should be shown; `null` when no menu should be shown. */ - val menu: Flow<KeyguardSettingsPopupMenuModel?> = - isLongPressHandlingEnabled.flatMapLatest { isEnabled -> - if (isEnabled) { - _menu - } else { - flowOf(null) + private val _isMenuVisible = MutableStateFlow(false) + /** Model for whether the menu should be shown. */ + val isMenuVisible: StateFlow<Boolean> = + isLongPressHandlingEnabled + .flatMapLatest { isEnabled -> + if (isEnabled) { + _isMenuVisible.asStateFlow() + } else { + // Reset the state so we don't see a menu when long-press handling is enabled + // again in the future. + _isMenuVisible.value = false + flowOf(false) + } } - } + .stateIn( + scope = scope, + started = SharingStarted.WhileSubscribed(), + initialValue = false, + ) + + private val _shouldOpenSettings = MutableStateFlow(false) + /** + * Whether the long-press accessible "settings" flow should be opened. + * + * Note that [onSettingsShown] must be invoked to consume this, once the settings are opened. + */ + val shouldOpenSettings = _shouldOpenSettings.asStateFlow() + + private var delayedHideMenuJob: Job? = null init { if (isFeatureEnabled()) { @@ -110,15 +125,46 @@ constructor( } /** Notifies that the user has long-pressed on the lock screen. */ - fun onLongPress(x: Int, y: Int) { - if (!_isLongPressHandlingEnabled.value) { + fun onLongPress() { + if (!isLongPressHandlingEnabled.value) { return } - showMenu( - x = x, - y = y, - ) + if (featureFlags.isEnabled(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP)) { + showSettings() + } else { + showMenu() + } + } + + /** Notifies that the user has touched outside of the pop-up. */ + fun onTouchedOutside() { + hideMenu() + } + + /** Notifies that the user has started a touch gesture on the menu. */ + fun onMenuTouchGestureStarted() { + cancelAutomaticMenuHiding() + } + + /** Notifies that the user has started a touch gesture on the menu. */ + fun onMenuTouchGestureEnded(isClick: Boolean) { + if (isClick) { + hideMenu() + logger.log(LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_CLICKED) + showSettings() + } else { + scheduleAutomaticMenuHiding() + } + } + + /** Notifies that the settings UI has been shown, consuming the event to show it. */ + fun onSettingsShown() { + _shouldOpenSettings.value = false + } + + private fun showSettings() { + _shouldOpenSettings.value = true } private fun isFeatureEnabled(): Boolean { @@ -126,51 +172,40 @@ constructor( featureFlags.isEnabled(Flags.REVAMPED_WALLPAPER_UI) } - /** Updates application state to ask to show the menu at the given coordinates. */ - private fun showMenu( - x: Int, - y: Int, - ) { - _menu.value = - KeyguardSettingsPopupMenuModel( - position = - Position( - x = x, - y = y, - ), - onClicked = { - hideMenu() - navigateToLockScreenSettings() - }, - onDismissed = { hideMenu() }, - ) + /** Updates application state to ask to show the menu. */ + private fun showMenu() { + _isMenuVisible.value = true + scheduleAutomaticMenuHiding() logger.log(LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_SHOWN) } + private fun scheduleAutomaticMenuHiding() { + cancelAutomaticMenuHiding() + delayedHideMenuJob = + scope.launch { + delay(timeOutMs()) + hideMenu() + } + } + /** Updates application state to ask to hide the menu. */ private fun hideMenu() { - _menu.value = null + cancelAutomaticMenuHiding() + _isMenuVisible.value = false } - /** Opens the wallpaper picker screen after the device is unlocked by the user. */ - private fun navigateToLockScreenSettings() { - logger.log(LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_CLICKED) - activityStarter.dismissKeyguardThenExecute( - /* action= */ { - appContext.startActivity( - Intent(Intent.ACTION_SET_WALLPAPER).apply { - flags = Intent.FLAG_ACTIVITY_NEW_TASK - appContext - .getString(R.string.config_wallpaperPickerPackage) - .takeIf { it.isNotEmpty() } - ?.let { packageName -> setPackage(packageName) } - } - ) - true - }, - /* cancel= */ {}, - /* afterKeyguardGone= */ true, - ) + private fun cancelAutomaticMenuHiding() { + delayedHideMenuJob?.cancel() + delayedHideMenuJob = null + } + + private fun timeOutMs(): Long { + return accessibilityManager + .getRecommendedTimeoutMillis( + DEFAULT_POPUP_AUTO_HIDE_TIMEOUT_MS.toInt(), + AccessibilityManager.FLAG_CONTENT_ICONS or AccessibilityManager.FLAG_CONTENT_TEXT, + ) + .toLong() } enum class LogEvents( @@ -184,4 +219,8 @@ constructor( override fun getId() = _id } + + companion object { + @VisibleForTesting const val DEFAULT_POPUP_AUTO_HIDE_TIMEOUT_MS = 5000L + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt index aabd212c1bd3..da0ada160518 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt @@ -78,6 +78,14 @@ constructor( val primaryBouncerToGoneTransition: Flow<TransitionStep> = repository.transition(PRIMARY_BOUNCER, GONE) + /** OFF->LOCKSCREEN transition information. */ + val offToLockscreenTransition: Flow<TransitionStep> = + repository.transition(KeyguardState.OFF, LOCKSCREEN) + + /** DOZING->LOCKSCREEN transition information. */ + val dozingToLockscreenTransition: Flow<TransitionStep> = + repository.transition(KeyguardState.DOZING, LOCKSCREEN) + /** * AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <-> * Lockscreen (0f). diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt new file mode 100644 index 000000000000..cad40aac00d3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt @@ -0,0 +1,62 @@ +/* + * 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.keyguard.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.shared.model.AuthenticationStatus +import com.android.systemui.keyguard.shared.model.DetectionStatus +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow + +/** + * Implementation of the interactor that noops all face auth operations. + * + * This is required for SystemUI variants that do not support face authentication but still inject + * other SysUI components that depend on [KeyguardFaceAuthInteractor] + */ +@SysUISingleton +class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInteractor { + override val authenticationStatus: Flow<AuthenticationStatus> + get() = emptyFlow() + override val detectionStatus: Flow<DetectionStatus> + get() = emptyFlow() + + override fun canFaceAuthRun(): Boolean = false + + override fun isRunning(): Boolean = false + + override fun isLockedOut(): Boolean = false + + override fun isEnabled() = false + + override fun registerListener(listener: FaceAuthenticationListener) {} + + override fun unregisterListener(listener: FaceAuthenticationListener) {} + + override fun onUdfpsSensorTouched() {} + + override fun onAssistantTriggeredOnLockScreen() {} + + override fun onDeviceLifted() {} + + override fun onQsExpansionStared() {} + + override fun onNotificationPanelClicked() {} + + override fun onSwipeUpOnBouncer() {} +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt new file mode 100644 index 000000000000..20ebb711c42d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt @@ -0,0 +1,200 @@ +/* + * 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.keyguard.domain.interactor + +import com.android.keyguard.FaceAuthUiEvent +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.log.FaceAuthenticationLogger +import com.android.systemui.util.kotlin.pairwise +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch + +/** + * Encapsulates business logic related face authentication being triggered for device entry from + * SystemUI Keyguard. + */ +@SysUISingleton +class SystemUIKeyguardFaceAuthInteractor +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + @Main private val mainDispatcher: CoroutineDispatcher, + private val repository: DeviceEntryFaceAuthRepository, + private val primaryBouncerInteractor: PrimaryBouncerInteractor, + private val alternateBouncerInteractor: AlternateBouncerInteractor, + private val keyguardTransitionInteractor: KeyguardTransitionInteractor, + private val featureFlags: FeatureFlags, + private val faceAuthenticationLogger: FaceAuthenticationLogger, + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, +) : CoreStartable, KeyguardFaceAuthInteractor { + + private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf() + + override fun start() { + if (!isEnabled()) { + return + } + // This is required because fingerprint state required for the face auth repository is + // backed by KeyguardUpdateMonitor. KeyguardUpdateMonitor constructor accesses the biometric + // state which makes lazy injection not an option. + keyguardUpdateMonitor.setFaceAuthInteractor(this) + observeFaceAuthStateUpdates() + faceAuthenticationLogger.interactorStarted() + primaryBouncerInteractor.isShowing + .whenItFlipsToTrue() + .onEach { + faceAuthenticationLogger.bouncerVisibilityChanged() + runFaceAuth( + FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN, + fallbackToDetect = true + ) + } + .launchIn(applicationScope) + + alternateBouncerInteractor.isVisible + .whenItFlipsToTrue() + .onEach { + faceAuthenticationLogger.alternateBouncerVisibilityChanged() + runFaceAuth( + FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN, + fallbackToDetect = false + ) + } + .launchIn(applicationScope) + + merge( + keyguardTransitionInteractor.aodToLockscreenTransition, + keyguardTransitionInteractor.offToLockscreenTransition, + keyguardTransitionInteractor.dozingToLockscreenTransition + ) + .filter { it.transitionState == TransitionState.STARTED } + .onEach { + faceAuthenticationLogger.lockscreenBecameVisible(it) + runFaceAuth( + FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED, + fallbackToDetect = true + ) + } + .launchIn(applicationScope) + } + + override fun onSwipeUpOnBouncer() { + runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER, false) + } + + override fun onNotificationPanelClicked() { + runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED, true) + } + + override fun onQsExpansionStared() { + runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED, true) + } + + override fun onDeviceLifted() { + runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_PICK_UP_GESTURE_TRIGGERED, true) + } + + override fun onAssistantTriggeredOnLockScreen() { + runFaceAuth(FaceAuthUiEvent.FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED, true) + } + + override fun onUdfpsSensorTouched() { + runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_UDFPS_POINTER_DOWN, false) + } + + override fun registerListener(listener: FaceAuthenticationListener) { + listeners.add(listener) + } + + override fun unregisterListener(listener: FaceAuthenticationListener) { + listeners.remove(listener) + } + + override fun isLockedOut(): Boolean = repository.isLockedOut.value + + override fun isRunning(): Boolean = repository.isAuthRunning.value + + override fun canFaceAuthRun(): Boolean = repository.canRunFaceAuth.value + + override fun isEnabled(): Boolean { + return featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR) + } + + /** Provide the status of face authentication */ + override val authenticationStatus = repository.authenticationStatus + + /** Provide the status of face detection */ + override val detectionStatus = repository.detectionStatus + + private fun runFaceAuth(uiEvent: FaceAuthUiEvent, fallbackToDetect: Boolean) { + if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) { + applicationScope.launch { + faceAuthenticationLogger.authRequested(uiEvent) + repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect) + } + } else { + faceAuthenticationLogger.ignoredFaceAuthTrigger( + uiEvent, + ignoredReason = "Skipping face auth request because feature flag is false" + ) + } + } + + private fun observeFaceAuthStateUpdates() { + authenticationStatus + .onEach { authStatusUpdate -> + listeners.forEach { it.onAuthenticationStatusChanged(authStatusUpdate) } + } + .flowOn(mainDispatcher) + .launchIn(applicationScope) + detectionStatus + .onEach { detectionStatusUpdate -> + listeners.forEach { it.onDetectionStatusChanged(detectionStatusUpdate) } + } + .flowOn(mainDispatcher) + .launchIn(applicationScope) + } + + companion object { + const val TAG = "KeyguardFaceAuthInteractor" + } +} + +// Extension method that filters a generic Boolean flow to one that emits +// whenever there is flip from false -> true +private fun Flow<Boolean>.whenItFlipsToTrue(): Flow<Boolean> { + return this.pairwise() + .filter { pair -> !pair.previousValue && pair.newValue } + .map { it.newValue } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/TrustAgentUiEvent.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/TrustAgentUiEvent.kt new file mode 100644 index 000000000000..ef6079fbc25b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/TrustAgentUiEvent.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.shared.constants + +import com.android.internal.logging.UiEvent +import com.android.internal.logging.UiEventLogger + +enum class TrustAgentUiEvent(private val metricId: Int) : UiEventLogger.UiEventEnum { + @UiEvent(doc = "TrustAgent newly unlocked the device") TRUST_AGENT_NEWLY_UNLOCKED(1361); + override fun getId() = metricId +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt new file mode 100644 index 000000000000..568db2f543b6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt @@ -0,0 +1,73 @@ +/* + * 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.keyguard.ui.binder + +import android.os.VibrationEffect +import kotlin.time.Duration.Companion.milliseconds + +object KeyguardBottomAreaVibrations { + + val ShakeAnimationDuration = 300.milliseconds + const val ShakeAnimationCycles = 5f + + private const val SmallVibrationScale = 0.3f + private const val BigVibrationScale = 0.6f + + val Shake = + VibrationEffect.startComposition() + .apply { + val vibrationDelayMs = + (ShakeAnimationDuration.inWholeMilliseconds / ShakeAnimationCycles * 2).toInt() + val vibrationCount = ShakeAnimationCycles.toInt() * 2 + repeat(vibrationCount) { + addPrimitive( + VibrationEffect.Composition.PRIMITIVE_TICK, + SmallVibrationScale, + vibrationDelayMs, + ) + } + } + .compose() + + val Activated = + VibrationEffect.startComposition() + .addPrimitive( + VibrationEffect.Composition.PRIMITIVE_TICK, + BigVibrationScale, + 0, + ) + .addPrimitive( + VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, + 0.1f, + 0, + ) + .compose() + + val Deactivated = + VibrationEffect.startComposition() + .addPrimitive( + VibrationEffect.Composition.PRIMITIVE_TICK, + BigVibrationScale, + 0, + ) + .addPrimitive( + VibrationEffect.Composition.PRIMITIVE_QUICK_FALL, + 0.1f, + 0, + ) + .compose() +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index d63636c6fccc..d96609c24dbd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -17,41 +17,42 @@ package com.android.systemui.keyguard.ui.binder import android.annotation.SuppressLint +import android.content.Intent +import android.graphics.Rect import android.graphics.drawable.Animatable2 -import android.os.VibrationEffect import android.util.Size import android.util.TypedValue -import android.view.MotionEvent import android.view.View -import android.view.ViewConfiguration import android.view.ViewGroup import android.view.ViewPropertyAnimator import android.widget.ImageView import android.widget.TextView -import androidx.core.animation.CycleInterpolator -import androidx.core.animation.ObjectAnimator +import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.settingslib.Utils import com.android.systemui.R +import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.animation.Expandable import com.android.systemui.animation.Interpolators +import com.android.systemui.animation.view.LaunchableLinearLayout import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.binder.IconViewBinder +import com.android.systemui.common.ui.binder.TextViewBinder import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper -import kotlin.math.pow -import kotlin.math.sqrt -import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @@ -91,15 +92,20 @@ object KeyguardBottomAreaViewBinder { * icon */ fun shouldConstrainToTopOfLockIcon(): Boolean + + /** Destroys this binding, releases resources, and cancels any coroutines. */ + fun destroy() } /** Binds the view to the view-model, continuing to update the former based on the latter. */ + @SuppressLint("ClickableViewAccessibility") @JvmStatic fun bind( view: ViewGroup, viewModel: KeyguardBottomAreaViewModel, falsingManager: FalsingManager?, vibratorHelper: VibratorHelper?, + activityStarter: ActivityStarter?, messageDisplayer: (Int) -> Unit, ): Binding { val indicationArea: View = view.requireViewById(R.id.keyguard_indication_area) @@ -110,137 +116,192 @@ object KeyguardBottomAreaViewBinder { val indicationText: TextView = view.requireViewById(R.id.keyguard_indication_text) val indicationTextBottom: TextView = view.requireViewById(R.id.keyguard_indication_text_bottom) + val settingsMenu: LaunchableLinearLayout = + view.requireViewById(R.id.keyguard_settings_button) view.clipChildren = false view.clipToPadding = false + view.setOnTouchListener { _, event -> + if (settingsMenu.isVisible) { + val hitRect = Rect() + settingsMenu.getHitRect(hitRect) + if (!hitRect.contains(event.x.toInt(), event.y.toInt())) { + viewModel.onTouchedOutsideLockScreenSettingsMenu() + } + } + + false + } val configurationBasedDimensions = MutableStateFlow(loadFromResources(view)) - view.repeatWhenAttached { - repeatOnLifecycle(Lifecycle.State.STARTED) { - launch { - viewModel.startButton.collect { buttonModel -> - updateButton( + val disposableHandle = + view.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.startButton.collect { buttonModel -> + updateButton( + view = startButton, + viewModel = buttonModel, + falsingManager = falsingManager, + messageDisplayer = messageDisplayer, + vibratorHelper = vibratorHelper, + ) + } + } + + launch { + viewModel.endButton.collect { buttonModel -> + updateButton( + view = endButton, + viewModel = buttonModel, + falsingManager = falsingManager, + messageDisplayer = messageDisplayer, + vibratorHelper = vibratorHelper, + ) + } + } + + launch { + viewModel.isOverlayContainerVisible.collect { isVisible -> + overlayContainer.visibility = + if (isVisible) { + View.VISIBLE + } else { + View.INVISIBLE + } + } + } + + launch { + viewModel.alpha.collect { alpha -> + view.importantForAccessibility = + if (alpha == 0f) { + View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + } else { + View.IMPORTANT_FOR_ACCESSIBILITY_AUTO + } + + ambientIndicationArea?.alpha = alpha + indicationArea.alpha = alpha + } + } + + launch { + updateButtonAlpha( view = startButton, - viewModel = buttonModel, - falsingManager = falsingManager, - messageDisplayer = messageDisplayer, - vibratorHelper = vibratorHelper, + viewModel = viewModel.startButton, + alphaFlow = viewModel.alpha, ) } - } - launch { - viewModel.endButton.collect { buttonModel -> - updateButton( + launch { + updateButtonAlpha( view = endButton, - viewModel = buttonModel, - falsingManager = falsingManager, - messageDisplayer = messageDisplayer, - vibratorHelper = vibratorHelper, + viewModel = viewModel.endButton, + alphaFlow = viewModel.alpha, ) } - } - launch { - viewModel.isOverlayContainerVisible.collect { isVisible -> - overlayContainer.visibility = - if (isVisible) { - View.VISIBLE - } else { - View.INVISIBLE - } + launch { + viewModel.indicationAreaTranslationX.collect { translationX -> + indicationArea.translationX = translationX + ambientIndicationArea?.translationX = translationX + } } - } - launch { - viewModel.alpha.collect { alpha -> - view.importantForAccessibility = - if (alpha == 0f) { - View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS - } else { - View.IMPORTANT_FOR_ACCESSIBILITY_AUTO + launch { + combine( + viewModel.isIndicationAreaPadded, + configurationBasedDimensions.map { it.indicationAreaPaddingPx }, + ) { isPadded, paddingIfPaddedPx -> + if (isPadded) { + paddingIfPaddedPx + } else { + 0 + } + } + .collect { paddingPx -> + indicationArea.setPadding(paddingPx, 0, paddingPx, 0) } - - ambientIndicationArea?.alpha = alpha - indicationArea.alpha = alpha } - } - - launch { - updateButtonAlpha( - view = startButton, - viewModel = viewModel.startButton, - alphaFlow = viewModel.alpha, - ) - } - - launch { - updateButtonAlpha( - view = endButton, - viewModel = viewModel.endButton, - alphaFlow = viewModel.alpha, - ) - } - launch { - viewModel.indicationAreaTranslationX.collect { translationX -> - indicationArea.translationX = translationX - ambientIndicationArea?.translationX = translationX + launch { + configurationBasedDimensions + .map { it.defaultBurnInPreventionYOffsetPx } + .flatMapLatest { defaultBurnInOffsetY -> + viewModel.indicationAreaTranslationY(defaultBurnInOffsetY) + } + .collect { translationY -> + indicationArea.translationY = translationY + ambientIndicationArea?.translationY = translationY + } } - } - launch { - combine( - viewModel.isIndicationAreaPadded, - configurationBasedDimensions.map { it.indicationAreaPaddingPx }, - ) { isPadded, paddingIfPaddedPx -> - if (isPadded) { - paddingIfPaddedPx - } else { - 0 + launch { + configurationBasedDimensions.collect { dimensions -> + indicationText.setTextSize( + TypedValue.COMPLEX_UNIT_PX, + dimensions.indicationTextSizePx.toFloat(), + ) + indicationTextBottom.setTextSize( + TypedValue.COMPLEX_UNIT_PX, + dimensions.indicationTextSizePx.toFloat(), + ) + + startButton.updateLayoutParams<ViewGroup.LayoutParams> { + width = dimensions.buttonSizePx.width + height = dimensions.buttonSizePx.height + } + endButton.updateLayoutParams<ViewGroup.LayoutParams> { + width = dimensions.buttonSizePx.width + height = dimensions.buttonSizePx.height } } - .collect { paddingPx -> - indicationArea.setPadding(paddingPx, 0, paddingPx, 0) - } - } + } - launch { - configurationBasedDimensions - .map { it.defaultBurnInPreventionYOffsetPx } - .flatMapLatest { defaultBurnInOffsetY -> - viewModel.indicationAreaTranslationY(defaultBurnInOffsetY) - } - .collect { translationY -> - indicationArea.translationY = translationY - ambientIndicationArea?.translationY = translationY + launch { + viewModel.settingsMenuViewModel.isVisible.distinctUntilChanged().collect { + isVisible -> + settingsMenu.animateVisibility(visible = isVisible) + if (isVisible) { + vibratorHelper?.vibrate(KeyguardBottomAreaVibrations.Activated) + settingsMenu.setOnTouchListener( + KeyguardSettingsButtonOnTouchListener( + view = settingsMenu, + viewModel = viewModel.settingsMenuViewModel, + ) + ) + IconViewBinder.bind( + icon = viewModel.settingsMenuViewModel.icon, + view = settingsMenu.requireViewById(R.id.icon), + ) + TextViewBinder.bind( + view = settingsMenu.requireViewById(R.id.text), + viewModel = viewModel.settingsMenuViewModel.text, + ) + } } - } - - launch { - configurationBasedDimensions.collect { dimensions -> - indicationText.setTextSize( - TypedValue.COMPLEX_UNIT_PX, - dimensions.indicationTextSizePx.toFloat(), - ) - indicationTextBottom.setTextSize( - TypedValue.COMPLEX_UNIT_PX, - dimensions.indicationTextSizePx.toFloat(), - ) + } - startButton.updateLayoutParams<ViewGroup.LayoutParams> { - width = dimensions.buttonSizePx.width - height = dimensions.buttonSizePx.height - } - endButton.updateLayoutParams<ViewGroup.LayoutParams> { - width = dimensions.buttonSizePx.width - height = dimensions.buttonSizePx.height + // activityStarter will only be null when rendering the preview that + // shows up in the Wallpaper Picker app. If we do that, then the + // settings menu should never be visible. + if (activityStarter != null) { + launch { + viewModel.settingsMenuViewModel.shouldOpenSettings + .filter { it } + .collect { + navigateToLockScreenSettings( + activityStarter = activityStarter, + view = settingsMenu, + ) + viewModel.settingsMenuViewModel.onSettingsShown() + } } } } } - } return object : Binding { override fun getIndicationAreaAnimators(): List<ViewPropertyAnimator> { @@ -253,6 +314,10 @@ object KeyguardBottomAreaViewBinder { override fun shouldConstrainToTopOfLockIcon(): Boolean = viewModel.shouldConstrainToTopOfLockIcon() + + override fun destroy() { + disposableHandle.dispose() + } } } @@ -265,7 +330,7 @@ object KeyguardBottomAreaViewBinder { vibratorHelper: VibratorHelper?, ) { if (!viewModel.isVisible) { - view.isVisible = false + view.isInvisible = true return } @@ -342,7 +407,7 @@ object KeyguardBottomAreaViewBinder { if (viewModel.isClickable) { if (viewModel.useLongPress) { view.setOnTouchListener( - OnTouchListener( + KeyguardQuickAffordanceOnTouchListener( view, viewModel, messageDisplayer, @@ -372,187 +437,21 @@ object KeyguardBottomAreaViewBinder { .collect { view.alpha = it } } - private class OnTouchListener( - private val view: View, - private val viewModel: KeyguardQuickAffordanceViewModel, - private val messageDisplayer: (Int) -> Unit, - private val vibratorHelper: VibratorHelper?, - private val falsingManager: FalsingManager?, - ) : View.OnTouchListener { - - private val longPressDurationMs = ViewConfiguration.getLongPressTimeout().toLong() - private var longPressAnimator: ViewPropertyAnimator? = null - - @SuppressLint("ClickableViewAccessibility") - override fun onTouch(v: View?, event: MotionEvent?): Boolean { - return when (event?.actionMasked) { - MotionEvent.ACTION_DOWN -> - if (viewModel.configKey != null) { - if (isUsingAccurateTool(event)) { - // For accurate tool types (stylus, mouse, etc.), we don't require a - // long-press. - } else { - // When not using a stylus, we require a long-press to activate the - // quick affordance, mostly to do "falsing" (e.g. protect from false - // clicks in the pocket/bag). - longPressAnimator = - view - .animate() - .scaleX(PRESSED_SCALE) - .scaleY(PRESSED_SCALE) - .setDuration(longPressDurationMs) - .withEndAction { - if ( - falsingManager - ?.isFalseLongTap( - FalsingManager.MODERATE_PENALTY - ) == false - ) { - dispatchClick(viewModel.configKey) - } - cancel() - } - } - true - } else { - false - } - MotionEvent.ACTION_MOVE -> { - if (!isUsingAccurateTool(event)) { - // Moving too far while performing a long-press gesture cancels that - // gesture. - val distanceMoved = distanceMoved(event) - if (distanceMoved > ViewConfiguration.getTouchSlop()) { - cancel() - } - } - true - } - MotionEvent.ACTION_UP -> { - if (isUsingAccurateTool(event)) { - // When using an accurate tool type (stylus, mouse, etc.), we don't require - // a long-press gesture to activate the quick affordance. Therefore, lifting - // the pointer performs a click. - if ( - viewModel.configKey != null && - distanceMoved(event) <= ViewConfiguration.getTouchSlop() && - falsingManager?.isFalseTap(FalsingManager.NO_PENALTY) == false - ) { - dispatchClick(viewModel.configKey) - } - } else { - // When not using a stylus, lifting the finger/pointer will actually cancel - // the long-press gesture. Calling cancel after the quick affordance was - // already long-press activated is a no-op, so it's safe to call from here. - cancel( - onAnimationEnd = - if (event.eventTime - event.downTime < longPressDurationMs) { - Runnable { - messageDisplayer.invoke( - R.string.keyguard_affordance_press_too_short - ) - val amplitude = - view.context.resources - .getDimensionPixelSize( - R.dimen.keyguard_affordance_shake_amplitude - ) - .toFloat() - val shakeAnimator = - ObjectAnimator.ofFloat( - view, - "translationX", - -amplitude / 2, - amplitude / 2, - ) - shakeAnimator.duration = - ShakeAnimationDuration.inWholeMilliseconds - shakeAnimator.interpolator = - CycleInterpolator(ShakeAnimationCycles) - shakeAnimator.start() - - vibratorHelper?.vibrate(Vibrations.Shake) - } - } else { - null - } - ) - } - true - } - MotionEvent.ACTION_CANCEL -> { - cancel() - true - } - else -> false - } - } - - private fun dispatchClick( - configKey: String, - ) { - view.setOnClickListener { - vibratorHelper?.vibrate( - if (viewModel.isActivated) { - Vibrations.Activated - } else { - Vibrations.Deactivated - } - ) - viewModel.onClicked( - KeyguardQuickAffordanceViewModel.OnClickedParameters( - configKey = configKey, - expandable = Expandable.fromView(view), - slotId = viewModel.slotId, - ) - ) - } - view.performClick() - view.setOnClickListener(null) - } - - private fun cancel(onAnimationEnd: Runnable? = null) { - longPressAnimator?.cancel() - longPressAnimator = null - view.animate().scaleX(1f).scaleY(1f).withEndAction(onAnimationEnd) - } - - companion object { - private const val PRESSED_SCALE = 1.5f - - /** - * Returns `true` if the tool type at the given pointer index is an accurate tool (like - * stylus or mouse), which means we can trust it to not be a false click; `false` - * otherwise. - */ - private fun isUsingAccurateTool( - event: MotionEvent, - pointerIndex: Int = 0, - ): Boolean { - return when (event.getToolType(pointerIndex)) { - MotionEvent.TOOL_TYPE_STYLUS -> true - MotionEvent.TOOL_TYPE_MOUSE -> true - else -> false + private fun View.animateVisibility(visible: Boolean) { + animate() + .withStartAction { + if (visible) { + alpha = 0f + isVisible = true } } - - /** - * Returns the amount of distance the pointer moved since the historical record at the - * [since] index. - */ - private fun distanceMoved( - event: MotionEvent, - since: Int = 0, - ): Float { - return if (event.historySize > 0) { - sqrt( - (event.y - event.getHistoricalY(since)).pow(2) + - (event.x - event.getHistoricalX(since)).pow(2) - ) - } else { - 0f + .alpha(if (visible) 1f else 0f) + .withEndAction { + if (!visible) { + isVisible = false } } - } + .start() } private class OnClickListener( @@ -594,64 +493,29 @@ object KeyguardBottomAreaViewBinder { ) } + /** Opens the wallpaper picker screen after the device is unlocked by the user. */ + private fun navigateToLockScreenSettings( + activityStarter: ActivityStarter, + view: View, + ) { + activityStarter.postStartActivityDismissingKeyguard( + Intent(Intent.ACTION_SET_WALLPAPER).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK + view.context + .getString(R.string.config_wallpaperPickerPackage) + .takeIf { it.isNotEmpty() } + ?.let { packageName -> setPackage(packageName) } + }, + /* delay= */ 0, + /* animationController= */ ActivityLaunchAnimator.Controller.fromView(view), + /* customMessage= */ view.context.getString(R.string.keyguard_unlock_to_customize_ls) + ) + } + private data class ConfigurationBasedDimensions( val defaultBurnInPreventionYOffsetPx: Int, val indicationAreaPaddingPx: Int, val indicationTextSizePx: Int, val buttonSizePx: Size, ) - - private val ShakeAnimationDuration = 300.milliseconds - private val ShakeAnimationCycles = 5f - - object Vibrations { - - private const val SmallVibrationScale = 0.3f - private const val BigVibrationScale = 0.6f - - val Shake = - VibrationEffect.startComposition() - .apply { - val vibrationDelayMs = - (ShakeAnimationDuration.inWholeMilliseconds / (ShakeAnimationCycles * 2)) - .toInt() - val vibrationCount = ShakeAnimationCycles.toInt() * 2 - repeat(vibrationCount) { - addPrimitive( - VibrationEffect.Composition.PRIMITIVE_TICK, - SmallVibrationScale, - vibrationDelayMs, - ) - } - } - .compose() - - val Activated = - VibrationEffect.startComposition() - .addPrimitive( - VibrationEffect.Composition.PRIMITIVE_TICK, - BigVibrationScale, - 0, - ) - .addPrimitive( - VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, - 0.1f, - 0, - ) - .compose() - - val Deactivated = - VibrationEffect.startComposition() - .addPrimitive( - VibrationEffect.Composition.PRIMITIVE_TICK, - BigVibrationScale, - 0, - ) - .addPrimitive( - VibrationEffect.Composition.PRIMITIVE_QUICK_FALL, - 0.1f, - 0, - ) - .compose() - } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt index 72dc7a4f7753..6bbc6f61cc6f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt @@ -193,7 +193,11 @@ object KeyguardBouncerViewBinder { launch { viewModel.bouncerShowMessage.collect { - securityContainerController.showMessage(it.message, it.colorStateList) + securityContainerController.showMessage( + it.message, + it.colorStateList, + /* animated= */ true + ) viewModel.onMessageShown() } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressPopupViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressPopupViewBinder.kt deleted file mode 100644 index d85682b3bab8..000000000000 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressPopupViewBinder.kt +++ /dev/null @@ -1,88 +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.systemui.keyguard.ui.binder - -import android.annotation.SuppressLint -import android.view.Gravity -import android.view.LayoutInflater -import android.view.View -import android.view.WindowManager -import android.widget.PopupWindow -import com.android.systemui.R -import com.android.systemui.common.ui.binder.IconViewBinder -import com.android.systemui.common.ui.binder.TextViewBinder -import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsPopupMenuViewModel - -object KeyguardLongPressPopupViewBinder { - @SuppressLint("InflateParams") // We don't care that the parent is null. - fun createAndShow( - container: View, - viewModel: KeyguardSettingsPopupMenuViewModel, - onDismissed: () -> Unit, - ): () -> Unit { - val contentView: View = - LayoutInflater.from(container.context) - .inflate( - R.layout.keyguard_settings_popup_menu, - null, - ) - - contentView.setOnClickListener { viewModel.onClicked() } - IconViewBinder.bind( - icon = viewModel.icon, - view = contentView.requireViewById(R.id.icon), - ) - TextViewBinder.bind( - view = contentView.requireViewById(R.id.text), - viewModel = viewModel.text, - ) - - val popupWindow = - PopupWindow(container.context).apply { - windowLayoutType = WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG - setBackgroundDrawable(null) - animationStyle = com.android.internal.R.style.Animation_Dialog - isOutsideTouchable = true - isFocusable = true - setContentView(contentView) - setOnDismissListener { onDismissed() } - contentView.measure( - View.MeasureSpec.makeMeasureSpec( - 0, - View.MeasureSpec.UNSPECIFIED, - ), - View.MeasureSpec.makeMeasureSpec( - 0, - View.MeasureSpec.UNSPECIFIED, - ), - ) - showAtLocation( - container, - Gravity.NO_GRAVITY, - viewModel.position.x - contentView.measuredWidth / 2, - viewModel.position.y - - contentView.measuredHeight - - container.context.resources.getDimensionPixelSize( - R.dimen.keyguard_long_press_settings_popup_vertical_offset - ), - ) - } - - return { popupWindow.dismiss() } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt index 86717537efd3..9cc503c07955 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt @@ -50,10 +50,7 @@ object KeyguardLongPressViewBinder { return } - viewModel.onLongPress( - x = x, - y = y, - ) + viewModel.onLongPress() } override fun onSingleTapDetected(view: View) { @@ -72,23 +69,6 @@ object KeyguardLongPressViewBinder { view.setLongPressHandlingEnabled(isEnabled) } } - - launch { - var dismissMenu: (() -> Unit)? = null - - viewModel.menu.collect { menuOrNull -> - if (menuOrNull != null) { - dismissMenu = - KeyguardLongPressPopupViewBinder.createAndShow( - container = view, - viewModel = menuOrNull, - onDismissed = menuOrNull.onDismissed, - ) - } else { - dismissMenu?.invoke() - } - } - } } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceOnTouchListener.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceOnTouchListener.kt new file mode 100644 index 000000000000..5745d6ae077e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceOnTouchListener.kt @@ -0,0 +1,206 @@ +/* + * 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.keyguard.ui.binder + +import android.annotation.SuppressLint +import android.graphics.PointF +import android.view.MotionEvent +import android.view.View +import android.view.ViewConfiguration +import android.view.ViewPropertyAnimator +import androidx.core.animation.CycleInterpolator +import androidx.core.animation.ObjectAnimator +import com.android.systemui.R +import com.android.systemui.animation.Expandable +import com.android.systemui.common.ui.view.rawDistanceFrom +import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.statusbar.VibratorHelper + +class KeyguardQuickAffordanceOnTouchListener( + private val view: View, + private val viewModel: KeyguardQuickAffordanceViewModel, + private val messageDisplayer: (Int) -> Unit, + private val vibratorHelper: VibratorHelper?, + private val falsingManager: FalsingManager?, +) : View.OnTouchListener { + + private val longPressDurationMs = ViewConfiguration.getLongPressTimeout().toLong() + private var longPressAnimator: ViewPropertyAnimator? = null + private val downDisplayCoords: PointF by lazy { PointF() } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(v: View, event: MotionEvent): Boolean { + return when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> + if (viewModel.configKey != null) { + downDisplayCoords.set(event.rawX, event.rawY) + if (isUsingAccurateTool(event)) { + // For accurate tool types (stylus, mouse, etc.), we don't require a + // long-press. + } else { + // When not using a stylus, we require a long-press to activate the + // quick affordance, mostly to do "falsing" (e.g. protect from false + // clicks in the pocket/bag). + longPressAnimator = + view + .animate() + .scaleX(PRESSED_SCALE) + .scaleY(PRESSED_SCALE) + .setDuration(longPressDurationMs) + .withEndAction { + if ( + falsingManager?.isFalseLongTap( + FalsingManager.MODERATE_PENALTY + ) == false + ) { + dispatchClick(viewModel.configKey) + } + cancel() + } + } + true + } else { + false + } + MotionEvent.ACTION_MOVE -> { + if (!isUsingAccurateTool(event)) { + // Moving too far while performing a long-press gesture cancels that + // gesture. + if ( + event + .rawDistanceFrom( + downDisplayCoords.x, + downDisplayCoords.y, + ) > ViewConfiguration.getTouchSlop() + ) { + cancel() + } + } + true + } + MotionEvent.ACTION_UP -> { + if (isUsingAccurateTool(event)) { + // When using an accurate tool type (stylus, mouse, etc.), we don't require + // a long-press gesture to activate the quick affordance. Therefore, lifting + // the pointer performs a click. + if ( + viewModel.configKey != null && + event.rawDistanceFrom(downDisplayCoords.x, downDisplayCoords.y) <= + ViewConfiguration.getTouchSlop() && + falsingManager?.isFalseTap(FalsingManager.NO_PENALTY) == false + ) { + dispatchClick(viewModel.configKey) + } + } else { + // When not using a stylus, lifting the finger/pointer will actually cancel + // the long-press gesture. Calling cancel after the quick affordance was + // already long-press activated is a no-op, so it's safe to call from here. + cancel( + onAnimationEnd = + if (event.eventTime - event.downTime < longPressDurationMs) { + Runnable { + messageDisplayer.invoke( + R.string.keyguard_affordance_press_too_short + ) + val amplitude = + view.context.resources + .getDimensionPixelSize( + R.dimen.keyguard_affordance_shake_amplitude + ) + .toFloat() + val shakeAnimator = + ObjectAnimator.ofFloat( + view, + "translationX", + -amplitude / 2, + amplitude / 2, + ) + shakeAnimator.duration = + KeyguardBottomAreaVibrations.ShakeAnimationDuration + .inWholeMilliseconds + shakeAnimator.interpolator = + CycleInterpolator( + KeyguardBottomAreaVibrations.ShakeAnimationCycles + ) + shakeAnimator.start() + + vibratorHelper?.vibrate(KeyguardBottomAreaVibrations.Shake) + } + } else { + null + } + ) + } + true + } + MotionEvent.ACTION_CANCEL -> { + cancel() + true + } + else -> false + } + } + + private fun dispatchClick( + configKey: String, + ) { + view.setOnClickListener { + vibratorHelper?.vibrate( + if (viewModel.isActivated) { + KeyguardBottomAreaVibrations.Activated + } else { + KeyguardBottomAreaVibrations.Deactivated + } + ) + viewModel.onClicked( + KeyguardQuickAffordanceViewModel.OnClickedParameters( + configKey = configKey, + expandable = Expandable.fromView(view), + slotId = viewModel.slotId, + ) + ) + } + view.performClick() + view.setOnClickListener(null) + } + + private fun cancel(onAnimationEnd: Runnable? = null) { + longPressAnimator?.cancel() + longPressAnimator = null + view.animate().scaleX(1f).scaleY(1f).withEndAction(onAnimationEnd) + } + + companion object { + private const val PRESSED_SCALE = 1.5f + + /** + * Returns `true` if the tool type at the given pointer index is an accurate tool (like + * stylus or mouse), which means we can trust it to not be a false click; `false` otherwise. + */ + private fun isUsingAccurateTool( + event: MotionEvent, + pointerIndex: Int = 0, + ): Boolean { + return when (event.getToolType(pointerIndex)) { + MotionEvent.TOOL_TYPE_STYLUS -> true + MotionEvent.TOOL_TYPE_MOUSE -> true + else -> false + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsButtonOnTouchListener.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsButtonOnTouchListener.kt new file mode 100644 index 000000000000..c54203c97013 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsButtonOnTouchListener.kt @@ -0,0 +1,60 @@ +/* + * 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.keyguard.ui.binder + +import android.graphics.PointF +import android.view.MotionEvent +import android.view.View +import android.view.ViewConfiguration +import com.android.systemui.animation.view.LaunchableLinearLayout +import com.android.systemui.common.ui.view.rawDistanceFrom +import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsMenuViewModel + +class KeyguardSettingsButtonOnTouchListener( + private val view: LaunchableLinearLayout, + private val viewModel: KeyguardSettingsMenuViewModel, +) : View.OnTouchListener { + + private val downPositionDisplayCoords = PointF() + + override fun onTouch(view: View, motionEvent: MotionEvent): Boolean { + when (motionEvent.actionMasked) { + MotionEvent.ACTION_DOWN -> { + view.isPressed = true + downPositionDisplayCoords.set(motionEvent.rawX, motionEvent.rawY) + viewModel.onTouchGestureStarted() + } + MotionEvent.ACTION_UP -> { + view.isPressed = false + val distanceMoved = + motionEvent + .rawDistanceFrom(downPositionDisplayCoords.x, downPositionDisplayCoords.y) + val isClick = distanceMoved < ViewConfiguration.getTouchSlop() + viewModel.onTouchGestureEnded(isClick) + if (isClick) { + view.performClick() + } + } + MotionEvent.ACTION_CANCEL -> { + view.isPressed = false + viewModel.onTouchGestureEnded(/* isClick= */ false) + } + } + + return true + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt index a8e346477690..2d83be95183e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt @@ -44,6 +44,8 @@ constructor( private val quickAffordanceInteractor: KeyguardQuickAffordanceInteractor, private val bottomAreaInteractor: KeyguardBottomAreaInteractor, private val burnInHelperWrapper: BurnInHelperWrapper, + private val longPressViewModel: KeyguardLongPressViewModel, + val settingsMenuViewModel: KeyguardSettingsMenuViewModel, ) { data class PreviewMode( val isInPreviewMode: Boolean = false, @@ -161,6 +163,14 @@ constructor( selectedPreviewSlotId.value = slotId } + /** + * Notifies that some input gesture has started somewhere in the bottom area that's outside of + * the lock screen settings menu item pop-up. + */ + fun onTouchedOutsideLockScreenSettingsMenu() { + longPressViewModel.onTouchedOutside() + } + private fun button( position: KeyguardQuickAffordancePosition ): Flow<KeyguardQuickAffordanceViewModel> { @@ -225,9 +235,10 @@ constructor( isDimmed = isDimmed, slotId = slotId, ) - is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel( - slotId = slotId, - ) + is KeyguardQuickAffordanceModel.Hidden -> + KeyguardQuickAffordanceViewModel( + slotId = slotId, + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt index d896390fd471..c73931a12455 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt @@ -17,15 +17,13 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.R -import com.android.systemui.common.shared.model.Icon -import com.android.systemui.common.shared.model.Text +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.KeyguardLongPressInteractor import javax.inject.Inject import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map /** Models UI state to support the lock screen long-press feature. */ +@SysUISingleton class KeyguardLongPressViewModel @Inject constructor( @@ -35,35 +33,16 @@ constructor( /** Whether the long-press handling feature should be enabled. */ val isLongPressHandlingEnabled: Flow<Boolean> = interactor.isLongPressHandlingEnabled - /** View-model for a menu that should be shown; `null` when no menu should be shown. */ - val menu: Flow<KeyguardSettingsPopupMenuViewModel?> = - interactor.menu.map { model -> - model?.let { - KeyguardSettingsPopupMenuViewModel( - icon = - Icon.Resource( - res = R.drawable.ic_settings, - contentDescription = null, - ), - text = - Text.Resource( - res = R.string.lock_screen_settings, - ), - position = model.position, - onClicked = model.onClicked, - onDismissed = model.onDismissed, - ) - } - } - /** Notifies that the user has long-pressed on the lock screen. */ - fun onLongPress( - x: Int, - y: Int, - ) { - interactor.onLongPress( - x = x, - y = y, - ) + fun onLongPress() { + interactor.onLongPress() + } + + /** + * Notifies that some input gesture has started somewhere outside of the lock screen settings + * menu item pop-up. + */ + fun onTouchedOutside() { + interactor.onTouchedOutside() } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsMenuViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsMenuViewModel.kt new file mode 100644 index 000000000000..c36da9da58a5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsMenuViewModel.kt @@ -0,0 +1,60 @@ +/* + * 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.keyguard.ui.viewmodel + +import com.android.systemui.R +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.common.shared.model.Text +import com.android.systemui.keyguard.domain.interactor.KeyguardLongPressInteractor +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +/** Models the UI state of a keyguard settings popup menu. */ +class KeyguardSettingsMenuViewModel +@Inject +constructor( + private val interactor: KeyguardLongPressInteractor, +) { + val isVisible: Flow<Boolean> = interactor.isMenuVisible + val shouldOpenSettings: Flow<Boolean> = interactor.shouldOpenSettings + + val icon: Icon = + Icon.Resource( + res = R.drawable.ic_palette, + contentDescription = null, + ) + + val text: Text = + Text.Resource( + res = R.string.lock_screen_settings, + ) + + fun onTouchGestureStarted() { + interactor.onMenuTouchGestureStarted() + } + + fun onTouchGestureEnded(isClick: Boolean) { + interactor.onMenuTouchGestureEnded( + isClick = isClick, + ) + } + + fun onSettingsShown() { + interactor.onSettingsShown() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsPopupMenuViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsPopupMenuViewModel.kt deleted file mode 100644 index 0571b05b4751..000000000000 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsPopupMenuViewModel.kt +++ /dev/null @@ -1,34 +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.systemui.keyguard.ui.viewmodel - -import com.android.systemui.common.shared.model.Icon -import com.android.systemui.common.shared.model.Position -import com.android.systemui.common.shared.model.Text - -/** Models the UI state of a keyguard settings popup menu. */ -data class KeyguardSettingsPopupMenuViewModel( - val icon: Icon, - val text: Text, - /** Where the menu should be anchored, roughly in screen space. */ - val position: Position, - /** Callback to invoke when the menu gets clicked by the user. */ - val onClicked: () -> Unit, - /** Callback to invoke when the menu gets dismissed by the user. */ - val onDismissed: () -> Unit, -) diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt index f7355d5c11e2..7f6e4a903d76 100644 --- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt @@ -4,6 +4,7 @@ import android.hardware.face.FaceManager import android.hardware.face.FaceSensorPropertiesInternal import com.android.keyguard.FaceAuthUiEvent import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.log.dagger.FaceAuthLog import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.plugins.log.LogLevel.DEBUG @@ -27,15 +28,15 @@ class FaceAuthenticationLogger constructor( @FaceAuthLog private val logBuffer: LogBuffer, ) { - fun ignoredFaceAuthTrigger(uiEvent: FaceAuthUiEvent) { + fun ignoredFaceAuthTrigger(uiEvent: FaceAuthUiEvent, ignoredReason: String) { logBuffer.log( TAG, DEBUG, - { str1 = uiEvent.reason }, { - "Ignoring trigger because face auth is currently running. " + - "Trigger reason: $str1" - } + str1 = uiEvent.reason + str2 = ignoredReason + }, + { "Ignoring trigger because $str2, Trigger reason: $str1" } ) } @@ -135,15 +136,6 @@ constructor( logBuffer.log(TAG, DEBUG, "Face authentication failed") } - fun authenticationAcquired(acquireInfo: Int) { - logBuffer.log( - TAG, - DEBUG, - { int1 = acquireInfo }, - { "Face acquired during face authentication: acquireInfo: $int1 " } - ) - } - fun authenticationError( errorCode: Int, errString: CharSequence?, @@ -217,4 +209,34 @@ constructor( fun cancellingFaceAuth() { logBuffer.log(TAG, DEBUG, "cancelling face auth because a gating condition became false") } + + fun interactorStarted() { + logBuffer.log(TAG, DEBUG, "KeyguardFaceAuthInteractor started") + } + + fun bouncerVisibilityChanged() { + logBuffer.log(TAG, DEBUG, "Triggering face auth because primary bouncer is visible") + } + + fun alternateBouncerVisibilityChanged() { + logBuffer.log(TAG, DEBUG, "Triggering face auth because alternate bouncer is visible") + } + + fun lockscreenBecameVisible(transitionStep: TransitionStep?) { + logBuffer.log( + TAG, + DEBUG, + { str1 = "$transitionStep" }, + { "Triggering face auth because lockscreen became visible due to transition: $str1" } + ) + } + + fun authRequested(uiEvent: FaceAuthUiEvent) { + logBuffer.log( + TAG, + DEBUG, + { str1 = "$uiEvent" }, + { "Requesting face auth for trigger: $str1" } + ) + } } 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 3775e2c6bbee..7edb37832c4f 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -31,6 +31,7 @@ import com.android.systemui.plugins.log.LogcatEchoTrackerDebug; import com.android.systemui.plugins.log.LogcatEchoTrackerProd; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.util.Compile; +import com.android.systemui.util.wakelock.WakeLockLog; import dagger.Module; import dagger.Provides; @@ -168,6 +169,14 @@ public class LogModule { false /* systrace */); } + /** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastSender} */ + @Provides + @SysUISingleton + @WakeLockLog + public static LogBuffer provideWakeLockLog(LogBufferFactory factory) { + return factory.create("WakeLockLog", 500 /* maxSize */, false /* systrace */); + } + /** Provides a logging buffer for all logs related to Toasts shown by SystemUI. */ @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt index 9d2d3553db6d..faaa205b15c2 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt @@ -18,7 +18,7 @@ package com.android.systemui.log.table import android.os.Trace import com.android.systemui.Dumpable -import com.android.systemui.plugins.util.RingBuffer +import com.android.systemui.common.buffer.RingBuffer import com.android.systemui.util.time.SystemClock import java.io.PrintWriter import java.text.SimpleDateFormat diff --git a/packages/SystemUI/src/com/android/systemui/logcat/LogAccessDialogActivity.java b/packages/SystemUI/src/com/android/systemui/logcat/LogAccessDialogActivity.java index 4f5bbb797516..81de607f24f8 100644 --- a/packages/SystemUI/src/com/android/systemui/logcat/LogAccessDialogActivity.java +++ b/packages/SystemUI/src/com/android/systemui/logcat/LogAccessDialogActivity.java @@ -239,7 +239,7 @@ public class LogAccessDialogActivity extends Activity implements if (view.getId() == R.id.log_access_dialog_allow_button) { mCallback.approveAccessForClient(mUid, mPackageName); finish(); - } else if (view.getId() == R.id.log_access_dialog_allow_button) { + } else if (view.getId() == R.id.log_access_dialog_deny_button) { declineLogAccess(); finish(); } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java index c4e76b203f19..ccddd1d359b7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java @@ -60,7 +60,7 @@ import javax.inject.Inject; import dagger.Lazy; public class MediaProjectionPermissionActivity extends Activity - implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener { + implements DialogInterface.OnClickListener { private static final String TAG = "MediaProjectionPermissionActivity"; private static final float MAX_APP_NAME_SIZE_PX = 500f; private static final String ELLIPSIS = "\u2026"; @@ -215,7 +215,8 @@ public class MediaProjectionPermissionActivity extends Activity SystemUIDialog.applyFlags(dialog); SystemUIDialog.setDialogSize(dialog); - dialog.setOnCancelListener(this); + dialog.setOnCancelListener(this::onDialogDismissedOrCancelled); + dialog.setOnDismissListener(this::onDialogDismissedOrCancelled); dialog.create(); dialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); @@ -283,9 +284,10 @@ public class MediaProjectionPermissionActivity extends Activity return intent; } - @Override - public void onCancel(DialogInterface dialog) { - finish(); + private void onDialogDismissedOrCancelled(DialogInterface dialogInterface) { + if (!isFinishing()) { + finish(); + } } private boolean isPartialScreenSharingEnabled() { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt index 4cc041074a8d..9997730fa938 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt @@ -43,14 +43,17 @@ import android.media.session.PlaybackState import android.net.Uri import android.os.Parcelable import android.os.Process +import android.os.RemoteException import android.os.UserHandle import android.provider.Settings import android.service.notification.StatusBarNotification import android.support.v4.media.MediaMetadataCompat import android.text.TextUtils import android.util.Log +import android.util.Pair as APair import androidx.media.utils.MediaConstants import com.android.internal.logging.InstanceId +import com.android.internal.statusbar.IStatusBarService import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.Dumpable import com.android.systemui.R @@ -136,6 +139,8 @@ internal val EMPTY_SMARTSPACE_MEDIA_DATA = expiryTimeMs = 0, ) +const val MEDIA_TITLE_ERROR_MESSAGE = "Invalid media data: title is null or blank." + fun isMediaNotification(sbn: StatusBarNotification): Boolean { return sbn.notification.isMediaNotification() } @@ -180,6 +185,7 @@ class MediaDataManager( private val logger: MediaUiEventLogger, private val smartspaceManager: SmartspaceManager, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val statusBarService: IStatusBarService, ) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener { companion object { @@ -217,6 +223,13 @@ class MediaDataManager( private var smartspaceSession: SmartspaceSession? = null private var allowMediaRecommendations = allowMediaRecommendations(context) + private val artworkWidth = + context.resources.getDimensionPixelSize( + com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize + ) + private val artworkHeight = + context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded) + /** Check whether this notification is an RCN */ private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean { return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE) @@ -244,6 +257,7 @@ class MediaDataManager( mediaFlags: MediaFlags, logger: MediaUiEventLogger, smartspaceManager: SmartspaceManager, + statusBarService: IStatusBarService, keyguardUpdateMonitor: KeyguardUpdateMonitor, ) : this( context, @@ -269,6 +283,7 @@ class MediaDataManager( logger, smartspaceManager, keyguardUpdateMonitor, + statusBarService, ) private val appChangeReceiver = @@ -370,21 +385,21 @@ class MediaDataManager( fun onNotificationAdded(key: String, sbn: StatusBarNotification) { if (useQsMediaPlayer && isMediaNotification(sbn)) { - var logEvent = false + var isNewlyActiveEntry = false Assert.isMainThread() val oldKey = findExistingEntry(key, sbn.packageName) if (oldKey == null) { val instanceId = logger.getNewInstanceId() val temp = LOADING.copy(packageName = sbn.packageName, instanceId = instanceId) mediaEntries.put(key, temp) - logEvent = true + isNewlyActiveEntry = true } else if (oldKey != key) { // Resume -> active conversion; move to new key val oldData = mediaEntries.remove(oldKey)!! - logEvent = true + isNewlyActiveEntry = true mediaEntries.put(key, oldData) } - loadMediaData(key, sbn, oldKey, logEvent) + loadMediaData(key, sbn, oldKey, isNewlyActiveEntry) } else { onNotificationRemoved(key) } @@ -467,9 +482,9 @@ class MediaDataManager( key: String, sbn: StatusBarNotification, oldKey: String?, - logEvent: Boolean = false + isNewlyActiveEntry: Boolean = false, ) { - backgroundExecutor.execute { loadMediaDataInBg(key, sbn, oldKey, logEvent) } + backgroundExecutor.execute { loadMediaDataInBg(key, sbn, oldKey, isNewlyActiveEntry) } } /** Add a listener for changes in this class */ @@ -593,9 +608,11 @@ class MediaDataManager( } } - private fun removeEntry(key: String) { + private fun removeEntry(key: String, logEvent: Boolean = true) { mediaEntries.remove(key)?.let { - logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId) + if (logEvent) { + logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId) + } } notifyMediaDataRemoved(key) } @@ -743,7 +760,7 @@ class MediaDataManager( key: String, sbn: StatusBarNotification, oldKey: String?, - logEvent: Boolean = false + isNewlyActiveEntry: Boolean = false, ) { val token = sbn.notification.extras.getParcelable( @@ -757,6 +774,34 @@ class MediaDataManager( val metadata = mediaController.metadata val notif: Notification = sbn.notification + // Song name + var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) + if (song == null) { + song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE) + } + if (song == null) { + song = HybridGroupManager.resolveTitle(notif) + } + // Media data must have a title. + if (song.isNullOrBlank()) { + try { + statusBarService.onNotificationError( + sbn.packageName, + sbn.tag, + sbn.id, + sbn.uid, + sbn.initialPid, + MEDIA_TITLE_ERROR_MESSAGE, + sbn.user.identifier + ) + } catch (e: RemoteException) { + Log.e(TAG, "cancelNotification failed: $e") + } + // Only add log for media removed if active media is updated with invalid title. + foregroundExecutor.execute { removeEntry(key, !isNewlyActiveEntry) } + return + } + val appInfo = notif.extras.getParcelable( Notification.EXTRA_BUILDER_APPLICATION_INFO, @@ -785,15 +830,6 @@ class MediaDataManager( // App Icon val smallIcon = sbn.notification.smallIcon - // Song name - var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) - if (song == null) { - song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE) - } - if (song == null) { - song = HybridGroupManager.resolveTitle(notif) - } - // Explicit Indicator var isExplicit = false if (mediaFlags.isExplicitIndicatorEnabled()) { @@ -865,7 +901,7 @@ class MediaDataManager( val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId() val appUid = appInfo?.uid ?: Process.INVALID_UID - if (logEvent) { + if (isNewlyActiveEntry) { logSingleVsMultipleMediaAdded(appUid, sbn.packageName, instanceId) logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation) } else if (playbackLocation != currentEntry?.playbackLocation) { @@ -1250,9 +1286,21 @@ class MediaDataManager( return null } - val source = ImageDecoder.createSource(context.getContentResolver(), uri) + val source = ImageDecoder.createSource(context.contentResolver, uri) return try { - ImageDecoder.decodeBitmap(source) { decoder, _, _ -> + ImageDecoder.decodeBitmap(source) { decoder, info, _ -> + val width = info.size.width + val height = info.size.height + val scale = + MediaDataUtils.getScaleFactor( + APair(width, height), + APair(artworkWidth, artworkHeight) + ) + + // Downscale if needed + if (scale != 0f && scale < 1) { + decoder.setTargetSize((scale * width).toInt(), (scale * height).toInt()) + } decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE } } catch (e: IOException) { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt index a1d9214cb215..ed4eef9eaa2b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt @@ -17,6 +17,7 @@ package com.android.systemui.media.controls.pipeline import android.media.session.MediaController +import android.media.session.MediaSession import android.media.session.PlaybackState import android.os.SystemProperties import com.android.internal.annotations.VisibleForTesting @@ -148,7 +149,7 @@ constructor( reusedListener?.let { val wasPlaying = it.isPlaying() logger.logUpdateListener(key, wasPlaying) - it.mediaData = data + it.setMediaData(data) it.key = key mediaListeners[key] = it if (wasPlaying != it.isPlaying()) { @@ -208,24 +209,7 @@ constructor( var resumption: Boolean? = null var destroyed = false var expiration = Long.MAX_VALUE - - var mediaData: MediaData = data - set(value) { - destroyed = false - mediaController?.unregisterCallback(this) - field = value - val token = field.token - mediaController = - if (token != null) { - mediaControllerFactory.create(token) - } else { - null - } - mediaController?.registerCallback(this) - // Let's register the cancellations, but not dispatch events now. - // Timeouts didn't happen yet and reentrant events are troublesome. - processState(mediaController?.playbackState, dispatchEvents = false) - } + var sessionToken: MediaSession.Token? = null // Resume controls may have null token private var mediaController: MediaController? = null @@ -236,7 +220,7 @@ constructor( fun isPlaying() = lastState?.state?.isPlaying() ?: false init { - mediaData = data + setMediaData(data) } fun destroy() { @@ -245,8 +229,28 @@ constructor( destroyed = true } + fun setMediaData(data: MediaData) { + sessionToken = data.token + destroyed = false + mediaController?.unregisterCallback(this) + mediaController = + if (data.token != null) { + mediaControllerFactory.create(data.token) + } else { + null + } + mediaController?.registerCallback(this) + // Let's register the cancellations, but not dispatch events now. + // Timeouts didn't happen yet and reentrant events are troublesome. + processState( + mediaController?.playbackState, + dispatchEvents = false, + currentResumption = data.resumption, + ) + } + override fun onPlaybackStateChanged(state: PlaybackState?) { - processState(state, dispatchEvents = true) + processState(state, dispatchEvents = true, currentResumption = resumption) } override fun onSessionDestroyed() { @@ -263,14 +267,18 @@ constructor( } } - private fun processState(state: PlaybackState?, dispatchEvents: Boolean) { + private fun processState( + state: PlaybackState?, + dispatchEvents: Boolean, + currentResumption: Boolean?, + ) { logger.logPlaybackState(key, state) val playingStateSame = (state?.state?.isPlaying() == isPlaying()) val actionsSame = (lastState?.actions == state?.actions) && areCustomActionListsEqual(lastState?.customActions, state?.customActions) - val resumptionChanged = resumption != mediaData.resumption + val resumptionChanged = resumption != currentResumption lastState = state @@ -282,7 +290,7 @@ constructor( if (playingStateSame && !resumptionChanged) { return } - resumption = mediaData.resumption + resumption = currentResumption val playing = isPlaying() if (!playing) { @@ -294,7 +302,7 @@ constructor( } expireMediaTimeout(key, "PLAYBACK STATE CHANGED - $state, $resumption") val timeout = - if (mediaData.resumption) { + if (currentResumption == true) { RESUME_MEDIA_TIMEOUT } else { PAUSED_MEDIA_TIMEOUT diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index cb1f12cf412f..40027a1d8f2c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -56,6 +56,7 @@ import android.os.Process; import android.os.Trace; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -122,6 +123,11 @@ import com.android.systemui.util.animation.TransitionLayout; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.time.SystemClock; +import dagger.Lazy; + +import kotlin.Triple; +import kotlin.Unit; + import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; @@ -129,10 +135,6 @@ import java.util.concurrent.Executor; import javax.inject.Inject; -import dagger.Lazy; -import kotlin.Triple; -import kotlin.Unit; - /** * A view controller used for Media Playback. */ @@ -1000,18 +1002,9 @@ public class MediaControlPanel { int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); - if (width == 0 || height == 0 || targetWidth == 0 || targetHeight == 0) { - return; - } - - float scale; - if ((width / (float) height) > (targetWidth / (float) targetHeight)) { - // Drawable is wider than target view, scale to match height - scale = targetHeight / (float) height; - } else { - // Drawable is taller than target view, scale to match width - scale = targetWidth / (float) width; - } + float scale = MediaDataUtils.getScaleFactor(new Pair(width, height), + new Pair(targetWidth, targetHeight)); + if (scale == 0) return; transitionDrawable.setLayerSize(layer, (int) (scale * width), (int) (scale * height)); } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java index e95106e0987a..0239d367e52d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java @@ -22,6 +22,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; import android.text.TextUtils; +import android.util.Pair; import androidx.core.math.MathUtils; import androidx.media.utils.MediaConstants; @@ -87,4 +88,32 @@ public class MediaDataUtils { } return null; } + + /** + * Calculate a scale factor that will allow the input to fill the target size. + * + * @param input width, height of the input view + * @param target width, height of the target view + * @return the scale factor; 0 if any given dimension is 0 + */ + public static float getScaleFactor(Pair<Integer, Integer> input, + Pair<Integer, Integer> target) { + float width = (float) input.first; + float height = (float) input.second; + + float targetWidth = (float) target.first; + float targetHeight = (float) target.second; + + if (width == 0 || height == 0 || targetWidth == 0 || targetHeight == 0) { + return 0f; + } + + if ((width / height) > (targetWidth / targetHeight)) { + // Input is wider than target view, scale to match height + return targetHeight / height; + } else { + // Input is taller than target view, scale to match width + return targetWidth / width; + } + } } 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 9606bcf3fd9b..08e47a09bab9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java @@ -273,8 +273,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements } @Override - public void onStart() { - super.onStart(); + public void start() { mMediaOutputController.start(this); if (isBroadcastSupported() && !mIsLeBroadcastCallbackRegistered) { mMediaOutputController.registerLeBroadcastServiceCallback(mExecutor, @@ -284,8 +283,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements } @Override - public void onStop() { - super.onStop(); + public void stop() { if (isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) { mMediaOutputController.unregisterLeBroadcastServiceCallback(mBroadcastCallback); mIsLeBroadcastCallbackRegistered = false; 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 f0ff1409faf1..abf0932c8407 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java @@ -212,8 +212,8 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } @Override - public void onStart() { - super.onStart(); + public void start() { + super.start(); if (!mIsLeBroadcastAssistantCallbackRegistered) { mIsLeBroadcastAssistantCallbackRegistered = true; mMediaOutputController.registerLeBroadcastAssistantServiceCallback(mExecutor, @@ -223,8 +223,8 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } @Override - public void onStop() { - super.onStop(); + public void stop() { + super.stop(); if (mIsLeBroadcastAssistantCallbackRegistered) { mIsLeBroadcastAssistantCallbackRegistered = false; mMediaOutputController.unregisterLeBroadcastAssistantServiceCallback( diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaComplicationViewController.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaComplicationViewController.java index 69b5698b9042..b4153d72e64c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaComplicationViewController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaComplicationViewController.java @@ -31,7 +31,7 @@ import javax.inject.Named; /** * {@link MediaComplicationViewController} handles connecting the - * {@link com.android.systemui.dreams.complication.Complication} view to the {@link MediaHost}. + * {@link com.android.systemui.complication.Complication} view to the {@link MediaHost}. */ public class MediaComplicationViewController extends ViewController<FrameLayout> { private final MediaHost mMediaHost; diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java index 2c35db337cda..96c870ded33c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java +++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java @@ -16,8 +16,8 @@ package com.android.systemui.media.dream; -import com.android.systemui.dreams.complication.Complication; -import com.android.systemui.dreams.complication.ComplicationViewModel; +import com.android.systemui.complication.Complication; +import com.android.systemui.complication.ComplicationViewModel; import com.android.systemui.media.dream.dagger.MediaComplicationComponent; import javax.inject.Inject; diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java index 20e8ae6719f3..08c626c9e0eb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java +++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java @@ -24,8 +24,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.CoreStartable; +import com.android.systemui.complication.DreamMediaEntryComplication; import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.dreams.complication.DreamMediaEntryComplication; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.controls.models.player.MediaData; import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData; diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaViewHolder.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaViewHolder.java index 128a38c639be..80d322fd5547 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaViewHolder.java +++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaViewHolder.java @@ -22,8 +22,8 @@ import static com.android.systemui.media.dream.dagger.MediaComplicationComponent import android.view.View; import android.widget.FrameLayout; -import com.android.systemui.dreams.complication.Complication; -import com.android.systemui.dreams.complication.ComplicationLayoutParams; +import com.android.systemui.complication.Complication; +import com.android.systemui.complication.ComplicationLayoutParams; import javax.inject.Inject; import javax.inject.Named; diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java index 052608f17e0e..72573a5f1321 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java +++ b/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java @@ -16,7 +16,7 @@ package com.android.systemui.media.dream.dagger; -import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_COMPLICATION_WEIGHT; +import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_COMPLICATION_WEIGHT; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -24,22 +24,22 @@ import android.content.Context; import android.view.ViewGroup; import android.widget.FrameLayout; -import com.android.systemui.dreams.complication.ComplicationLayoutParams; +import com.android.systemui.complication.ComplicationLayoutParams; import com.android.systemui.media.dream.MediaViewHolder; +import dagger.Module; +import dagger.Provides; +import dagger.Subcomponent; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; import javax.inject.Named; import javax.inject.Scope; -import dagger.Module; -import dagger.Provides; -import dagger.Subcomponent; - /** * {@link MediaComplicationComponent} is responsible for generating dependencies surrounding the - * media {@link com.android.systemui.dreams.complication.Complication}, such as view controllers + * media {@link com.android.systemui.complication.Complication}, such as view controllers * and layout details. */ @Subcomponent(modules = { diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt index dbc2a5ec4e0a..b29b5887545a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt @@ -19,7 +19,7 @@ package com.android.systemui.media.taptotransfer.common import android.content.Context import android.content.pm.PackageManager import android.graphics.drawable.Drawable -import androidx.annotation.ColorRes +import androidx.annotation.AttrRes import androidx.annotation.DrawableRes import com.android.systemui.R import com.android.systemui.common.shared.model.ContentDescription @@ -108,7 +108,7 @@ class MediaTttUtils { data class IconInfo( val contentDescription: ContentDescription, val icon: MediaTttIcon, - @ColorRes val tint: Int?, + @AttrRes val tint: Int?, /** * True if [drawable] is the app's icon, and false if [drawable] is some generic default icon. */ diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt index 70040c75d123..c804df8fa555 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt @@ -363,12 +363,8 @@ class BackPanel( } fun popOffEdge(startingVelocity: Float) { - val heightStretchAmount = startingVelocity * 50 - val widthStretchAmount = startingVelocity * 150 - val scaleStretchAmount = startingVelocity * 0.8f - backgroundHeight.stretchTo(stretchAmount = 0f, startingVelocity = -heightStretchAmount) - backgroundWidth.stretchTo(stretchAmount = 0f, startingVelocity = widthStretchAmount) - scale.stretchTo(stretchAmount = 0f, startingVelocity = -scaleStretchAmount) + scale.stretchTo(stretchAmount = 0f, startingVelocity = startingVelocity * -.8f) + horizontalTranslation.stretchTo(stretchAmount = 0f, startingVelocity * 200f) } fun popScale(startingVelocity: Float) { @@ -410,7 +406,7 @@ class BackPanel( arrowAlpha.updateRestingPosition(restingParams.arrowDimens.alpha, animate) arrowLength.updateRestingPosition(restingParams.arrowDimens.length, animate) arrowHeight.updateRestingPosition(restingParams.arrowDimens.height, animate) - scalePivotX.updateRestingPosition(restingParams.backgroundDimens.width, animate) + scalePivotX.updateRestingPosition(restingParams.scalePivotX, animate) backgroundWidth.updateRestingPosition(restingParams.backgroundDimens.width, animate) backgroundHeight.updateRestingPosition(restingParams.backgroundDimens.height, animate) backgroundEdgeCornerRadius.updateRestingPosition( 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 a29eb3bda748..3770b2885b18 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt @@ -49,6 +49,7 @@ import kotlin.math.sign private const val TAG = "BackPanelController" private const val ENABLE_FAILSAFE = true +private const val FAILSAFE_DELAY_MS = 350L private const val PX_PER_SEC = 1000 private const val PX_PER_MS = 1 @@ -64,9 +65,9 @@ private const val MIN_DURATION_FLING_ANIMATION = 160L private const val MIN_DURATION_ENTRY_TO_ACTIVE_CONSIDERED_AS_FLING = 100L private const val MIN_DURATION_INACTIVE_TO_ACTIVE_CONSIDERED_AS_FLING = 400L -private const val FAILSAFE_DELAY_MS = 350L -private const val POP_ON_FLING_DELAY = 50L -private const val POP_ON_FLING_SCALE = 3f +private const val POP_ON_FLING_DELAY = 60L +private const val POP_ON_FLING_SCALE = 2f +private const val POP_ON_COMMITTED_SCALE = 3f internal val VIBRATE_ACTIVATED_EFFECT = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK) @@ -774,7 +775,9 @@ class BackPanelController internal constructor( GestureState.ENTRY, GestureState.INACTIVE, GestureState.CANCELLED -> params.preThresholdIndicator.scalePivotX - else -> params.committedIndicator.scalePivotX + GestureState.ACTIVE -> params.activeIndicator.scalePivotX + GestureState.FLUNG, + GestureState.COMMITTED -> params.committedIndicator.scalePivotX }, horizontalTranslation = when (currentState) { GestureState.GONE -> { @@ -921,7 +924,7 @@ class BackPanelController internal constructor( mainHandler.postDelayed(onEndSetGoneStateListener.runnable, MIN_DURATION_COMMITTED_AFTER_FLING_ANIMATION) } else { - mView.popScale(POP_ON_FLING_SCALE) + mView.popScale(POP_ON_COMMITTED_SCALE) mainHandler.postDelayed(onAlphaEndSetGoneStateListener.runnable, MIN_DURATION_COMMITTED_ANIMATION) } 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 26b0e8dd9895..b9ef916eebdf 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -55,6 +55,7 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; +import android.view.VelocityTracker; import android.view.ViewConfiguration; import android.view.WindowInsets; import android.view.WindowManager; @@ -173,7 +174,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack } }; - + private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); private final Context mContext; private final UserTracker mUserTracker; private final OverviewProxyService mOverviewProxyService; @@ -901,6 +902,10 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack Log.d(DEBUG_MISSING_GESTURE_TAG, "Start gesture: " + ev); } + // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new + // ACTION_DOWN, in that case we should just reuse the old instance. + mVelocityTracker.clear(); + // 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); @@ -1027,11 +1032,30 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack private void dispatchToBackAnimation(MotionEvent event) { if (mBackAnimation != null) { + mVelocityTracker.addMovement(event); + + final float velocityX; + final float velocityY; + if (event.getAction() == MotionEvent.ACTION_UP) { + // Compute the current velocity is expensive (see computeCurrentVelocity), so we + // are only doing it when the user completes the gesture. + int unitPixelPerSecond = 1000; + int maxVelocity = mViewConfiguration.getScaledMaximumFlingVelocity(); + mVelocityTracker.computeCurrentVelocity(unitPixelPerSecond, maxVelocity); + velocityX = mVelocityTracker.getXVelocity(); + velocityY = mVelocityTracker.getYVelocity(); + } else { + velocityX = Float.NaN; + velocityY = Float.NaN; + } + mBackAnimation.onBackMotion( - event.getX(), - event.getY(), - event.getActionMasked(), - mIsOnLeftEdge ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT); + /* touchX = */ event.getX(), + /* touchY = */ event.getY(), + /* velocityX = */ velocityX, + /* velocityY = */ velocityY, + /* keyAction = */ event.getActionMasked(), + /* swipeEdge = */ mIsOnLeftEdge ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT); } } 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 6ce6f0d5f722..c9d8c8495dcc 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt @@ -35,7 +35,7 @@ data class EdgePanelParams(private var resources: Resources) { data class BackIndicatorDimens( val horizontalTranslation: Float? = 0f, val scale: Float = 0f, - val scalePivotX: Float = 0f, + val scalePivotX: Float? = null, val arrowDimens: ArrowDimens, val backgroundDimens: BackgroundDimens, val verticalTranslationSpring: SpringForce? = null, @@ -203,7 +203,8 @@ data class EdgePanelParams(private var resources: Resources) { horizontalTranslation = getDimen(R.dimen.navigation_edge_active_margin), scale = getDimenFloat(R.dimen.navigation_edge_active_scale), horizontalTranslationSpring = entryActiveHorizontalTranslationSpring, - scaleSpring = createSpring(450f, 0.415f), + scaleSpring = createSpring(450f, 0.39f), + scalePivotX = getDimen(R.dimen.navigation_edge_active_background_width), arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_active_arrow_length), height = getDimen(R.dimen.navigation_edge_active_arrow_height), @@ -258,6 +259,7 @@ data class EdgePanelParams(private var resources: Resources) { committedIndicator = activeIndicator.copy( horizontalTranslation = null, + scalePivotX = null, arrowDimens = activeIndicator.arrowDimens.copy( lengthSpring = activeCommittedArrowLengthSpring, heightSpring = activeCommittedArrowHeightSpring, diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt index 334c70b217a3..5f4e7cac4452 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt @@ -34,7 +34,9 @@ import android.os.Build import android.os.UserHandle import android.os.UserManager import android.util.Log +import android.widget.Toast import androidx.annotation.VisibleForTesting +import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser @@ -170,7 +172,13 @@ constructor( return } - val info = resolver.resolveInfo(entryPoint, isKeyguardLocked) ?: return + val info = resolver.resolveInfo(entryPoint, isKeyguardLocked) + + if (info == null) { + logDebug { "Default notes app isn't set" } + showNoDefaultNotesAppToast() + return + } infoReference.set(info) @@ -207,6 +215,12 @@ constructor( logDebug { "onShowNoteTask - completed: $info" } } + @VisibleForTesting + fun showNoDefaultNotesAppToast() { + Toast.makeText(context, R.string.set_default_notes_app_toast_content, Toast.LENGTH_SHORT) + .show() + } + /** * Set `android:enabled` property in the `AndroidManifest` associated with the Shortcut * component to [value]. @@ -214,7 +228,7 @@ constructor( * If the shortcut entry `android:enabled` is set to `true`, the shortcut will be visible in the * Widget Picker to all users. */ - fun setNoteTaskShortcutEnabled(value: Boolean) { + fun setNoteTaskShortcutEnabled(value: Boolean, user: UserHandle) { val componentName = ComponentName(context, CreateNoteTaskShortcutActivity::class.java) val enabledState = @@ -224,7 +238,16 @@ constructor( PackageManager.COMPONENT_ENABLED_STATE_DISABLED } - context.packageManager.setComponentEnabledSetting( + // If the required user matches the tracking user, the injected context is already a context + // of the required user. Avoid calling #createContextAsUser because creating a context for + // a user takes time. + val userContext = + if (user == userTracker.userHandle) { + context + } else { + context.createContextAsUser(user, /* flags= */ 0) + } + userContext.packageManager.setComponentEnabledSetting( componentName, enabledState, PackageManager.DONT_KILL_APP, @@ -246,7 +269,7 @@ constructor( val packageName = roleManager.getDefaultRoleHolderAsUser(ROLE_NOTES, user) val hasNotesRoleHolder = isEnabled && !packageName.isNullOrEmpty() - setNoteTaskShortcutEnabled(hasNotesRoleHolder) + setNoteTaskShortcutEnabled(hasNotesRoleHolder, user) if (hasNotesRoleHolder) { shortcutManager.enableShortcuts(listOf(SHORTCUT_ID)) diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt index 23ee13b4deac..7bb615b8d866 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt @@ -20,6 +20,7 @@ import android.os.UserHandle import android.view.KeyEvent import androidx.annotation.VisibleForTesting import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.CommandQueue import com.android.wm.shell.bubbles.Bubbles import java.util.Optional @@ -36,6 +37,7 @@ constructor( private val optionalBubbles: Optional<Bubbles>, @Background private val backgroundExecutor: Executor, @NoteTaskEnabledKey private val isEnabled: Boolean, + private val userTracker: UserTracker, ) { @VisibleForTesting @@ -44,8 +46,9 @@ constructor( override fun handleSystemKey(key: KeyEvent) { if (key.keyCode == KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL) { controller.showNoteTask(NoteTaskEntryPoint.TAIL_BUTTON) - } else if (key.keyCode == KeyEvent.KEYCODE_N && key.isMetaPressed && - key.isCtrlPressed) { + } else if ( + key.keyCode == KeyEvent.KEYCODE_N && key.isMetaPressed && key.isCtrlPressed + ) { controller.showNoteTask(NoteTaskEntryPoint.KEYBOARD_SHORTCUT) } } @@ -55,7 +58,7 @@ constructor( // Guard against feature not being enabled or mandatory dependencies aren't available. if (!isEnabled || optionalBubbles.isEmpty) return - controller.setNoteTaskShortcutEnabled(true) + controller.setNoteTaskShortcutEnabled(true, userTracker.userHandle) commandQueue.addCallback(callbacks) roleManager.addOnRoleHoldersChangedListenerAsUser( backgroundExecutor, diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt index 44855fb7c8cc..0f38d32e0b64 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt @@ -18,9 +18,11 @@ package com.android.systemui.notetask.shortcut import android.content.Context import android.content.Intent -import android.content.pm.UserInfo +import android.os.Build import android.os.Bundle +import android.os.UserHandle import android.os.UserManager +import android.util.Log import androidx.activity.ComponentActivity import com.android.systemui.notetask.NoteTaskController import com.android.systemui.notetask.NoteTaskEntryPoint @@ -63,9 +65,13 @@ constructor( // | Bubble#showOrHideAppBubble | <-------------- // | (with WP user ID) | // ---------------------------- - val mainUser: UserInfo? = userTracker.userProfiles.firstOrNull { it.isMain } - if (userManager.isManagedProfile && mainUser != null) { - controller.startNoteTaskProxyActivityForUser(mainUser.userHandle) + val mainUser: UserHandle? = userManager.mainUser + if (userManager.isManagedProfile) { + if (mainUser == null) { + logDebug { "Can't find the main user. Skipping the notes app launch." } + } else { + controller.startNoteTaskProxyActivityForUser(mainUser) + } } else { controller.showNoteTask(entryPoint = NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT) } @@ -83,3 +89,8 @@ constructor( } } } + +/** [Log.println] a [Log.DEBUG] message, only when [Build.IS_DEBUGGABLE]. */ +private inline fun Any.logDebug(message: () -> String) { + if (Build.IS_DEBUGGABLE) Log.d(this::class.java.simpleName.orEmpty(), message()) +} diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index c2c1306d2a32..a765702a95b2 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -18,6 +18,10 @@ package com.android.systemui.power; import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_CONFIRMATION; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_LOW_WARNING; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.SaverManualEnabledReason; + import android.app.Dialog; import android.app.KeyguardManager; import android.app.Notification; @@ -691,7 +695,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { d.setTitle(R.string.battery_saver_confirmation_title); d.setPositiveButton(R.string.battery_saver_confirmation_ok, (dialog, which) -> { - setSaverMode(true, false); + setSaverMode(true, false, SAVER_ENABLED_CONFIRMATION); logEvent(BatteryWarningEvents.LowBatteryWarningEvent.SAVER_CONFIRM_OK); }); d.setNegativeButton(android.R.string.cancel, (dialog, which) -> @@ -790,8 +794,9 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { return builder; } - private void setSaverMode(boolean mode, boolean needFirstTimeWarning) { - BatterySaverUtils.setPowerSaveMode(mContext, mode, needFirstTimeWarning); + private void setSaverMode(boolean mode, boolean needFirstTimeWarning, + @SaverManualEnabledReason int reason) { + BatterySaverUtils.setPowerSaveMode(mContext, mode, needFirstTimeWarning, reason); } private void startBatterySaverSchedulePage() { @@ -839,7 +844,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } else if (action.equals(ACTION_START_SAVER)) { logEvent(BatteryWarningEvents .LowBatteryWarningEvent.LOW_BATTERY_NOTIFICATION_TURN_ON); - setSaverMode(true, true); + setSaverMode(true, true, SAVER_ENABLED_LOW_WARNING); dismissLowBatteryNotification(); } else if (action.equals(ACTION_SHOW_START_SAVER_CONFIRMATION)) { dismissLowBatteryNotification(); diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt index 03145a714289..35a7cf1bf402 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt @@ -90,8 +90,7 @@ class PrivacyDialog( } } - override fun onStop() { - super.onStop() + override fun stop() { dismissed.set(true) val iterator = dismissListeners.iterator() while (iterator.hasNext()) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index ce690e239da0..856c64a52290 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -20,14 +20,10 @@ import android.content.res.Resources; import android.os.Build; import android.provider.Settings; -import com.android.internal.logging.InstanceId; -import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.plugins.qs.QSFactory; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTileView; -import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository; -import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor; import com.android.systemui.util.leak.GarbageMonitor; import java.util.ArrayList; @@ -35,7 +31,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -public interface QSHost extends PanelInteractor, CustomTileAddedRepository { +public interface QSHost { String TILES_SETTING = Settings.Secure.QS_TILES; int POSITION_AT_END = -1; @@ -57,11 +53,9 @@ public interface QSHost extends PanelInteractor, CustomTileAddedRepository { return tiles; } - void warn(String message, Throwable t); Context getContext(); Context getUserContext(); int getUserId(); - UiEventLogger getUiEventLogger(); Collection<QSTile> getTiles(); void addCallback(Callback callback); void removeCallback(Callback callback); @@ -75,7 +69,11 @@ public interface QSHost extends PanelInteractor, CustomTileAddedRepository { * @see QSFactory#createTileView */ QSTileView createTileView(Context themedContext, QSTile tile, boolean collapsedView); - /** Create a {@link QSTile} of a {@code tileSpec} type. */ + /** Create a {@link QSTile} of a {@code tileSpec} type. + * + * This should only be called by classes that need to create one-off instances of tiles. + * Do not use to create {@code custom} tiles without explicitly taking care of its lifecycle. + */ QSTile createTile(String tileSpec); /** @@ -105,8 +103,6 @@ public interface QSHost extends PanelInteractor, CustomTileAddedRepository { int indexOf(String tileSpec); - InstanceId getNewInstanceId(); - interface Callback { void onTilesChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt new file mode 100644 index 000000000000..67927a4153b3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt @@ -0,0 +1,202 @@ +/* + * 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 + +import android.content.ComponentName +import android.content.Context +import androidx.annotation.GuardedBy +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dump.DumpManager +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.plugins.qs.QSTileView +import com.android.systemui.qs.external.TileServiceRequestController +import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END +import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor +import com.android.systemui.qs.pipeline.shared.TileSpec +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch + +/** + * Adapter to determine what real class to use for classes that depend on [QSHost]. + * * When [Flags.QS_PIPELINE_NEW_HOST] is off, all calls will be routed to [QSTileHost]. + * * When [Flags.QS_PIPELINE_NEW_HOST] is on, calls regarding the current set of tiles will be + * routed to [CurrentTilesInteractor]. Other calls (like [createTileView]) will still be routed to + * [QSTileHost]. + * + * This routing also includes dumps. + */ +@SysUISingleton +class QSHostAdapter +@Inject +constructor( + private val qsTileHost: QSTileHost, + private val interactor: CurrentTilesInteractor, + private val context: Context, + private val tileServiceRequestControllerBuilder: TileServiceRequestController.Builder, + @Application private val scope: CoroutineScope, + private val featureFlags: FeatureFlags, + dumpManager: DumpManager, +) : QSHost { + + companion object { + private const val TAG = "QSTileHost" + } + + private val useNewHost = featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST) + + @GuardedBy("callbacksMap") private val callbacksMap = mutableMapOf<QSHost.Callback, Job>() + + init { + scope.launch { tileServiceRequestControllerBuilder.create(this@QSHostAdapter).init() } + // Redirect dump to the correct host (needed for CTS tests) + dumpManager.registerCriticalDumpable(TAG, if (useNewHost) interactor else qsTileHost) + } + + override fun getTiles(): Collection<QSTile> { + return if (useNewHost) { + interactor.currentQSTiles + } else { + qsTileHost.getTiles() + } + } + + override fun getSpecs(): List<String> { + return if (useNewHost) { + interactor.currentTilesSpecs.map { it.spec } + } else { + qsTileHost.getSpecs() + } + } + + override fun removeTile(spec: String) { + if (useNewHost) { + interactor.removeTiles(listOf(TileSpec.create(spec))) + } else { + qsTileHost.removeTile(spec) + } + } + + override fun addCallback(callback: QSHost.Callback) { + if (useNewHost) { + val job = scope.launch { interactor.currentTiles.collect { callback.onTilesChanged() } } + synchronized(callbacksMap) { callbacksMap.put(callback, job) } + } else { + qsTileHost.addCallback(callback) + } + } + + override fun removeCallback(callback: QSHost.Callback) { + if (useNewHost) { + synchronized(callbacksMap) { callbacksMap.get(callback)?.cancel() } + } else { + qsTileHost.removeCallback(callback) + } + } + + override fun removeTiles(specs: Collection<String>) { + if (useNewHost) { + interactor.removeTiles(specs.map(TileSpec::create)) + } else { + qsTileHost.removeTiles(specs) + } + } + + override fun removeTileByUser(component: ComponentName) { + if (useNewHost) { + interactor.removeTiles(listOf(TileSpec.create(component))) + } else { + qsTileHost.removeTileByUser(component) + } + } + + override fun addTile(spec: String, position: Int) { + if (useNewHost) { + interactor.addTile(TileSpec.create(spec), position) + } else { + qsTileHost.addTile(spec, position) + } + } + + override fun addTile(component: ComponentName, end: Boolean) { + if (useNewHost) { + interactor.addTile(TileSpec.create(component), if (end) POSITION_AT_END else 0) + } else { + qsTileHost.addTile(component, end) + } + } + + override fun changeTilesByUser(previousTiles: List<String>, newTiles: List<String>) { + if (useNewHost) { + interactor.setTiles(newTiles.map(TileSpec::create)) + } else { + qsTileHost.changeTilesByUser(previousTiles, newTiles) + } + } + + override fun getContext(): Context { + return if (useNewHost) { + context + } else { + qsTileHost.context + } + } + + override fun getUserContext(): Context { + return if (useNewHost) { + interactor.userContext.value + } else { + qsTileHost.userContext + } + } + + override fun getUserId(): Int { + return if (useNewHost) { + interactor.userId.value + } else { + qsTileHost.userId + } + } + + override fun createTileView( + themedContext: Context?, + tile: QSTile?, + collapsedView: Boolean + ): QSTileView { + return qsTileHost.createTileView(themedContext, tile, collapsedView) + } + + override fun createTile(tileSpec: String): QSTile? { + return qsTileHost.createTile(tileSpec) + } + + override fun addTile(spec: String) { + return addTile(spec, QSHost.POSITION_AT_END) + } + + override fun addTile(tile: ComponentName) { + return addTile(tile, false) + } + + override fun indexOf(tileSpec: String): Int { + return specs.indexOf(tileSpec) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 8bbdeeda356c..59b94b7c4bd4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -29,16 +29,14 @@ import androidx.annotation.MainThread; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.logging.InstanceId; -import com.android.internal.logging.InstanceIdSequence; -import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dumpable; import com.android.systemui.ProtoDumpable; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.nano.SystemUIProtoDump; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.qs.QSFactory; @@ -48,9 +46,10 @@ import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.external.CustomTileStatePersister; import com.android.systemui.qs.external.TileLifecycleManager; import com.android.systemui.qs.external.TileServiceKey; -import com.android.systemui.qs.external.TileServiceRequestController; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.nano.QsTileState; +import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository; +import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor; import com.android.systemui.settings.UserFileManager; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.phone.AutoTileManager; @@ -85,10 +84,10 @@ import javax.inject.Provider; * This class also provides the interface for adding/removing/changing tiles. */ @SysUISingleton -public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, ProtoDumpable { +public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, ProtoDumpable, + PanelInteractor, CustomTileAddedRepository { private static final String TAG = "QSTileHost"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final int MAX_QS_INSTANCE_ID = 1 << 20; // Shared prefs that hold tile lifecycle info. @VisibleForTesting @@ -99,10 +98,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P private final ArrayList<String> mTileSpecs = new ArrayList<>(); private final TunerService mTunerService; private final PluginManager mPluginManager; - private final DumpManager mDumpManager; private final QSLogger mQSLogger; - private final UiEventLogger mUiEventLogger; - private final InstanceIdSequence mInstanceIdSequence; private final CustomTileStatePersister mCustomTileStatePersister; private final Executor mMainExecutor; private final UserFileManager mUserFileManager; @@ -122,9 +118,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P // This is enforced by only cleaning the flag at the end of a successful run of #onTuningChanged private boolean mTilesListDirty = true; - private final TileServiceRequestController mTileServiceRequestController; private TileLifecycleManager.Factory mTileLifeCycleManagerFactory; + private final FeatureFlags mFeatureFlags; + @Inject public QSTileHost(Context context, QSFactory defaultFactory, @@ -132,35 +129,29 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P PluginManager pluginManager, TunerService tunerService, Provider<AutoTileManager> autoTiles, - DumpManager dumpManager, Optional<CentralSurfaces> centralSurfacesOptional, QSLogger qsLogger, - UiEventLogger uiEventLogger, UserTracker userTracker, SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, - TileServiceRequestController.Builder tileServiceRequestControllerBuilder, TileLifecycleManager.Factory tileLifecycleManagerFactory, - UserFileManager userFileManager + UserFileManager userFileManager, + FeatureFlags featureFlags ) { mContext = context; mUserContext = context; mTunerService = tunerService; mPluginManager = pluginManager; - mDumpManager = dumpManager; mQSLogger = qsLogger; - mUiEventLogger = uiEventLogger; mMainExecutor = mainExecutor; - mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this); mTileLifeCycleManagerFactory = tileLifecycleManagerFactory; mUserFileManager = userFileManager; + mFeatureFlags = featureFlags; - mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID); mCentralSurfacesOptional = centralSurfacesOptional; mQsFactories.add(defaultFactory); pluginManager.addPluginListener(this, QSFactory.class, true); - mDumpManager.registerDumpable(TAG, this); mUserTracker = userTracker; mSecureSettings = secureSettings; mCustomTileStatePersister = customTileStatePersister; @@ -172,22 +163,14 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P tunerService.addTunable(this, TILES_SETTING); // AutoTileManager can modify mTiles so make sure mTiles has already been initialized. mAutoTiles = autoTiles.get(); - mTileServiceRequestController.init(); }); } - @Override - public InstanceId getNewInstanceId() { - return mInstanceIdSequence.newInstanceId(); - } - public void destroy() { mTiles.values().forEach(tile -> tile.destroy()); mAutoTiles.destroy(); mTunerService.removeTunable(this); mPluginManager.removePluginListener(this); - mDumpManager.unregisterDumpable(TAG); - mTileServiceRequestController.destroy(); } @Override @@ -210,11 +193,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P } @Override - public UiEventLogger getUiEventLogger() { - return mUiEventLogger; - } - - @Override public void addCallback(Callback callback) { mCallbacks.add(callback); } @@ -230,11 +208,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P } @Override - public void warn(String message, Throwable t) { - // already logged - } - - @Override public void collapsePanels() { mCentralSurfacesOptional.ifPresent(CentralSurfaces::postAnimateCollapsePanels); } @@ -300,6 +273,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P if (!TILES_SETTING.equals(key)) { return; } + // Do not process tiles if the flag is enabled. + if (mFeatureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) { + return; + } if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) { newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QsEventLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/QsEventLogger.kt new file mode 100644 index 000000000000..fc739edc69d2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QsEventLogger.kt @@ -0,0 +1,44 @@ +/* + * 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 + +import com.android.internal.logging.InstanceId +import com.android.internal.logging.InstanceIdSequence +import com.android.internal.logging.UiEventLogger +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +interface QsEventLogger : UiEventLogger { + fun getNewInstanceId(): InstanceId +} + +@SysUISingleton +class QsEventLoggerImpl +@Inject +constructor( + uiEventLogger: UiEventLogger, +) : QsEventLogger, UiEventLogger by uiEventLogger { + + companion object { + private const val MAX_QS_INSTANCE_ID = 1 shl 20 + } + + val sequence = InstanceIdSequence(MAX_QS_INSTANCE_ID) + override fun getNewInstanceId(): InstanceId { + return sequence.newInstanceId() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt index 964fe7104324..1f63f5da2f2b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSHostModule.kt @@ -19,7 +19,10 @@ package com.android.systemui.qs.dagger import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QSHostAdapter import com.android.systemui.qs.QSTileHost +import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.QsEventLoggerImpl import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedSharedPrefsRepository import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor @@ -31,15 +34,19 @@ import dagger.Provides @Module interface QSHostModule { - @Binds fun provideQsHost(controllerImpl: QSTileHost): QSHost + @Binds fun provideQsHost(controllerImpl: QSHostAdapter): QSHost + + @Binds fun provideEventLogger(impl: QsEventLoggerImpl): QsEventLogger @Module companion object { + private const val MAX_QS_INSTANCE_ID = 1 shl 20 + @Provides @JvmStatic fun providePanelInteractor( featureFlags: FeatureFlags, - qsHost: QSHost, + qsHost: QSTileHost, panelInteractorImpl: PanelInteractorImpl ): PanelInteractor { return if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) { @@ -53,7 +60,7 @@ interface QSHostModule { @JvmStatic fun provideCustomTileAddedRepository( featureFlags: FeatureFlags, - qsHost: QSHost, + qsHost: QSTileHost, customTileAddedRepository: CustomTileAddedSharedPrefsRepository ): CustomTileAddedRepository { return if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index d4854e1a7daf..897b0e73dca0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -59,17 +59,20 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.State; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.DisplayTracker; +import dagger.Lazy; + import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import javax.inject.Inject; -import dagger.Lazy; + public class CustomTile extends QSTileImpl<State> implements TileChangeListener { public static final String PREFIX = "custom("; @@ -111,6 +114,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener private CustomTile( QSHost host, + QsEventLogger uiEventLogger, Looper backgroundLooper, Handler mainHandler, FalsingManager falsingManager, @@ -124,7 +128,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener TileServices tileServices, DisplayTracker displayTracker ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mTileServices = tileServices; mWindowManager = WindowManagerGlobal.getWindowManagerService(); @@ -561,6 +565,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener public static class Builder { final Lazy<QSHost> mQSHostLazy; + final QsEventLogger mUiEventLogger; final Looper mBackgroundLooper; final Handler mMainHandler; private final FalsingManager mFalsingManager; @@ -578,6 +583,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener @Inject public Builder( Lazy<QSHost> hostLazy, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -590,6 +596,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener DisplayTracker displayTracker ) { mQSHostLazy = hostLazy; + mUiEventLogger = uiEventLogger; mBackgroundLooper = backgroundLooper; mMainHandler = mainHandler; mFalsingManager = falsingManager; @@ -620,6 +627,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener String action = getAction(mSpec); return new CustomTile( mQSHostLazy.get(), + mUiEventLogger, mBackgroundLooper, mMainHandler, mFalsingManager, diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddModule.kt new file mode 100644 index 000000000000..99792286d962 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddModule.kt @@ -0,0 +1,28 @@ +/* + * 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.qs.pipeline.data.repository.AutoAddRepository +import com.android.systemui.qs.pipeline.data.repository.AutoAddSettingRepository +import dagger.Binds +import dagger.Module + +@Module +abstract class QSAutoAddModule { + + @Binds abstract fun bindAutoAddRepository(impl: AutoAddSettingRepository): AutoAddRepository +} 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 index 00f0a67dbe22..e85440cad6b0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt @@ -22,6 +22,8 @@ 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.domain.interactor.CurrentTilesInteractor +import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractorImpl import com.android.systemui.qs.pipeline.prototyping.PrototypeCoreStartable import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import dagger.Binds @@ -30,7 +32,7 @@ import dagger.Provides import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap -@Module +@Module(includes = [QSAutoAddModule::class]) abstract class QSPipelineModule { /** Implementation for [TileSpecRepository] */ @@ -38,6 +40,11 @@ abstract class QSPipelineModule { abstract fun provideTileSpecRepository(impl: TileSpecSettingsRepository): TileSpecRepository @Binds + abstract fun bindCurrentTilesInteractor( + impl: CurrentTilesInteractorImpl + ): CurrentTilesInteractor + + @Binds @IntoMap @ClassKey(PrototypeCoreStartable::class) abstract fun providePrototypeCoreStartable(startable: PrototypeCoreStartable): CoreStartable diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt new file mode 100644 index 000000000000..43a16b69d1a8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/AutoAddRepository.kt @@ -0,0 +1,135 @@ +/* + * 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.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.qs.pipeline.shared.TileSpec +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.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.withContext + +/** Repository to track what QS tiles have been auto-added */ +interface AutoAddRepository { + + /** Flow of tiles that have been auto-added */ + fun autoAddedTiles(userId: Int): Flow<Set<TileSpec>> + + /** Mark a tile as having been auto-added */ + suspend fun markTileAdded(userId: Int, spec: TileSpec) + + /** + * Unmark a tile as having been auto-added. This is used for tiles that can be auto-added + * multiple times. + */ + suspend fun unmarkTileAdded(userId: Int, spec: TileSpec) +} + +/** + * Implementation that tracks the auto-added tiles stored in [Settings.Secure.QS_AUTO_ADDED_TILES]. + */ +@SysUISingleton +class AutoAddSettingRepository +@Inject +constructor( + private val secureSettings: SecureSettings, + @Background private val bgDispatcher: CoroutineDispatcher, +) : AutoAddRepository { + override fun autoAddedTiles(userId: Int): Flow<Set<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) ?: "" } + .distinctUntilChanged() + .map { + it.split(DELIMITER).map(TileSpec::create).filter { it !is TileSpec.Invalid }.toSet() + } + .flowOn(bgDispatcher) + } + + override suspend fun markTileAdded(userId: Int, spec: TileSpec) { + if (spec is TileSpec.Invalid) { + return + } + val added = load(userId).toMutableSet() + if (added.add(spec)) { + store(userId, added) + } + } + + override suspend fun unmarkTileAdded(userId: Int, spec: TileSpec) { + if (spec is TileSpec.Invalid) { + return + } + val added = load(userId).toMutableSet() + if (added.remove(spec)) { + store(userId, added) + } + } + + private suspend fun store(userId: Int, tiles: Set<TileSpec>) { + val toStore = + tiles + .filter { it !is TileSpec.Invalid } + .joinToString(DELIMITER, transform = TileSpec::spec) + withContext(bgDispatcher) { + secureSettings.putStringForUser( + SETTING, + toStore, + null, + false, + userId, + true, + ) + } + } + + private suspend fun load(userId: Int): Set<TileSpec> { + return withContext(bgDispatcher) { + (secureSettings.getStringForUser(SETTING, userId) ?: "") + .split(",") + .map(TileSpec::create) + .filter { it !is TileSpec.Invalid } + .toSet() + } + } + + companion object { + private const val SETTING = Settings.Secure.QS_AUTO_ADDED_TILES + private const val DELIMITER = "," + } +} 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 index d254e1b3d0d7..595b29a9dcb8 100644 --- 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 @@ -32,6 +32,7 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -53,6 +54,8 @@ interface TileSpecRepository { * at the end of the list. * * Passing [TileSpec.Invalid] is a noop. + * + * Trying to add a tile beyond the end of the list will add it at the end. */ suspend fun addTile(@UserIdInt userId: Int, tile: TileSpec, position: Int = POSITION_AT_END) @@ -61,7 +64,7 @@ interface TileSpecRepository { * * Passing [TileSpec.Invalid] or a non present tile is a noop. */ - suspend fun removeTile(@UserIdInt userId: Int, tile: TileSpec) + suspend fun removeTiles(@UserIdInt userId: Int, tiles: Collection<TileSpec>) /** * Sets the list of current [tiles] for a given [userId]. @@ -106,6 +109,7 @@ constructor( } .onStart { emit(Unit) } .map { secureSettings.getStringForUser(SETTING, userId) ?: "" } + .distinctUntilChanged() .onEach { logger.logTilesChangedInSettings(it, userId) } .map { parseTileSpecs(it, userId) } .flowOn(backgroundDispatcher) @@ -117,7 +121,7 @@ constructor( } val tilesList = loadTiles(userId).toMutableList() if (tile !in tilesList) { - if (position < 0) { + if (position < 0 || position >= tilesList.size) { tilesList.add(tile) } else { tilesList.add(position, tile) @@ -126,12 +130,12 @@ constructor( } } - override suspend fun removeTile(userId: Int, tile: TileSpec) { - if (tile == TileSpec.Invalid) { + override suspend fun removeTiles(userId: Int, tiles: Collection<TileSpec>) { + if (tiles.all { it == TileSpec.Invalid }) { return } val tilesList = loadTiles(userId).toMutableList() - if (tilesList.remove(tile)) { + if (tilesList.removeAll(tiles)) { storeTiles(userId, tilesList.toList()) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt new file mode 100644 index 000000000000..91c6e8b5fcb6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt @@ -0,0 +1,344 @@ +/* + * 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.domain.interactor + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.UserHandle +import com.android.systemui.Dumpable +import com.android.systemui.ProtoDumpable +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.nano.SystemUIProtoDump +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.plugins.qs.QSFactory +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.qs.external.CustomTile +import com.android.systemui.qs.external.CustomTileStatePersister +import com.android.systemui.qs.external.TileLifecycleManager +import com.android.systemui.qs.external.TileServiceKey +import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository +import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository +import com.android.systemui.qs.pipeline.domain.model.TileModel +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import com.android.systemui.qs.toProto +import com.android.systemui.settings.UserTracker +import com.android.systemui.user.data.repository.UserRepository +import com.android.systemui.util.kotlin.pairwise +import java.io.PrintWriter +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * Interactor for retrieving the list of current QS tiles, as well as making changes to this list + * + * It is [ProtoDumpable] as it needs to be able to dump state for CTS tests. + */ +interface CurrentTilesInteractor : ProtoDumpable { + /** Current list of tiles with their corresponding spec. */ + val currentTiles: StateFlow<List<TileModel>> + + /** User for the [currentTiles]. */ + val userId: StateFlow<Int> + + /** [Context] corresponding to [userId] */ + val userContext: StateFlow<Context> + + /** List of specs corresponding to the last value of [currentTiles] */ + val currentTilesSpecs: List<TileSpec> + get() = currentTiles.value.map(TileModel::spec) + + /** List of tiles corresponding to the last value of [currentTiles] */ + val currentQSTiles: List<QSTile> + get() = currentTiles.value.map(TileModel::tile) + + /** + * Requests that a tile be added in the list of tiles for the current user. + * + * @see TileSpecRepository.addTile + */ + fun addTile(spec: TileSpec, position: Int = TileSpecRepository.POSITION_AT_END) + + /** + * Requests that tiles be removed from the list of tiles for the current user + * + * If tiles with [TileSpec.CustomTileSpec] are removed, their lifecycle will be terminated and + * marked as removed. + * + * @see TileSpecRepository.removeTiles + */ + fun removeTiles(specs: Collection<TileSpec>) + + /** + * Requests that the list of tiles for the current user is changed to [specs]. + * + * If tiles with [TileSpec.CustomTileSpec] are removed, their lifecycle will be terminated and + * marked as removed. + * + * @see TileSpecRepository.setTiles + */ + fun setTiles(specs: List<TileSpec>) +} + +/** + * This implementation of [CurrentTilesInteractor] will try to re-use existing [QSTile] objects when + * possible, in particular: + * * It will only destroy tiles when they are not part of the list of tiles anymore + * * Platform tiles will be kept between users, with a call to [QSTile.userSwitch] + * * [CustomTile]s will only be destroyed if the user changes. + */ +@SysUISingleton +class CurrentTilesInteractorImpl +@Inject +constructor( + private val tileSpecRepository: TileSpecRepository, + private val userRepository: UserRepository, + private val customTileStatePersister: CustomTileStatePersister, + private val tileFactory: QSFactory, + private val customTileAddedRepository: CustomTileAddedRepository, + private val tileLifecycleManagerFactory: TileLifecycleManager.Factory, + private val userTracker: UserTracker, + @Main private val mainDispatcher: CoroutineDispatcher, + @Background private val backgroundDispatcher: CoroutineDispatcher, + @Application private val scope: CoroutineScope, + private val logger: QSPipelineLogger, + featureFlags: FeatureFlags, +) : CurrentTilesInteractor { + + private val _currentSpecsAndTiles: MutableStateFlow<List<TileModel>> = + MutableStateFlow(emptyList()) + + override val currentTiles: StateFlow<List<TileModel>> = _currentSpecsAndTiles.asStateFlow() + + // This variable should only be accessed inside the collect of `startTileCollection`. + private val specsToTiles = mutableMapOf<TileSpec, QSTile>() + + private val currentUser = MutableStateFlow(userTracker.userId) + override val userId = currentUser.asStateFlow() + + private val _userContext = MutableStateFlow(userTracker.userContext) + override val userContext = _userContext.asStateFlow() + + init { + if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) { + startTileCollection() + } + } + + @OptIn(ExperimentalCoroutinesApi::class) + private fun startTileCollection() { + scope.launch { + userRepository.selectedUserInfo + .flatMapLatest { user -> + currentUser.value = user.id + _userContext.value = userTracker.userContext + tileSpecRepository.tilesSpecs(user.id).map { user.id to it } + } + .distinctUntilChanged() + .pairwise(-1 to emptyList()) + .flowOn(backgroundDispatcher) + .collect { (old, new) -> + val newTileList = new.second + val userChanged = old.first != new.first + val newUser = new.first + + // Destroy all tiles that are not in the new set + specsToTiles + .filter { it.key !in newTileList } + .forEach { entry -> + logger.logTileDestroyed( + entry.key, + if (userChanged) { + QSPipelineLogger.TileDestroyedReason + .TILE_NOT_PRESENT_IN_NEW_USER + } else { + QSPipelineLogger.TileDestroyedReason.TILE_REMOVED + } + ) + entry.value.destroy() + } + // MutableMap will keep the insertion order + val newTileMap = mutableMapOf<TileSpec, QSTile>() + + newTileList.forEach { tileSpec -> + if (tileSpec !in newTileMap) { + val newTile = + if (tileSpec in specsToTiles) { + processExistingTile( + tileSpec, + specsToTiles.getValue(tileSpec), + userChanged, + newUser + ) + ?: createTile(tileSpec) + } else { + createTile(tileSpec) + } + if (newTile != null) { + newTileMap[tileSpec] = newTile + } + } + } + + val resolvedSpecs = newTileMap.keys.toList() + specsToTiles.clear() + specsToTiles.putAll(newTileMap) + _currentSpecsAndTiles.value = newTileMap.map { TileModel(it.key, it.value) } + if (resolvedSpecs != newTileList) { + // There were some tiles that couldn't be created. Change the value in the + // repository + launch { tileSpecRepository.setTiles(currentUser.value, resolvedSpecs) } + } + } + } + } + + override fun addTile(spec: TileSpec, position: Int) { + scope.launch { + tileSpecRepository.addTile(userRepository.getSelectedUserInfo().id, spec, position) + } + } + + override fun removeTiles(specs: Collection<TileSpec>) { + val currentSpecsCopy = currentTilesSpecs.toSet() + val user = currentUser.value + // intersect: tiles that are there and are being removed + val toFree = currentSpecsCopy.intersect(specs).filterIsInstance<TileSpec.CustomTileSpec>() + toFree.forEach { onCustomTileRemoved(it.componentName, user) } + if (currentSpecsCopy.intersect(specs).isNotEmpty()) { + // We don't want to do the call to set in case getCurrentTileSpecs is not the most + // up to date for this user. + scope.launch { tileSpecRepository.removeTiles(user, specs) } + } + } + + override fun setTiles(specs: List<TileSpec>) { + val currentSpecsCopy = currentTilesSpecs + val user = currentUser.value + if (currentSpecsCopy != specs) { + // minus: tiles that were there but are not there anymore + val toFree = currentSpecsCopy.minus(specs).filterIsInstance<TileSpec.CustomTileSpec>() + toFree.forEach { onCustomTileRemoved(it.componentName, user) } + scope.launch { tileSpecRepository.setTiles(user, specs) } + } + } + + override fun dump(pw: PrintWriter, args: Array<out String>) { + pw.println("CurrentTileInteractorImpl:") + pw.println("User: ${userId.value}") + currentTiles.value + .map { it.tile } + .filterIsInstance<Dumpable>() + .forEach { it.dump(pw, args) } + } + + override fun dumpProto(systemUIProtoDump: SystemUIProtoDump, args: Array<String>) { + val data = + currentTiles.value.map { it.tile.state }.mapNotNull { it.toProto() }.toTypedArray() + systemUIProtoDump.tiles = data + } + + private fun onCustomTileRemoved(componentName: ComponentName, userId: Int) { + val intent = Intent().setComponent(componentName) + val lifecycleManager = tileLifecycleManagerFactory.create(intent, UserHandle.of(userId)) + lifecycleManager.onStopListening() + lifecycleManager.onTileRemoved() + customTileStatePersister.removeState(TileServiceKey(componentName, userId)) + customTileAddedRepository.setTileAdded(componentName, userId, false) + lifecycleManager.flushMessagesAndUnbind() + } + + private suspend fun createTile(spec: TileSpec): QSTile? { + val tile = withContext(mainDispatcher) { tileFactory.createTile(spec.spec) } + if (tile == null) { + logger.logTileNotFoundInFactory(spec) + return null + } else { + tile.tileSpec = spec.spec + return if (!tile.isAvailable) { + logger.logTileDestroyed( + spec, + QSPipelineLogger.TileDestroyedReason.NEW_TILE_NOT_AVAILABLE, + ) + tile.destroy() + null + } else { + logger.logTileCreated(spec) + tile + } + } + } + + private fun processExistingTile( + tileSpec: TileSpec, + qsTile: QSTile, + userChanged: Boolean, + user: Int, + ): QSTile? { + return when { + !qsTile.isAvailable -> { + logger.logTileDestroyed( + tileSpec, + QSPipelineLogger.TileDestroyedReason.EXISTING_TILE_NOT_AVAILABLE + ) + qsTile.destroy() + null + } + // Tile is in the current list of tiles and available. + // We have a handful of different cases + qsTile !is CustomTile -> { + // The tile is not a custom tile. Make sure they are reset to the correct user + qsTile.removeCallbacks() + if (userChanged) { + qsTile.userSwitch(user) + logger.logTileUserChanged(tileSpec, user) + } + qsTile + } + qsTile.user == user -> { + // The tile is a custom tile for the same user, just return it + qsTile.removeCallbacks() + qsTile + } + else -> { + // The tile is a custom tile and the user has changed. Destroy it + qsTile.destroy() + logger.logTileDestroyed( + tileSpec, + QSPipelineLogger.TileDestroyedReason.CUSTOM_TILE_USER_CHANGED + ) + null + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/TileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/TileModel.kt new file mode 100644 index 000000000000..e2381ecd8b97 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/TileModel.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.pipeline.domain.model + +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.qs.pipeline.shared.TileSpec + +/** + * Container for a [tile] and its [spec]. The following must be true: + * ``` + * spec.spec == tile.tileSpec + * ``` + */ +data class TileModel(val spec: TileSpec, val tile: QSTile) { + init { + check(spec.spec == tile.tileSpec) + } +} 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 index 69d8248a11f5..bbd72341acc6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/prototyping/PrototypeCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/prototyping/PrototypeCoreStartable.kt @@ -16,11 +16,13 @@ package com.android.systemui.qs.pipeline.prototyping +import android.util.Log 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.AutoAddRepository import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.statusbar.commandline.Command @@ -46,6 +48,7 @@ class PrototypeCoreStartable @Inject constructor( private val tileSpecRepository: TileSpecRepository, + private val autoAddRepository: AutoAddRepository, private val userRepository: UserRepository, private val featureFlags: FeatureFlags, @Application private val scope: CoroutineScope, @@ -60,6 +63,13 @@ constructor( .flatMapLatest { user -> tileSpecRepository.tilesSpecs(user.id) } .collect {} } + if (featureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD)) { + scope.launch { + userRepository.selectedUserInfo + .flatMapLatest { user -> autoAddRepository.autoAddedTiles(user.id) } + .collect { tiles -> Log.d(TAG, "Auto-added tiles: $tiles") } + } + } commandRegistry.registerCommand(COMMAND, ::CommandExecutor) } } @@ -93,7 +103,7 @@ constructor( private fun performRemove(args: List<String>, spec: TileSpec) { val user = args.getOrNull(2)?.toInt() ?: userRepository.getSelectedUserInfo().id - scope.launch { tileSpecRepository.removeTile(user, spec) } + scope.launch { tileSpecRepository.removeTiles(user, listOf(spec)) } } override fun help(pw: PrintWriter) { @@ -105,5 +115,6 @@ constructor( companion object { private const val COMMAND = "qs-pipeline" + private const val TAG = "PrototypeCoreStartable" } } 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 index c691c2f668ad..af1cd0995a21 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt @@ -66,6 +66,10 @@ sealed class TileSpec private constructor(open val spec: String) { } } + fun create(component: ComponentName): CustomTileSpec { + return CustomTileSpec(CustomTile.toSpec(component), component) + } + private val String.isCustomTileSpec: Boolean get() = startsWith(CustomTile.PREFIX) 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 index 200f7431e906..767ce919d027 100644 --- 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 @@ -73,4 +73,59 @@ constructor( { "Tiles changed in settings for user $int1: $str1" } ) } + + /** Log when a tile is destroyed and its reason for destroying. */ + fun logTileDestroyed(spec: TileSpec, reason: TileDestroyedReason) { + tileListLogBuffer.log( + TILE_LIST_TAG, + LogLevel.DEBUG, + { + str1 = spec.toString() + str2 = reason.readable + }, + { "Tile $str1 destroyed. Reason: $str2" } + ) + } + + /** Log when a tile is created. */ + fun logTileCreated(spec: TileSpec) { + tileListLogBuffer.log( + TILE_LIST_TAG, + LogLevel.DEBUG, + { str1 = spec.toString() }, + { "Tile $str1 created" } + ) + } + + /** Ĺog when trying to create a tile, but it's not found in the factory. */ + fun logTileNotFoundInFactory(spec: TileSpec) { + tileListLogBuffer.log( + TILE_LIST_TAG, + LogLevel.VERBOSE, + { str1 = spec.toString() }, + { "Tile $str1 not found in factory" } + ) + } + + /** Log when the user is changed for a platform tile. */ + fun logTileUserChanged(spec: TileSpec, user: Int) { + tileListLogBuffer.log( + TILE_LIST_TAG, + LogLevel.VERBOSE, + { + str1 = spec.toString() + int1 = user + }, + { "User changed to $int1 for tile $str1" } + ) + } + + /** Reasons for destroying an existing tile. */ + enum class TileDestroyedReason(val readable: String) { + TILE_REMOVED("Tile removed from current set"), + CUSTOM_TILE_USER_CHANGED("User changed for custom tile"), + NEW_TILE_NOT_AVAILABLE("New tile not available"), + EXISTING_TILE_NOT_AVAILABLE("Existing tile not available"), + TILE_NOT_PRESENT_IN_NEW_USER("Tile not present in new user"), + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java index 49ba5086f64d..2a9e7d05c187 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -66,6 +66,7 @@ import com.android.systemui.plugins.qs.QSTile.State; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSEvent; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SideLabelTileLayout; import com.android.systemui.qs.logging.QSLogger; @@ -179,6 +180,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy protected QSTileImpl( QSHost host, + QsEventLogger uiEventLogger, Looper backgroundLooper, Handler mainHandler, FalsingManager falsingManager, @@ -189,8 +191,8 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy ) { mHost = host; mContext = host.getContext(); - mInstanceId = host.getNewInstanceId(); - mUiEventLogger = host.getUiEventLogger(); + mInstanceId = uiEventLogger.getNewInstanceId(); + mUiEventLogger = uiEventLogger; mUiHandler = mainHandler; mHandler = new H(backgroundLooper); @@ -633,7 +635,6 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy } catch (Throwable t) { final String error = "Error in " + name; Log.w(TAG, error, t); - mHost.warn(error, t); } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index 92a83bba8a68..30765f7f974d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -45,15 +45,18 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.util.settings.GlobalSettings; +import dagger.Lazy; + import javax.inject.Inject; -import dagger.Lazy; + /** Quick settings tile: Airplane mode **/ public class AirplaneModeTile extends QSTileImpl<BooleanState> { @@ -69,6 +72,7 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> { @Inject public AirplaneModeTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -81,7 +85,7 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> { GlobalSettings globalSettings, UserTracker userTracker ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mBroadcastDispatcher = broadcastDispatcher; mLazyConnectivityManager = lazyConnectivityManager; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt index 2ca452e45ecf..c709969ec6e2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt @@ -22,6 +22,7 @@ import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.settings.UserTracker @@ -31,6 +32,7 @@ import javax.inject.Inject class AlarmTile @Inject constructor( host: QSHost, + uiEventLogger: QsEventLogger, @Background backgroundLooper: Looper, @Main mainHandler: Handler, falsingManager: FalsingManager, @@ -42,6 +44,7 @@ class AlarmTile @Inject constructor( nextAlarmController: NextAlarmController ) : QSTileImpl<QSTile.State>( host, + uiEventLogger, backgroundLooper, mainHandler, falsingManager, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java index 027a464251c9..a444e7631527 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java @@ -37,6 +37,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -62,6 +63,7 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements @Inject public BatterySaverTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -72,7 +74,7 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements BatteryController batteryController, SecureSettings secureSettings ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mBatteryController = batteryController; mBatteryController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 08fe2709b810..30218a6a3180 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -47,6 +47,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BluetoothController; @@ -74,6 +75,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { @Inject public BluetoothTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -83,7 +85,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { QSLogger qsLogger, BluetoothController bluetoothController ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = bluetoothController; mController.observe(getLifecycle(), mCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java index 93e5f1efbdc8..65ef6b9c31a5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java @@ -37,6 +37,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -48,7 +49,9 @@ public class CameraToggleTile extends SensorPrivacyToggleTile { public static final String TILE_SPEC = "cameratoggle"; @Inject - protected CameraToggleTile(QSHost host, + protected CameraToggleTile( + QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, MetricsLogger metricsLogger, @@ -58,7 +61,7 @@ public class CameraToggleTile extends SensorPrivacyToggleTile { QSLogger qsLogger, IndividualSensorPrivacyController sensorPrivacyController, KeyguardStateController keyguardStateController) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger, sensorPrivacyController, keyguardStateController); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 8d984817ba77..54376fe604df 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -47,6 +47,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.connectivity.NetworkController; @@ -84,6 +85,7 @@ public class CastTile extends QSTileImpl<BooleanState> { @Inject public CastTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -97,7 +99,7 @@ public class CastTile extends QSTileImpl<BooleanState> { HotspotController hotspotController, DialogLaunchAnimator dialogLaunchAnimator ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = castController; mKeyguard = keyguardStateController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java index b6205d5df63d..cf9e3468c8f5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java @@ -37,6 +37,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -56,6 +57,7 @@ public class ColorCorrectionTile extends QSTileImpl<BooleanState> { @Inject public ColorCorrectionTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -66,7 +68,7 @@ public class ColorCorrectionTile extends QSTileImpl<BooleanState> { UserTracker userTracker, SecureSettings secureSettings ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mSetting = new SettingObserver(secureSettings, mHandler, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index 9a44e83ad9a1..4ecde6123dd5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -38,6 +38,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -55,6 +56,7 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { @Inject public ColorInversionTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -65,7 +67,7 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { UserTracker userTracker, SecureSettings secureSettings ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mSetting = new SettingObserver(secureSettings, mHandler, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index add517e18516..e769b5ef9989 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -38,6 +38,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; @@ -58,6 +59,7 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements @Inject public DataSaverTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -68,7 +70,7 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements DataSaverController dataSaverController, DialogLaunchAnimator dialogLaunchAnimator ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mDataSaverController = dataSaverController; mDialogLaunchAnimator = dialogLaunchAnimator; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt index 01164fb0a009..ddaff3bb9a64 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt @@ -40,6 +40,7 @@ import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import java.util.concurrent.atomic.AtomicBoolean @@ -47,6 +48,7 @@ import javax.inject.Inject class DeviceControlsTile @Inject constructor( host: QSHost, + uiEventLogger: QsEventLogger, @Background backgroundLooper: Looper, @Main mainHandler: Handler, falsingManager: FalsingManager, @@ -56,14 +58,15 @@ class DeviceControlsTile @Inject constructor( qsLogger: QSLogger, private val controlsComponent: ControlsComponent ) : QSTileImpl<QSTile.State>( - host, - backgroundLooper, - mainHandler, - falsingManager, - metricsLogger, - statusBarStateController, - activityStarter, - qsLogger + host, + uiEventLogger, + backgroundLooper, + mainHandler, + falsingManager, + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger ) { private var hasControlsApps = AtomicBoolean(false) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 434fe45f47c0..3e7bdd1a1444 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -54,6 +54,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -88,6 +89,7 @@ public class DndTile extends QSTileImpl<BooleanState> { @Inject public DndTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -100,7 +102,7 @@ public class DndTile extends QSTileImpl<BooleanState> { SecureSettings secureSettings, DialogLaunchAnimator dialogLaunchAnimator ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = zenModeController; mSharedPreferences = sharedPreferences; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java index f913326a6a67..eef4c1dd4436 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java @@ -48,6 +48,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -90,6 +91,7 @@ public class DreamTile extends QSTileImpl<QSTile.BooleanState> { @Inject public DreamTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -105,7 +107,7 @@ public class DreamTile extends QSTileImpl<QSTile.BooleanState> { @Named(DreamModule.DREAM_ONLY_ENABLED_FOR_DOCK_USER) boolean dreamOnlyEnabledForDockUser ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mDreamManager = dreamManager; mBroadcastDispatcher = broadcastDispatcher; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index e091a750fbec..2c986da8370a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -37,6 +37,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.FlashlightController; @@ -55,6 +56,7 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements @Inject public FlashlightTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -64,7 +66,7 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements QSLogger qsLogger, FlashlightController flashlightController ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mFlashlightController = flashlightController; mFlashlightController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt index 3f514344cee1..12d98473ff07 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt @@ -36,6 +36,7 @@ import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.phone.SystemUIDialog @@ -47,6 +48,7 @@ class FontScalingTile @Inject constructor( host: QSHost, + uiEventLogger: QsEventLogger, @Background backgroundLooper: Looper, @Main mainHandler: Handler, falsingManager: FalsingManager, @@ -61,6 +63,7 @@ constructor( ) : QSTileImpl<QSTile.State?>( host, + uiEventLogger, backgroundLooper, mainHandler, falsingManager, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 6bf8b7666054..4c3699ced6e5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -41,6 +41,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.DataSaverController; @@ -61,6 +62,7 @@ public class HotspotTile extends QSTileImpl<BooleanState> { @Inject public HotspotTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -71,7 +73,7 @@ public class HotspotTile extends QSTileImpl<BooleanState> { HotspotController hotspotController, DataSaverController dataSaverController ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mHotspotController = hotspotController; mDataSaverController = dataSaverController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 75d01723667d..f16f0dcc5dba 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -51,6 +51,7 @@ import com.android.systemui.plugins.qs.QSTile.SignalState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.AlphaControlledSignalTileView; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.qs.tiles.dialog.InternetDialogFactory; @@ -90,6 +91,7 @@ public class InternetTile extends QSTileImpl<SignalState> { @Inject public InternetTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -101,7 +103,7 @@ public class InternetTile extends QSTileImpl<SignalState> { AccessPointController accessPointController, InternetDialogFactory internetDialogFactory ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mInternetDialogFactory = internetDialogFactory; mHandler = mainHandler; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index 27f58269722a..83c568878c94 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -37,6 +37,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -59,6 +60,7 @@ public class LocationTile extends QSTileImpl<BooleanState> { @Inject public LocationTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -70,7 +72,7 @@ public class LocationTile extends QSTileImpl<BooleanState> { KeyguardStateController keyguardStateController, PanelInteractor panelInteractor ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = locationController; mKeyguard = keyguardStateController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java index 2e475d40d55f..86a6a8c6a2b6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java @@ -37,6 +37,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -48,7 +49,9 @@ public class MicrophoneToggleTile extends SensorPrivacyToggleTile { public static final String TILE_SPEC = "mictoggle"; @Inject - protected MicrophoneToggleTile(QSHost host, + protected MicrophoneToggleTile( + QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, MetricsLogger metricsLogger, @@ -58,7 +61,7 @@ public class MicrophoneToggleTile extends SensorPrivacyToggleTile { QSLogger qsLogger, IndividualSensorPrivacyController sensorPrivacyController, KeyguardStateController keyguardStateController) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger, sensorPrivacyController, keyguardStateController); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index e189f80a7c23..29ccb76de820 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -43,6 +43,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -65,6 +66,7 @@ public class NfcTile extends QSTileImpl<BooleanState> { @Inject public NfcTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -74,7 +76,7 @@ public class NfcTile extends QSTileImpl<BooleanState> { QSLogger qsLogger, BroadcastDispatcher broadcastDispatcher ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mBroadcastDispatcher = broadcastDispatcher; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index aacd53bde51c..405e1394871c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -45,6 +45,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.LocationController; @@ -80,6 +81,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements @Inject public NightDisplayTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -91,7 +93,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements ColorDisplayManager colorDisplayManager, NightDisplayListenerModule.Builder nightDisplayListenerBuilder ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mLocationController = locationController; mManager = colorDisplayManager; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java index ae67d99ea2fb..1eb317aaeae8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java @@ -36,6 +36,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -57,6 +58,7 @@ public class OneHandedModeTile extends QSTileImpl<BooleanState> { @Inject public OneHandedModeTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -66,7 +68,7 @@ public class OneHandedModeTile extends QSTileImpl<BooleanState> { QSLogger qsLogger, UserTracker userTracker, SecureSettings secureSettings) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mSetting = new SettingObserver(secureSettings, mHandler, Settings.Secure.ONE_HANDED_MODE_ENABLED, userTracker.getUserId()) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java index 92f52724ca0c..9e365d34bed9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java @@ -37,6 +37,7 @@ import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qrcodescanner.controller.QRCodeScannerController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -62,6 +63,7 @@ public class QRCodeScannerTile extends QSTileImpl<QSTile.State> { @Inject public QRCodeScannerTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -70,7 +72,7 @@ public class QRCodeScannerTile extends QSTileImpl<QSTile.State> { ActivityStarter activityStarter, QSLogger qsLogger, QRCodeScannerController qrCodeScannerController) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mQRCodeScannerController = qrCodeScannerController; mQRCodeScannerController.observe(getLifecycle(), mCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java index 4a3c56328006..e026bdbc2e08 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java @@ -49,6 +49,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -83,6 +84,7 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { @Inject public QuickAccessWalletTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -94,7 +96,7 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { PackageManager packageManager, SecureSettings secureSettings, QuickAccessWalletController quickAccessWalletController) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = quickAccessWalletController; mKeyguardStateController = keyguardStateController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java index 10f1ce4946c8..2e04afb0048a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java @@ -38,6 +38,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -59,6 +60,7 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> @Named(RBC_AVAILABLE) boolean isAvailable, ReduceBrightColorsController reduceBrightColorsController, QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -67,7 +69,7 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> ActivityStarter activityStarter, QSLogger qsLogger ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mReduceBrightColorsController = reduceBrightColorsController; mReduceBrightColorsController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index 8888c733c3c1..7f7f8ad6a4c1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -44,6 +44,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -71,6 +72,7 @@ public class RotationLockTile extends QSTileImpl<BooleanState> implements @Inject public RotationLockTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -83,7 +85,7 @@ public class RotationLockTile extends QSTileImpl<BooleanState> implements BatteryController batteryController, SecureSettings secureSettings ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = rotationLockController; mController.observe(this, mCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index 65592a717565..2d4652db6b80 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -41,6 +41,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -74,6 +75,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> @Inject public ScreenRecordTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -88,7 +90,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> DialogLaunchAnimator dialogLaunchAnimator, PanelInteractor panelInteractor ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = controller; mController.observe(this, mCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java index d99c1d1daf7e..7c4f097a1724 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java @@ -39,6 +39,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; @@ -68,7 +69,9 @@ public abstract class SensorPrivacyToggleTile extends QSTileImpl<QSTile.BooleanS */ public abstract String getRestriction(); - protected SensorPrivacyToggleTile(QSHost host, + protected SensorPrivacyToggleTile( + QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -78,7 +81,7 @@ public abstract class SensorPrivacyToggleTile extends QSTileImpl<QSTile.BooleanS QSLogger qsLogger, IndividualSensorPrivacyController sensorPrivacyController, KeyguardStateController keyguardStateController) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mSensorPrivacyController = sensorPrivacyController; mKeyguard = keyguardStateController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index 809689cb806d..a60d1ad448b4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -39,6 +39,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; @@ -69,6 +70,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements @Inject public UiModeNightTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -80,7 +82,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements BatteryController batteryController, LocationController locationController ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mBatteryController = batteryController; mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index 6a5c99032457..17e72e597e58 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -40,6 +40,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.ManagedProfileController; @@ -59,6 +60,7 @@ public class WorkModeTile extends QSTileImpl<BooleanState> implements @Inject public WorkModeTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -68,7 +70,7 @@ public class WorkModeTile extends QSTileImpl<BooleanState> implements QSLogger qsLogger, ManagedProfileController managedProfileController ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mProfileController = managedProfileController; mProfileController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index 039dafb80522..380b85cb5504 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -259,8 +259,7 @@ public class InternetDialog extends SystemUIDialog implements } @Override - public void onStart() { - super.onStart(); + public void start() { if (DEBUG) { Log.d(TAG, "onStart"); } @@ -280,8 +279,7 @@ public class InternetDialog extends SystemUIDialog implements } @Override - public void onStop() { - super.onStop(); + public void stop() { if (DEBUG) { Log.d(TAG, "onStop"); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index f62e93976d71..0a188e0e7d0b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -16,6 +16,8 @@ package com.android.systemui.recents; +import static android.content.Intent.ACTION_PACKAGE_ADDED; +import static android.content.Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; @@ -32,6 +34,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; @@ -46,6 +49,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; +import android.content.pm.ResolveInfo; import android.graphics.Region; import android.hardware.input.InputManager; import android.hardware.input.InputManagerGlobal; @@ -112,7 +116,9 @@ import dagger.Lazy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.function.Supplier; @@ -390,19 +396,36 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - updateEnabledState(); + // If adding, bind immediately + if (Objects.equals(intent.getAction(), ACTION_PACKAGE_ADDED)) { + updateEnabledAndBinding(); + return; + } + + // ACTION_PACKAGE_CHANGED + String[] compsList = intent.getStringArrayExtra(EXTRA_CHANGED_COMPONENT_NAME_LIST); + if (compsList == null) { + return; + } - // Reconnect immediately, instead of waiting for resume to arrive. - startConnectionToCurrentUser(); + // Only rebind for TouchInteractionService component from launcher + ResolveInfo ri = context.getPackageManager() + .resolveService(new Intent(ACTION_QUICKSTEP), 0); + String interestingComponent = ri.serviceInfo.name; + for (String component : compsList) { + if (interestingComponent.equals(component)) { + Log.i(TAG_OPS, "Rebinding for component [" + component + "] change"); + updateEnabledAndBinding(); + return; + } + } } }; private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { - if (SysUiState.DEBUG) { - Log.d(TAG_OPS, "Overview proxy service connected"); - } + Log.d(TAG_OPS, "Overview proxy service connected"); mConnectionBackoffAttempts = 0; mHandler.removeCallbacks(mDeferredConnectionCallback); try { @@ -447,6 +470,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis notifySystemUiStateFlags(mSysUiState.getFlags()); notifyConnectionChanged(); + if (mLatchForOnUserChanging != null) { + mLatchForOnUserChanging.countDown(); + mLatchForOnUserChanging = null; + } } @Override @@ -501,11 +528,14 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } }; + private CountDownLatch mLatchForOnUserChanging; private final UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() { @Override - public void onUserChanged(int newUser, @NonNull Context userContext) { + public void onUserChanging(int newUser, @NonNull Context userContext, + CountDownLatch latch) { mConnectionBackoffAttempts = 0; + mLatchForOnUserChanging = latch; internalConnectToCurrentUser("User changed"); } }; @@ -603,8 +633,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis screenLifecycle.addObserver(mScreenLifecycleObserver); wakefulnessLifecycle.addObserver(mWakefulnessLifecycleObserver); // Connect to the service - updateEnabledState(); - startConnectionToCurrentUser(); + updateEnabledAndBinding(); // Listen for assistant changes assistUtils.registerVoiceInteractionSessionListener(mVoiceInteractionSessionListener); @@ -626,6 +655,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private void dispatchNavigationBarSurface() { try { if (mOverviewProxy != null) { + // Catch all for cases where the surface is no longer valid + if (mNavigationBarSurface != null && !mNavigationBarSurface.isValid()) { + mNavigationBarSurface = null; + } mOverviewProxy.onNavigationBarSurface(mNavigationBarSurface); } } catch (RemoteException e) { @@ -633,6 +666,11 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } + private void updateEnabledAndBinding() { + updateEnabledState(); + startConnectionToCurrentUser(); + } + private void updateSystemUiStateFlags() { final NavigationBar navBarFragment = mNavBarControllerLazy.get().getDefaultNavigationBar(); @@ -676,11 +714,14 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, - boolean bouncerShowing, boolean isDozing, boolean panelExpanded, boolean isDreaming) { + boolean keyguardGoingAway, boolean bouncerShowing, boolean isDozing, + boolean panelExpanded, boolean isDreaming) { mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING, keyguardShowing && !keyguardOccluded) .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED, keyguardShowing && keyguardOccluded) + .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY, + keyguardGoingAway) .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing) .setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing) .setFlag(SYSUI_STATE_DEVICE_DREAMING, isDreaming) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 6f85c45a6614..c9d1da38b196 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -289,7 +289,7 @@ public class ScreenshotController { if (DEBUG_INPUT) { Log.d(TAG, "Predictive Back callback dispatched"); } - respondToBack(); + respondToKeyDismissal(); }; private ScreenshotView mScreenshotView; @@ -581,7 +581,7 @@ public class ScreenshotController { } } - private void respondToBack() { + private void respondToKeyDismissal() { dismissScreenshot(SCREENSHOT_DISMISSED_OTHER); } @@ -641,11 +641,11 @@ public class ScreenshotController { mScreenshotView.setDefaultTimeoutMillis(mScreenshotHandler.getDefaultTimeoutMillis()); mScreenshotView.setOnKeyListener((v, keyCode, event) -> { - if (keyCode == KeyEvent.KEYCODE_BACK) { + if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) { if (DEBUG_INPUT) { - Log.d(TAG, "onKeyEvent: KeyEvent.KEYCODE_BACK"); + Log.d(TAG, "onKeyEvent: " + keyCode); } - respondToBack(); + respondToKeyDismissal(); return true; } return false; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java index d0b7ad3e9dd5..394949297d6d 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java @@ -27,9 +27,15 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.os.IBinder; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import com.android.internal.infra.AndroidFuture; +import com.android.internal.infra.ServiceConnector; import com.android.internal.statusbar.IAppClipsService; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Application; @@ -37,6 +43,7 @@ import com.android.systemui.flags.FeatureFlags; import com.android.wm.shell.bubbles.Bubbles; import java.util.Optional; +import java.util.concurrent.ExecutionException; import javax.inject.Inject; @@ -46,21 +53,63 @@ import javax.inject.Inject; */ public class AppClipsService extends Service { + private static final String TAG = AppClipsService.class.getSimpleName(); + @Application private final Context mContext; private final FeatureFlags mFeatureFlags; private final Optional<Bubbles> mOptionalBubbles; private final DevicePolicyManager mDevicePolicyManager; + private final UserManager mUserManager; + private final boolean mAreTaskAndTimeIndependentPrerequisitesMet; + @VisibleForTesting() + @Nullable ServiceConnector<IAppClipsService> mProxyConnectorToMainProfile; + @Inject public AppClipsService(@Application Context context, FeatureFlags featureFlags, - Optional<Bubbles> optionalBubbles, DevicePolicyManager devicePolicyManager) { + Optional<Bubbles> optionalBubbles, DevicePolicyManager devicePolicyManager, + UserManager userManager) { mContext = context; mFeatureFlags = featureFlags; mOptionalBubbles = optionalBubbles; mDevicePolicyManager = devicePolicyManager; + mUserManager = userManager; + + // The consumer of this service are apps that call through StatusBarManager API to query if + // it can use app clips API. Since these apps can be launched as work profile users, this + // service will start as work profile user. SysUI doesn't share injected instances for + // different users. This is why the bubbles instance injected will be incorrect. As the apps + // don't generally have permission to connect to a service running as different user, we + // start a proxy connection to communicate with the main user's version of this service. + if (mUserManager.isManagedProfile()) { + // No need to check for prerequisites in this case as those are incorrect for work + // profile user instance of the service and the main user version of the service will + // take care of this check. + mAreTaskAndTimeIndependentPrerequisitesMet = false; + + // Get the main user so that we can connect to the main user's version of the service. + UserHandle mainUser = mUserManager.getMainUser(); + if (mainUser == null) { + // If main user is not available there isn't much we can do, no apps can use app + // clips. + return; + } + + // Set up the connection to be used later during onBind callback. + mProxyConnectorToMainProfile = + new ServiceConnector.Impl<>( + context, + new Intent(context, AppClipsService.class), + Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY + | Context.BIND_NOT_VISIBLE, + mainUser.getIdentifier(), + IAppClipsService.Stub::asInterface); + return; + } mAreTaskAndTimeIndependentPrerequisitesMet = checkIndependentVariables(); + mProxyConnectorToMainProfile = null; } private boolean checkIndependentVariables() { @@ -95,6 +144,13 @@ public class AppClipsService extends Service { return new IAppClipsService.Stub() { @Override public boolean canLaunchCaptureContentActivityForNote(int taskId) { + // In case of managed profile, use the main user's instance of the service. Callers + // cannot directly connect to the main user's instance as they may not have the + // permission to interact across users. + if (mUserManager.isManagedProfile()) { + return canLaunchCaptureContentActivityForNoteFromMainUser(taskId); + } + if (!mAreTaskAndTimeIndependentPrerequisitesMet) { return false; } @@ -107,4 +163,21 @@ public class AppClipsService extends Service { } }; } + + /** Returns whether the app clips API can be used by querying the service as the main user. */ + private boolean canLaunchCaptureContentActivityForNoteFromMainUser(int taskId) { + if (mProxyConnectorToMainProfile == null) { + return false; + } + + try { + AndroidFuture<Boolean> future = mProxyConnectorToMainProfile.postForResult( + service -> service.canLaunchCaptureContentActivityForNote(taskId)); + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.d(TAG, "Exception from service\n" + e); + } + + return false; + } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java index 3cb1a34a921c..0487cbc995dd 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java @@ -40,6 +40,8 @@ import android.os.Bundle; import android.os.Handler; import android.os.Parcel; import android.os.ResultReceiver; +import android.os.UserHandle; +import android.os.UserManager; import android.util.Log; import androidx.annotation.Nullable; @@ -79,13 +81,10 @@ public class AppClipsTrampolineActivity extends Activity { private static final String TAG = AppClipsTrampolineActivity.class.getSimpleName(); static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; - @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) - public static final String EXTRA_SCREENSHOT_URI = TAG + "SCREENSHOT_URI"; + static final String EXTRA_SCREENSHOT_URI = TAG + "SCREENSHOT_URI"; static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE"; - @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) - public static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER"; - @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) - public static final String EXTRA_CALLING_PACKAGE_NAME = TAG + "CALLING_PACKAGE_NAME"; + static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER"; + static final String EXTRA_CALLING_PACKAGE_NAME = TAG + "CALLING_PACKAGE_NAME"; private static final ApplicationInfoFlags APPLICATION_INFO_FLAGS = ApplicationInfoFlags.of(0); private final DevicePolicyManager mDevicePolicyManager; @@ -95,6 +94,7 @@ public class AppClipsTrampolineActivity extends Activity { private final PackageManager mPackageManager; private final UserTracker mUserTracker; private final UiEventLogger mUiEventLogger; + private final UserManager mUserManager; private final ResultReceiver mResultReceiver; private Intent mKillAppClipsBroadcastIntent; @@ -103,7 +103,7 @@ public class AppClipsTrampolineActivity extends Activity { public AppClipsTrampolineActivity(DevicePolicyManager devicePolicyManager, FeatureFlags flags, Optional<Bubbles> optionalBubbles, NoteTaskController noteTaskController, PackageManager packageManager, UserTracker userTracker, UiEventLogger uiEventLogger, - @Main Handler mainHandler) { + UserManager userManager, @Main Handler mainHandler) { mDevicePolicyManager = devicePolicyManager; mFeatureFlags = flags; mOptionalBubbles = optionalBubbles; @@ -111,6 +111,7 @@ public class AppClipsTrampolineActivity extends Activity { mPackageManager = packageManager; mUserTracker = userTracker; mUiEventLogger = uiEventLogger; + mUserManager = userManager; mResultReceiver = createResultReceiver(mainHandler); } @@ -123,6 +124,12 @@ public class AppClipsTrampolineActivity extends Activity { return; } + if (mUserManager.isManagedProfile()) { + maybeStartActivityForWPUser(); + finish(); + return; + } + if (!mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)) { finish(); return; @@ -191,6 +198,19 @@ public class AppClipsTrampolineActivity extends Activity { } } + private void maybeStartActivityForWPUser() { + UserHandle mainUser = mUserManager.getMainUser(); + if (mainUser == null) { + setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_FAILED); + return; + } + + // Start the activity as the main user with activity result forwarding. + startActivityAsUser( + new Intent(this, AppClipsTrampolineActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT), mainUser); + } + private void setErrorResultAndFinish(int errorCode) { setResult(RESULT_OK, new Intent().putExtra(EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE, errorCode)); diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index 72286f175671..3711a2f39b7b 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -162,7 +162,7 @@ open class UserTrackerImpl internal constructor( private fun registerUserSwitchObserver() { iActivityManager.registerUserSwitchObserver(object : UserSwitchObserver() { override fun onBeforeUserSwitching(newUserId: Int) { - setUserIdInternal(newUserId) + handleBeforeUserSwitching(newUserId) } override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) { @@ -180,6 +180,10 @@ open class UserTrackerImpl internal constructor( }, TAG) } + protected open fun handleBeforeUserSwitching(newUserId: Int) { + setUserIdInternal(newUserId) + } + @WorkerThread protected open fun handleUserSwitching(newUserId: Int) { Assert.isNotMainThread() diff --git a/packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt b/packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt index 754036d3baa9..b8bd95c89ec8 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt @@ -14,9 +14,9 @@ package com.android.systemui.shade import android.view.MotionEvent +import com.android.systemui.common.buffer.RingBuffer import com.android.systemui.dump.DumpsysTableLogger import com.android.systemui.dump.Row -import com.android.systemui.plugins.util.RingBuffer import java.text.SimpleDateFormat import java.util.Locale diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 79d3b26e01c7..a4a7d4cd76e5 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -22,10 +22,6 @@ import static android.view.MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; -import static androidx.constraintlayout.widget.ConstraintSet.END; -import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID; - -import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION; import static com.android.keyguard.KeyguardClockSwitch.LARGE; import static com.android.keyguard.KeyguardClockSwitch.SMALL; import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE; @@ -73,12 +69,6 @@ import android.os.Trace; import android.os.UserManager; import android.os.VibrationEffect; import android.provider.Settings; -import android.transition.ChangeBounds; -import android.transition.Transition; -import android.transition.TransitionListenerAdapter; -import android.transition.TransitionManager; -import android.transition.TransitionSet; -import android.transition.TransitionValues; import android.util.IndentingPrintWriter; import android.util.Log; import android.util.MathUtils; @@ -100,8 +90,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Interpolator; import android.widget.FrameLayout; -import androidx.constraintlayout.widget.ConstraintSet; - import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; @@ -141,6 +129,7 @@ import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants; @@ -162,7 +151,7 @@ import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.plugins.ClockController; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingManager.FalsingTapListener; import com.android.systemui.plugins.qs.QS; @@ -299,11 +288,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1); private static final Rect EMPTY_RECT = new Rect(); /** - * Duration to use for the animator when the keyguard status view alignment changes, and a - * custom clock animation is in use. - */ - private static final int KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION = 1000; - /** * Whether the Shade should animate to reflect Back gesture progress. * To minimize latency at runtime, we cache this, else we'd be reading it every time * updateQsExpansion() is called... and it's called very often. @@ -347,6 +331,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final PulseExpansionHandler mPulseExpansionHandler; private final KeyguardBypassController mKeyguardBypassController; private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; private final ConversationNotificationManager mConversationNotificationManager; private final AuthController mAuthController; private final MediaHierarchyManager mMediaHierarchyManager; @@ -550,8 +535,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final KeyguardMediaController mKeyguardMediaController; - private boolean mStatusViewCentered = true; - private final Optional<KeyguardUnfoldTransition> mKeyguardUnfoldTransition; private final Optional<NotificationPanelUnfoldAnimationController> mNotificationPanelUnfoldAnimationController; @@ -682,35 +665,29 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump step.getTransitionState() == TransitionState.RUNNING; }; - private final TransitionListenerAdapter mKeyguardStatusAlignmentTransitionListener = - new TransitionListenerAdapter() { - @Override - public void onTransitionCancel(Transition transition) { - mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); - } - - @Override - public void onTransitionEnd(Transition transition) { - mInteractionJankMonitor.end(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); - } - }; + private final ActivityStarter mActivityStarter; @Inject public NotificationPanelViewController(NotificationPanelView view, @Main Handler handler, LayoutInflater layoutInflater, FeatureFlags featureFlags, - NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator coordinator, + PulseExpansionHandler pulseExpansionHandler, DynamicPrivacyController dynamicPrivacyController, - KeyguardBypassController bypassController, FalsingManager falsingManager, + KeyguardBypassController bypassController, + FalsingManager falsingManager, FalsingCollector falsingCollector, KeyguardStateController keyguardStateController, StatusBarStateController statusBarStateController, StatusBarWindowStateController statusBarWindowStateController, NotificationShadeWindowController notificationShadeWindowController, DozeLog dozeLog, - DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper, - LatencyTracker latencyTracker, PowerManager powerManager, + DozeParameters dozeParameters, + CommandQueue commandQueue, + VibratorHelper vibratorHelper, + LatencyTracker latencyTracker, + PowerManager powerManager, AccessibilityManager accessibilityManager, @DisplayId int displayId, KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger, @@ -771,7 +748,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump Provider<MultiShadeInteractor> multiShadeInteractorProvider, DumpManager dumpManager, KeyguardLongPressViewModel keyguardLongPressViewModel, - KeyguardInteractor keyguardInteractor) { + KeyguardInteractor keyguardInteractor, + ActivityStarter activityStarter, + KeyguardFaceAuthInteractor keyguardFaceAuthInteractor) { mInteractionJankMonitor = interactionJankMonitor; keyguardStateController.addCallback(new KeyguardStateController.Callback() { @Override @@ -915,6 +894,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mScreenOffAnimationController = screenOffAnimationController; mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; mLastDownEvents = new NPVCDownEventState.Buffer(MAX_DOWN_EVENT_BUFFER_SIZE); + mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor; int currentMode = navigationModeController.addListener( mode -> mIsGestureNavigation = QuickStepContract.isGesturalMode(mode)); @@ -952,6 +932,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump return Unit.INSTANCE; }, mFalsingManager); + mActivityStarter = activityStarter; onFinishInflate(); keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener( new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() { @@ -1313,9 +1294,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump keyguardStatusView = (KeyguardStatusView) mLayoutInflater.inflate( R.layout.keyguard_status_view, mNotificationContainerParent, false); mNotificationContainerParent.addView(keyguardStatusView, statusIndex); - // When it's reinflated, this is centered by default. If it shouldn't be, this will update - // below when resources are updated. - mStatusViewCentered = true; attachSplitShadeMediaPlayerContainer( keyguardStatusView.findViewById(R.id.status_view_media_container)); @@ -1394,7 +1372,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mLockIconViewController, stringResourceId -> mKeyguardIndicationController.showTransientIndication(stringResourceId), - mVibratorHelper); + mVibratorHelper, + mActivityStarter); } @VisibleForTesting @@ -1609,68 +1588,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private void updateKeyguardStatusViewAlignment(boolean animate) { boolean shouldBeCentered = shouldKeyguardStatusViewBeCentered(); - if (mStatusViewCentered != shouldBeCentered) { - mStatusViewCentered = shouldBeCentered; - ConstraintSet constraintSet = new ConstraintSet(); - constraintSet.clone(mNotificationContainerParent); - int statusConstraint = shouldBeCentered ? PARENT_ID : R.id.qs_edge_guideline; - constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END); - if (animate) { - mInteractionJankMonitor.begin(mView, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); - ChangeBounds transition = new ChangeBounds(); - if (mSplitShadeEnabled) { - // Excluding media from the transition on split-shade, as it doesn't transition - // horizontally properly. - transition.excludeTarget(R.id.status_view_media_container, true); - } - - transition.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); - transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); - - ClockController clock = mKeyguardStatusViewController.getClockController(); - boolean customClockAnimation = clock != null - && clock.getConfig().getHasCustomPositionUpdatedAnimation(); - - if (mFeatureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION) && customClockAnimation) { - // Find the clock, so we can exclude it from this transition. - FrameLayout clockContainerView = - mView.findViewById(R.id.lockscreen_clock_view_large); - - // The clock container can sometimes be null. If it is, just fall back to the - // old animation rather than setting up the custom animations. - if (clockContainerView == null || clockContainerView.getChildCount() == 0) { - transition.addListener(mKeyguardStatusAlignmentTransitionListener); - TransitionManager.beginDelayedTransition( - mNotificationContainerParent, transition); - } else { - View clockView = clockContainerView.getChildAt(0); - - transition.excludeTarget(clockView, /* exclude= */ true); - - TransitionSet set = new TransitionSet(); - set.addTransition(transition); - - SplitShadeTransitionAdapter adapter = - new SplitShadeTransitionAdapter(mKeyguardStatusViewController); - - // Use linear here, so the actual clock can pick its own interpolator. - adapter.setInterpolator(Interpolators.LINEAR); - adapter.setDuration(KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION); - adapter.addTarget(clockView); - set.addTransition(adapter); - set.addListener(mKeyguardStatusAlignmentTransitionListener); - TransitionManager.beginDelayedTransition(mNotificationContainerParent, set); - } - } else { - transition.addListener(mKeyguardStatusAlignmentTransitionListener); - TransitionManager.beginDelayedTransition( - mNotificationContainerParent, transition); - } - } - - constraintSet.applyTo(mNotificationContainerParent); - } - mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(mStatusViewCentered)); + mKeyguardStatusViewController.updateAlignment( + mNotificationContainerParent, mSplitShadeEnabled, shouldBeCentered, animate); + mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered)); } private boolean shouldKeyguardStatusViewBeCentered() { @@ -2848,6 +2768,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mShadeLog.v("onMiddleClicked on Keyguard, mDozingOnDown: false"); // Try triggering face auth, this "might" run. Check // KeyguardUpdateMonitor#shouldListenForFace to see when face auth won't run. + mKeyguardFaceAuthInteractor.onNotificationPanelClicked(); boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth( FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED); @@ -3324,7 +3245,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump ipw.print("mIsGestureNavigation="); ipw.println(mIsGestureNavigation); ipw.print("mOldLayoutDirection="); ipw.println(mOldLayoutDirection); ipw.print("mMinFraction="); ipw.println(mMinFraction); - ipw.print("mStatusViewCentered="); ipw.println(mStatusViewCentered); ipw.print("mSplitShadeFullTransitionDistance="); ipw.println(mSplitShadeFullTransitionDistance); ipw.print("mSplitShadeScrimTransitionDistance="); @@ -3418,7 +3338,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mGestureRecorder = recorder; mHideExpandedRunnable = hideExpandedRunnable; - mNotificationStackScrollLayoutController.setShelfController(notificationShelfController); + if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { + mNotificationStackScrollLayoutController.setShelfController( + notificationShelfController); + } mNotificationShelfController = notificationShelfController; mLockscreenShadeTransitionController.bindController(notificationShelfController); updateMaxDisplayedNotifications(true); @@ -4925,6 +4848,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } handled |= handleTouch(event); + mShadeLog.logOnTouchEventLastReturn(event, !mDozing, handled); return !mDozing || handled; } @@ -5107,6 +5031,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } break; } + mShadeLog.logHandleTouchLastReturn(event, !mGestureWaitForTouchSlop, mTracking); return !mGestureWaitForTouchSlop || mTracking; } @@ -5117,65 +5042,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } } - static class SplitShadeTransitionAdapter extends Transition { - private static final String PROP_BOUNDS = "splitShadeTransitionAdapter:bounds"; - private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS }; - - private final KeyguardStatusViewController mController; - - SplitShadeTransitionAdapter(KeyguardStatusViewController controller) { - mController = controller; - } - - private void captureValues(TransitionValues transitionValues) { - Rect boundsRect = new Rect(); - boundsRect.left = transitionValues.view.getLeft(); - boundsRect.top = transitionValues.view.getTop(); - boundsRect.right = transitionValues.view.getRight(); - boundsRect.bottom = transitionValues.view.getBottom(); - transitionValues.values.put(PROP_BOUNDS, boundsRect); - } - - @Override - public void captureEndValues(TransitionValues transitionValues) { - captureValues(transitionValues); - } - - @Override - public void captureStartValues(TransitionValues transitionValues) { - captureValues(transitionValues); - } - - @Nullable - @Override - public Animator createAnimator(ViewGroup sceneRoot, @Nullable TransitionValues startValues, - @Nullable TransitionValues endValues) { - if (startValues == null || endValues == null) { - return null; - } - ValueAnimator anim = ValueAnimator.ofFloat(0, 1); - - Rect from = (Rect) startValues.values.get(PROP_BOUNDS); - Rect to = (Rect) endValues.values.get(PROP_BOUNDS); - - anim.addUpdateListener(animation -> { - ClockController clock = mController.getClockController(); - if (clock == null) { - return; - } - - clock.getAnimations().onPositionUpdated(from, to, animation.getAnimatedFraction()); - }); - - return anim; - } - - @Override - public String[] getTransitionProperties() { - return TRANSITION_PROPERTIES; - } - } - private final class HeadsUpNotificationViewControllerImpl implements HeadsUpTouchHelper.HeadsUpNotificationViewController { @Override diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index 156e4fd1889f..af74c2793cc9 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -561,6 +561,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW for (StatusBarWindowCallback cb : activeCallbacks) { cb.onStateChanged(mCurrentState.keyguardShowing, mCurrentState.keyguardOccluded, + mCurrentState.keyguardGoingAway, mCurrentState.bouncerShowing, mCurrentState.dozing, mCurrentState.panelExpanded, diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt index fed9b8469c4b..7812f07fc59c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt @@ -16,9 +16,9 @@ package com.android.systemui.shade +import com.android.systemui.common.buffer.RingBuffer import com.android.systemui.dump.DumpsysTableLogger import com.android.systemui.dump.Row -import com.android.systemui.plugins.util.RingBuffer import com.android.systemui.shade.NotificationShadeWindowState.Buffer import com.android.systemui.statusbar.StatusBarState diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index b31ec3319781..ef14d1cb7f63 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -17,6 +17,8 @@ package com.android.systemui.shade; +import static android.view.WindowInsets.Type.ime; + import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE; import static com.android.systemui.classifier.Classifier.QS_COLLAPSE; import static com.android.systemui.shade.NotificationPanelViewController.COUNTER_PANEL_OPEN_QS; @@ -62,6 +64,7 @@ import com.android.systemui.classifier.Classifier; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.media.controls.pipeline.MediaDataManager; import com.android.systemui.media.controls.ui.MediaHierarchyManager; import com.android.systemui.plugins.FalsingManager; @@ -130,6 +133,7 @@ public class QuickSettingsController { private final FalsingCollector mFalsingCollector; private final LockscreenGestureLogger mLockscreenGestureLogger; private final ShadeLogger mShadeLog; + private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; private final FeatureFlags mFeatureFlags; private final InteractionJankMonitor mInteractionJankMonitor; private final FalsingManager mFalsingManager; @@ -316,7 +320,8 @@ public class QuickSettingsController { MetricsLogger metricsLogger, FeatureFlags featureFlags, InteractionJankMonitor interactionJankMonitor, - ShadeLogger shadeLog + ShadeLogger shadeLog, + KeyguardFaceAuthInteractor keyguardFaceAuthInteractor ) { mPanelViewControllerLazy = panelViewControllerLazy; mPanelView = panelView; @@ -355,6 +360,7 @@ public class QuickSettingsController { mLockscreenGestureLogger = lockscreenGestureLogger; mMetricsLogger = metricsLogger; mShadeLog = shadeLog; + mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor; mFeatureFlags = featureFlags; mInteractionJankMonitor = interactionJankMonitor; @@ -463,9 +469,17 @@ public class QuickSettingsController { return (mQs != null ? mQs.getHeader().getHeight() : 0) + mPeekHeight; } + private boolean isRemoteInputActiveWithKeyboardUp() { + //TODO(b/227115380) remove the isVisible(ime()) check once isRemoteInputActive is fixed. + // The check for keyboard visibility is a temporary workaround that allows QS to expand + // even when isRemoteInputActive is mistakenly returning true. + return mRemoteInputManager.isRemoteInputActive() + && mPanelView.getRootWindowInsets().isVisible(ime()); + } + public boolean isExpansionEnabled() { return mExpansionEnabledPolicy && mExpansionEnabledAmbient - && !mRemoteInputManager.isRemoteInputActive(); + && !isRemoteInputActiveWithKeyboardUp(); } public float getTransitioningToFullShadeProgress() { @@ -927,6 +941,7 @@ public class QuickSettingsController { // When expanding QS, let's authenticate the user if possible, // this will speed up notification actions. if (height == 0 && !mKeyguardStateController.canDismissLockScreen()) { + mKeyguardFaceAuthInteractor.onQsExpansionStared(); mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.QS_EXPANDED); } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt index b79f32a6eae1..f0815e93dccd 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt @@ -19,11 +19,14 @@ package com.android.systemui.shade import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.annotation.IdRes +import android.app.PendingIntent import android.app.StatusBarManager +import android.content.Intent import android.content.res.Configuration import android.os.Bundle import android.os.Trace import android.os.Trace.TRACE_TAG_APP +import android.provider.AlarmClock import android.util.Pair import android.view.DisplayCutout import android.view.View @@ -41,15 +44,16 @@ import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.demomode.DemoMode import com.android.systemui.demomode.DemoModeController import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.ChipVisibilityListener import com.android.systemui.qs.HeaderPrivacyIconsController -import com.android.systemui.qs.carrier.QSCarrierGroup -import com.android.systemui.qs.carrier.QSCarrierGroupController import com.android.systemui.shade.ShadeHeaderController.Companion.HEADER_TRANSITION_ID import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_HEADER_CONSTRAINT import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_HEADER_TRANSITION_ID import com.android.systemui.shade.ShadeHeaderController.Companion.QQS_HEADER_CONSTRAINT import com.android.systemui.shade.ShadeHeaderController.Companion.QS_HEADER_CONSTRAINT +import com.android.systemui.shade.carrier.ShadeCarrierGroup +import com.android.systemui.shade.carrier.ShadeCarrierGroupController import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.phone.StatusBarLocation @@ -58,6 +62,7 @@ import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.Cent import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SHADE_HEADER import com.android.systemui.statusbar.policy.Clock import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.NextAlarmController import com.android.systemui.statusbar.policy.VariableDateView import com.android.systemui.statusbar.policy.VariableDateViewController import com.android.systemui.util.ViewController @@ -87,10 +92,12 @@ constructor( private val variableDateViewControllerFactory: VariableDateViewController.Factory, @Named(SHADE_HEADER) private val batteryMeterViewController: BatteryMeterViewController, private val dumpManager: DumpManager, - private val qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder, + private val shadeCarrierGroupControllerBuilder: ShadeCarrierGroupController.Builder, private val combinedShadeHeadersConstraintManager: CombinedShadeHeadersConstraintManager, private val demoModeController: DemoModeController, private val qsBatteryModeController: QsBatteryModeController, + private val nextAlarmController: NextAlarmController, + private val activityStarter: ActivityStarter, ) : ViewController<View>(header), Dumpable { companion object { @@ -103,6 +110,8 @@ constructor( @VisibleForTesting internal val LARGE_SCREEN_HEADER_CONSTRAINT = R.id.large_screen_header_constraint + @VisibleForTesting internal val DEFAULT_CLOCK_INTENT = Intent(AlarmClock.ACTION_SHOW_ALARMS) + private fun Int.stateToString() = when (this) { QQS_HEADER_CONSTRAINT -> "QQS Header" @@ -114,17 +123,18 @@ constructor( private lateinit var iconManager: StatusBarIconController.TintedIconManager private lateinit var carrierIconSlots: List<String> - private lateinit var qsCarrierGroupController: QSCarrierGroupController + private lateinit var mShadeCarrierGroupController: ShadeCarrierGroupController private val batteryIcon: BatteryMeterView = header.findViewById(R.id.batteryRemainingIcon) private val clock: Clock = header.findViewById(R.id.clock) private val date: TextView = header.findViewById(R.id.date) private val iconContainer: StatusIconContainer = header.findViewById(R.id.statusIcons) - private val qsCarrierGroup: QSCarrierGroup = header.findViewById(R.id.carrier_group) + private val mShadeCarrierGroup: ShadeCarrierGroup = header.findViewById(R.id.carrier_group) private var roundedCorners = 0 private var cutout: DisplayCutout? = null private var lastInsets: WindowInsets? = null + private var nextAlarmIntent: PendingIntent? = null private var qsDisabled = false private var visible = false @@ -243,7 +253,7 @@ constructor( override fun onDensityOrFontScaleChanged() { clock.setTextAppearance(R.style.TextAppearance_QS_Status) date.setTextAppearance(R.style.TextAppearance_QS_Status) - qsCarrierGroup.updateTextAppearance(R.style.TextAppearance_QS_Status_Carriers) + mShadeCarrierGroup.updateTextAppearance(R.style.TextAppearance_QS_Status_Carriers) loadConstraints() header.minHeight = resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_min_height) @@ -252,6 +262,11 @@ constructor( } } + private val nextAlarmCallback = + NextAlarmController.NextAlarmChangeCallback { nextAlarm -> + nextAlarmIntent = nextAlarm?.showIntent + } + override fun onInit() { variableDateViewControllerFactory.create(date as VariableDateView).init() batteryMeterViewController.init() @@ -266,8 +281,8 @@ constructor( carrierIconSlots = listOf(header.context.getString(com.android.internal.R.string.status_bar_mobile)) - qsCarrierGroupController = - qsCarrierGroupControllerBuilder.setQSCarrierGroup(qsCarrierGroup).build() + mShadeCarrierGroupController = + shadeCarrierGroupControllerBuilder.setShadeCarrierGroup(mShadeCarrierGroup).build() privacyIconsController.onParentVisible() } @@ -284,21 +299,25 @@ constructor( v.pivotX = newPivot v.pivotY = v.height.toFloat() / 2 - qsCarrierGroup.setPaddingRelative((v.width * v.scaleX).toInt(), 0, 0, 0) + mShadeCarrierGroup.setPaddingRelative((v.width * v.scaleX).toInt(), 0, 0, 0) } + clock.setOnClickListener { launchClockActivity() } dumpManager.registerDumpable(this) configurationController.addCallback(configurationControllerListener) demoModeController.addCallback(demoModeReceiver) statusBarIconController.addIconGroup(iconManager) + nextAlarmController.addCallback(nextAlarmCallback) } override fun onViewDetached() { + clock.setOnClickListener(null) privacyIconsController.chipVisibilityListener = null dumpManager.unregisterDumpable(this::class.java.simpleName) configurationController.removeCallback(configurationControllerListener) demoModeController.removeCallback(demoModeReceiver) statusBarIconController.removeIconGroup(iconManager) + nextAlarmController.removeCallback(nextAlarmCallback) } fun disable(state1: Int, state2: Int, animate: Boolean) { @@ -318,6 +337,15 @@ constructor( .start() } + @VisibleForTesting + internal fun launchClockActivity() { + if (nextAlarmIntent != null) { + activityStarter.postStartActivityDismissingKeyguard(nextAlarmIntent) + } else { + activityStarter.postStartActivityDismissingKeyguard(DEFAULT_CLOCK_INTENT, 0 /*delay */) + } + } + private fun loadConstraints() { // Use resources.getXml instead of passing the resource id due to bug b/205018300 header @@ -439,12 +467,14 @@ constructor( } private fun updateListeners() { - qsCarrierGroupController.setListening(visible) + mShadeCarrierGroupController.setListening(visible) if (visible) { - updateSingleCarrier(qsCarrierGroupController.isSingleCarrier) - qsCarrierGroupController.setOnSingleCarrierChangedListener { updateSingleCarrier(it) } + updateSingleCarrier(mShadeCarrierGroupController.isSingleCarrier) + mShadeCarrierGroupController.setOnSingleCarrierChangedListener { + updateSingleCarrier(it) + } } else { - qsCarrierGroupController.setOnSingleCarrierChangedListener(null) + mShadeCarrierGroupController.setOnSingleCarrierChangedListener(null) } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt index da4944c20f6e..a93183865a3f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt @@ -316,4 +316,80 @@ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) { { "QSC NotificationsClippingTopBound set to $int1 - $int2" } ) } + + fun logOnTouchEventLastReturn( + event: MotionEvent, + dozing: Boolean, + handled: Boolean, + ) { + buffer.log( + TAG, + LogLevel.VERBOSE, + { + bool1 = dozing + bool2 = handled + long1 = event.eventTime + long2 = event.downTime + int1 = event.action + int2 = event.classification + double1 = event.y.toDouble() + }, + { + "NPVC onTouchEvent last return: !mDozing: $bool1 || handled: $bool2 " + + "\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2" + } + ) + } + + fun logHandleTouchLastReturn( + event: MotionEvent, + gestureWaitForTouchSlop: Boolean, + tracking: Boolean, + ) { + buffer.log( + TAG, + LogLevel.VERBOSE, + { + bool1 = gestureWaitForTouchSlop + bool2 = tracking + long1 = event.eventTime + long2 = event.downTime + int1 = event.action + int2 = event.classification + double1 = event.y.toDouble() + }, + { + "NPVC handleTouch last return: !mGestureWaitForTouchSlop: $bool1 " + + "|| mTracking: $bool2 " + + "\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2" + } + ) + } + + fun logUpdateNotificationPanelTouchState( + disabled: Boolean, + isGoingToSleep: Boolean, + shouldControlScreenOff: Boolean, + deviceInteractive: Boolean, + isPulsing: Boolean, + isFrpActive: Boolean, + ) { + buffer.log( + TAG, + LogLevel.VERBOSE, + { + bool1 = disabled + bool2 = isGoingToSleep + bool3 = shouldControlScreenOff + bool4 = deviceInteractive + str1 = isPulsing.toString() + str2 = isFrpActive.toString() + }, + { + "CentralSurfaces updateNotificationPanelTouchState set disabled to: $bool1\n" + + "isGoingToSleep: $bool2, !shouldControlScreenOff: $bool3," + + "!mDeviceInteractive: $bool4, !isPulsing: $str1, isFrpActive: $str2" + } + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt b/packages/SystemUI/src/com/android/systemui/shade/carrier/CellSignalState.kt index e925b5472c27..958230bbef99 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/CellSignalState.kt @@ -1,11 +1,11 @@ /* - * Copyright (C) 2020 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.android.systemui.qs.carrier +package com.android.systemui.shade.carrier /** * Represents the state of cell signal for a particular slot. * - * To be used between [QSCarrierGroupController] and [QSCarrier]. + * To be used between [ShadeCarrierGroupController] and [ShadeCarrier]. */ data class CellSignalState( @JvmField val visible: Boolean = false, @@ -37,7 +37,6 @@ data class CellSignalState( * @return `this` if `this.visible == visible`. Else, a new copy with the visibility changed. */ fun changeVisibility(visible: Boolean): CellSignalState { - if (this.visible == visible) return this - else return copy(visible = visible) + if (this.visible == visible) return this else return copy(visible = visible) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java index b5ceeaed4904..8586828af0cd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java +++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2020 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.qs.carrier; +package com.android.systemui.shade.carrier; import android.annotation.StyleRes; import android.content.Context; @@ -38,7 +38,7 @@ import com.android.systemui.util.LargeScreenUtils; import java.util.Objects; -public class QSCarrier extends LinearLayout { +public class ShadeCarrier extends LinearLayout { private View mMobileGroup; private TextView mCarrierText; @@ -50,19 +50,19 @@ public class QSCarrier extends LinearLayout { private boolean mMobileSignalInitialized = false; private boolean mIsSingleCarrier; - public QSCarrier(Context context) { + public ShadeCarrier(Context context) { super(context); } - public QSCarrier(Context context, AttributeSet attrs) { + public ShadeCarrier(Context context, AttributeSet attrs) { super(context, attrs); } - public QSCarrier(Context context, AttributeSet attrs, int defStyleAttr) { + public ShadeCarrier(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } - public QSCarrier(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public ShadeCarrier(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @@ -72,7 +72,7 @@ public class QSCarrier extends LinearLayout { mMobileGroup = findViewById(R.id.mobile_combo); mMobileRoaming = findViewById(R.id.mobile_roaming); mMobileSignal = findViewById(R.id.mobile_signal); - mCarrierText = findViewById(R.id.qs_carrier_text); + mCarrierText = findViewById(R.id.shade_carrier_text); mSpacer = findViewById(R.id.spacer); updateResources(); } @@ -158,7 +158,7 @@ public class QSCarrier extends LinearLayout { mCarrierText.setMaxEms( useLargeScreenHeader ? Integer.MAX_VALUE - : getResources().getInteger(R.integer.qs_carrier_max_em) + : getResources().getInteger(R.integer.shade_carrier_max_em) ); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroup.java index a36035b99b4f..68561d1cfd0f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java +++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroup.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2020 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.qs.carrier; +package com.android.systemui.shade.carrier; import android.annotation.StyleRes; import android.content.Context; @@ -27,10 +27,10 @@ import com.android.systemui.FontSizeUtils; import com.android.systemui.R; /** - * Displays Carrier name and network status in QS + * Displays Carrier name and network status in the shade header */ -public class QSCarrierGroup extends LinearLayout { - public QSCarrierGroup(Context context, AttributeSet attrs) { +public class ShadeCarrierGroup extends LinearLayout { + public ShadeCarrierGroup(Context context, AttributeSet attrs) { super(context, attrs); } @@ -38,24 +38,24 @@ public class QSCarrierGroup extends LinearLayout { return findViewById(R.id.no_carrier_text); } - QSCarrier getCarrier1View() { + ShadeCarrier getCarrier1View() { return findViewById(R.id.carrier1); } - QSCarrier getCarrier2View() { + ShadeCarrier getCarrier2View() { return findViewById(R.id.carrier2); } - QSCarrier getCarrier3View() { + ShadeCarrier getCarrier3View() { return findViewById(R.id.carrier3); } View getCarrierDivider1() { - return findViewById(R.id.qs_carrier_divider1); + return findViewById(R.id.shade_carrier_divider1); } View getCarrierDivider2() { - return findViewById(R.id.qs_carrier_divider2); + return findViewById(R.id.shade_carrier_divider2); } public void updateTextAppearance(@StyleRes int resId) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java index 6a8bf759a849..0ebcfa2a1876 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2020 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.qs.carrier; +package com.android.systemui.shade.carrier; import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; @@ -52,8 +52,8 @@ import java.util.function.Consumer; import javax.inject.Inject; -public class QSCarrierGroupController { - private static final String TAG = "QSCarrierGroup"; +public class ShadeCarrierGroupController { + private static final String TAG = "ShadeCarrierGroup"; /** * Support up to 3 slots which is what's supported by {@link TelephonyManager#getPhoneCount} @@ -72,7 +72,7 @@ public class QSCarrierGroupController { private final CellSignalState[] mInfos = new CellSignalState[SIM_SLOTS]; private View[] mCarrierDividers = new View[SIM_SLOTS - 1]; - private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS]; + private ShadeCarrier[] mCarrierGroups = new ShadeCarrier[SIM_SLOTS]; private int[] mLastSignalLevel = new int[SIM_SLOTS]; private String[] mLastSignalLevelDescription = new String[SIM_SLOTS]; private final CarrierConfigTracker mCarrierConfigTracker; @@ -129,7 +129,7 @@ public class QSCarrierGroupController { } } - private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter, + private ShadeCarrierGroupController(ShadeCarrierGroup view, ActivityStarter activityStarter, @Background Handler bgHandler, @Main Looper mainLooper, NetworkController networkController, CarrierTextManager.Builder carrierTextManagerBuilder, Context context, @@ -167,7 +167,7 @@ public class QSCarrierGroupController { for (int i = 0; i < SIM_SLOTS; i++) { mInfos[i] = new CellSignalState( true, - R.drawable.ic_qs_no_calling_sms, + R.drawable.ic_shade_no_calling_sms, context.getText(AccessibilityContentDescriptions.NO_CALLING).toString(), "", false); @@ -257,7 +257,7 @@ public class QSCarrierGroupController { if (singleCarrier) { for (int i = 0; i < SIM_SLOTS; i++) { if (mInfos[i].visible - && mInfos[i].mobileSignalIconId == R.drawable.ic_qs_sim_card) { + && mInfos[i].mobileSignalIconId == R.drawable.ic_shade_sim_card) { mInfos[i] = new CellSignalState(true, R.drawable.ic_blank, "", "", false); } } @@ -322,8 +322,8 @@ public class QSCarrierGroupController { Log.e(TAG, "Carrier information arrays not of same length"); } } else { - // No sims or airplane mode (but not WFC). Do not show QSCarrierGroup, instead just show - // info.carrierText in a different view. + // No sims or airplane mode (but not WFC). Do not show ShadeCarrierGroup, + // instead just show info.carrierText in a different view. for (int i = 0; i < SIM_SLOTS; i++) { mInfos[i] = mInfos[i].changeVisibility(false); mCarrierGroups[i].setCarrierText(""); @@ -368,7 +368,7 @@ public class QSCarrierGroupController { } public static class Builder { - private QSCarrierGroup mView; + private ShadeCarrierGroup mView; private final ActivityStarter mActivityStarter; private final Handler mHandler; private final Looper mLooper; @@ -393,13 +393,13 @@ public class QSCarrierGroupController { mSlotIndexResolver = slotIndexResolver; } - public Builder setQSCarrierGroup(QSCarrierGroup view) { + public Builder setShadeCarrierGroup(ShadeCarrierGroup view) { mView = view; return this; } - public QSCarrierGroupController build() { - return new QSCarrierGroupController(mView, mActivityStarter, mHandler, mLooper, + public ShadeCarrierGroupController build() { + return new ShadeCarrierGroupController(mView, mActivityStarter, mHandler, mLooper, mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker, mSlotIndexResolver); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java index c84894fc81ee..06f43f1eeaa5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java @@ -841,6 +841,19 @@ public final class KeyboardShortcutListSearch { BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet); behavior.setState(BottomSheetBehavior.STATE_EXPANDED); behavior.setSkipCollapsed(true); + behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { + @Override + public void onStateChanged(@NonNull View bottomSheet, int newState) { + if (newState == BottomSheetBehavior.STATE_DRAGGING) { + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + } + } + + @Override + public void onSlide(@NonNull View bottomSheet, float slideOffset) { + // Do nothing. + } + }); mKeyboardShortcutsBottomSheetDialog.setCanceledOnTouchOutside(true); Window keyboardShortcutsWindow = mKeyboardShortcutsBottomSheetDialog.getWindow(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 765c93ed209b..142689e88b51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -1127,13 +1127,7 @@ public class KeyguardIndicationController { final boolean faceAuthUnavailable = biometricSourceType == FACE && msgId == BIOMETRIC_HELP_FACE_NOT_AVAILABLE; - // TODO(b/141025588): refactor to reduce repetition of code/comments - // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong - // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to - // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the - // check of whether non-strong biometric is allowed - if (!mKeyguardUpdateMonitor - .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */) + if (isPrimaryAuthRequired() && !faceAuthUnavailable) { return; } @@ -1234,7 +1228,7 @@ public class KeyguardIndicationController { private void onFaceAuthError(int msgId, String errString) { CharSequence deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage(); mFaceAcquiredMessageDeferral.reset(); - if (shouldSuppressFaceError(msgId, mKeyguardUpdateMonitor)) { + if (shouldSuppressFaceError(msgId)) { mKeyguardLogger.logBiometricMessage("suppressingFaceError", msgId, errString); return; } @@ -1248,7 +1242,7 @@ public class KeyguardIndicationController { } private void onFingerprintAuthError(int msgId, String errString) { - if (shouldSuppressFingerprintError(msgId, mKeyguardUpdateMonitor)) { + if (shouldSuppressFingerprintError(msgId)) { mKeyguardLogger.logBiometricMessage("suppressingFingerprintError", msgId, errString); @@ -1257,31 +1251,19 @@ public class KeyguardIndicationController { } } - private boolean shouldSuppressFingerprintError(int msgId, - KeyguardUpdateMonitor updateMonitor) { - // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong - // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to - // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the - // check of whether non-strong biometric is allowed - return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */) - && !isLockoutError(msgId)) + private boolean shouldSuppressFingerprintError(int msgId) { + return ((isPrimaryAuthRequired() && !isLockoutError(msgId)) || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED || msgId == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED || msgId == FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED); } - private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) { - // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong - // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to - // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the - // check of whether non-strong biometric is allowed - return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */) - && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) + private boolean shouldSuppressFaceError(int msgId) { + return ((isPrimaryAuthRequired() && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) || msgId == FaceManager.FACE_ERROR_CANCELED || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS); } - @Override public void onTrustChanged(int userId) { if (!isCurrentUser(userId)) return; @@ -1355,6 +1337,16 @@ public class KeyguardIndicationController { } } + private boolean isPrimaryAuthRequired() { + // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong + // as long as primary auth, i.e. PIN/pattern/password, is required), so it's ok to + // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the + // check of whether non-strong biometric is allowed since strong biometrics can still be + // used. + return !mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + true /* isStrongBiometric */); + } + protected boolean isPluggedInAndCharging() { return mPowerPluggedIn; } @@ -1431,7 +1423,7 @@ public class KeyguardIndicationController { private boolean canUnlockWithFingerprint() { return mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - getCurrentUser()); + getCurrentUser()) && mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed(); } private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java index cb4ae286d5c3..f7d37e6b1058 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java @@ -25,7 +25,6 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationIconContainer; @@ -35,7 +34,7 @@ import javax.inject.Inject; * Controller class for {@link NotificationShelf}. */ @NotificationRowScope -public class NotificationShelfController { +public class LegacyNotificationShelfControllerImpl implements NotificationShelfController { private final NotificationShelf mView; private final ActivatableNotificationViewController mActivatableNotificationViewController; private final KeyguardBypassController mKeyguardBypassController; @@ -44,7 +43,7 @@ public class NotificationShelfController { private AmbientState mAmbientState; @Inject - public NotificationShelfController( + public LegacyNotificationShelfControllerImpl( NotificationShelf notificationShelf, ActivatableNotificationViewController activatableNotificationViewController, KeyguardBypassController keyguardBypassController, @@ -79,56 +78,42 @@ public class NotificationShelfController { } } + @Override public NotificationShelf getView() { return mView; } + @Override public boolean canModifyColorOfNotifications() { return mAmbientState.isShadeExpanded() && !(mAmbientState.isOnKeyguard() && mKeyguardBypassController.getBypassEnabled()); } + @Override public NotificationIconContainer getShelfIcons() { return mView.getShelfIcons(); } - public @View.Visibility int getVisibility() { - return mView.getVisibility(); - } - - public void setCollapsedIcons(NotificationIconContainer notificationIcons) { - mView.setCollapsedIcons(notificationIcons); - } - + @Override public void bind(AmbientState ambientState, NotificationStackScrollLayoutController notificationStackScrollLayoutController) { mView.bind(ambientState, notificationStackScrollLayoutController); mAmbientState = ambientState; } - public int getHeight() { - return mView.getHeight(); - } - - public void updateState(StackScrollAlgorithm.StackScrollAlgorithmState algorithmState, - AmbientState ambientState) { - mAmbientState = ambientState; - mView.updateState(algorithmState, ambientState); - } - + @Override public int getIntrinsicHeight() { return mView.getIntrinsicHeight(); } + @Override public void setOnActivatedListener(ActivatableNotificationView.OnActivatedListener listener) { mView.setOnActivatedListener(listener); } + @Override public void setOnClickListener(View.OnClickListener onClickListener) { mView.setOnClickListener(onClickListener); } - public int getNotGoneIndex() { - return mView.getNotGoneIndex(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index ced725e0b1d6..ea9817c68c30 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -702,6 +702,13 @@ public class NotificationMediaManager implements Dumpable { mProcessArtworkTasks.remove(task); } + // TODO(b/273443374): remove + public boolean isLockscreenWallpaperOnNotificationShade() { + return mBackdrop != null && mLockscreenWallpaper != null + && !mLockscreenWallpaper.isLockscreenLiveWallpaperEnabled() + && (mBackdropFront.isVisibleToUser() || mBackdropBack.isVisibleToUser()); + } + /** * {@link AsyncTask} to prepare album art for use as backdrop on lock screen. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 4873c9dae89a..7eb63da38028 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -24,6 +24,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.util.AttributeSet; import android.util.IndentingPrintWriter; +import android.util.Log; import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; @@ -52,6 +53,8 @@ import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; +import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm; import com.android.systemui.statusbar.notification.stack.ViewState; @@ -64,8 +67,7 @@ import java.io.PrintWriter; * A notification shelf view that is placed inside the notification scroller. It manages the * overflow icons that don't fit into the regular list anymore. */ -public class NotificationShelf extends ActivatableNotificationView implements - View.OnLayoutChangeListener, StateListener { +public class NotificationShelf extends ActivatableNotificationView implements StateListener { private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag; private static final String TAG = "NotificationShelf"; @@ -78,7 +80,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private static final SourceType SHELF_SCROLL = SourceType.from("ShelfScroll"); private NotificationIconContainer mShelfIcons; - private int[] mTmp = new int[2]; private boolean mHideBackground; private int mStatusBarHeight; private boolean mEnableNotificationClipping; @@ -87,7 +88,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private int mPaddingBetweenElements; private int mNotGoneIndex; private boolean mHasItemsInStableShelf; - private NotificationIconContainer mCollapsedIcons; private int mScrollFastThreshold; private int mStatusBarState; private boolean mInteractive; @@ -99,6 +99,11 @@ public class NotificationShelf extends ActivatableNotificationView implements private NotificationShelfController mController; private float mActualWidth = -1; private boolean mSensitiveRevealAnimEndabled; + private boolean mShelfRefactorFlagEnabled; + private boolean mCanModifyColorOfNotifications; + private boolean mCanInteract; + private NotificationStackScrollLayout mHostLayout; + private NotificationRoundnessManager mRoundnessManager; public NotificationShelf(Context context, AttributeSet attrs) { super(context, attrs); @@ -135,6 +140,7 @@ public class NotificationShelf extends ActivatableNotificationView implements public void bind(AmbientState ambientState, NotificationStackScrollLayoutController hostLayoutController) { + assertRefactorFlagDisabled(); mAmbientState = ambientState; mHostLayoutController = hostLayoutController; hostLayoutController.setOnNotificationRemovedListener((child, isTransferInProgress) -> { @@ -142,6 +148,14 @@ public class NotificationShelf extends ActivatableNotificationView implements }); } + public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout, + NotificationRoundnessManager roundnessManager) { + if (!checkRefactorFlagEnabled()) return; + mAmbientState = ambientState; + mHostLayout = hostLayout; + mRoundnessManager = roundnessManager; + } + private void updateResources() { Resources res = getResources(); mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext); @@ -233,7 +247,7 @@ public class NotificationShelf extends ActivatableNotificationView implements } else { viewState.setAlpha(1f - ambientState.getHideAmount()); } - viewState.belowSpeedBump = mHostLayoutController.getSpeedBumpIndex() == 0; + viewState.belowSpeedBump = getSpeedBumpIndex() == 0; viewState.hideSensitive = false; viewState.setXTranslation(getTranslationX()); viewState.hasItemsInStableShelf = lastViewState.inShelf; @@ -276,6 +290,14 @@ public class NotificationShelf extends ActivatableNotificationView implements } } + private int getSpeedBumpIndex() { + if (mShelfRefactorFlagEnabled) { + return mHostLayout.getSpeedBumpIndex(); + } else { + return mHostLayoutController.getSpeedBumpIndex(); + } + } + /** * @param fractionToShade Fraction of lockscreen to shade transition * @param shortestWidth Shortest width to use for lockscreen shelf @@ -388,8 +410,8 @@ public class NotificationShelf extends ActivatableNotificationView implements int baseZHeight = mAmbientState.getBaseZHeight(); int clipTopAmount = 0; - for (int i = 0; i < mHostLayoutController.getChildCount(); i++) { - ExpandableView child = mHostLayoutController.getChildAt(i); + for (int i = 0; i < getHostLayoutChildCount(); i++) { + ExpandableView child = getHostLayoutChildAt(i); if (!child.needsClippingToShelf() || child.getVisibility() == GONE) { continue; } @@ -428,7 +450,7 @@ public class NotificationShelf extends ActivatableNotificationView implements transitionAmount = inShelfAmount; } // We don't want to modify the color if the notification is hun'd - if (isLastChild && mController.canModifyColorOfNotifications()) { + if (isLastChild && canModifyColorOfNotifications()) { if (colorOfViewBeforeLast == NO_COLOR) { colorOfViewBeforeLast = ownColorUntinted; } @@ -474,11 +496,11 @@ public class NotificationShelf extends ActivatableNotificationView implements // TODO(b/172289889) transition last icon in shelf to notification icon and vice versa. setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE); - mShelfIcons.setSpeedBumpIndex(mHostLayoutController.getSpeedBumpIndex()); + mShelfIcons.setSpeedBumpIndex(getSpeedBumpIndex()); mShelfIcons.calculateIconXTranslations(); mShelfIcons.applyIconStates(); - for (int i = 0; i < mHostLayoutController.getChildCount(); i++) { - View child = mHostLayoutController.getChildAt(i); + for (int i = 0; i < getHostLayoutChildCount(); i++) { + View child = getHostLayoutChildAt(i); if (!(child instanceof ExpandableNotificationRow) || child.getVisibility() == GONE) { continue; @@ -493,6 +515,30 @@ public class NotificationShelf extends ActivatableNotificationView implements } } + private ExpandableView getHostLayoutChildAt(int index) { + if (mShelfRefactorFlagEnabled) { + return (ExpandableView) mHostLayout.getChildAt(index); + } else { + return mHostLayoutController.getChildAt(index); + } + } + + private int getHostLayoutChildCount() { + if (mShelfRefactorFlagEnabled) { + return mHostLayout.getChildCount(); + } else { + return mHostLayoutController.getChildCount(); + } + } + + private boolean canModifyColorOfNotifications() { + if (mShelfRefactorFlagEnabled) { + return mCanModifyColorOfNotifications && mAmbientState.isShadeExpanded(); + } else { + return mController.canModifyColorOfNotifications(); + } + } + private void updateCornerRoundnessOnScroll( ActivatableNotificationView anv, float viewStart, @@ -507,7 +553,7 @@ public class NotificationShelf extends ActivatableNotificationView implements && anv == mAmbientState.getTrackedHeadsUpRow(); final boolean shouldUpdateCornerRoundness = viewStart < shelfStart - && !mHostLayoutController.isViewAffectedBySwipe(anv) + && !isViewAffectedBySwipe(anv) && !isUnlockedHeadsUp && !isHunGoingToShade && !anv.isAboveShelf() @@ -559,6 +605,14 @@ public class NotificationShelf extends ActivatableNotificationView implements anv.requestBottomRoundness(bottomValue, sourceType, /* animate = */ false); } + private boolean isViewAffectedBySwipe(ExpandableView expandableView) { + if (!mShelfRefactorFlagEnabled) { + return mHostLayoutController.isViewAffectedBySwipe(expandableView); + } else { + return mRoundnessManager.isViewAffectedBySwipe(expandableView); + } + } + /** * Clips transient views to the top of the shelf - Transient views are only used for * disappearing views/animations and need to be clipped correctly by the shelf to ensure they @@ -566,8 +620,8 @@ public class NotificationShelf extends ActivatableNotificationView implements * swipes quickly. */ private void clipTransientViews() { - for (int i = 0; i < mHostLayoutController.getTransientViewCount(); i++) { - View transientView = mHostLayoutController.getTransientView(i); + for (int i = 0; i < getHostLayoutTransientViewCount(); i++) { + View transientView = getHostLayoutTransientView(i); if (transientView instanceof ExpandableView) { ExpandableView transientExpandableView = (ExpandableView) transientView; updateNotificationClipHeight(transientExpandableView, getTranslationY(), -1); @@ -575,6 +629,22 @@ public class NotificationShelf extends ActivatableNotificationView implements } } + private View getHostLayoutTransientView(int index) { + if (mShelfRefactorFlagEnabled) { + return mHostLayout.getTransientView(index); + } else { + return mHostLayoutController.getTransientView(index); + } + } + + private int getHostLayoutTransientViewCount() { + if (mShelfRefactorFlagEnabled) { + return mHostLayout.getTransientViewCount(); + } else { + return mHostLayoutController.getTransientViewCount(); + } + } + private void updateIconClipAmount(ExpandableNotificationRow row) { float maxTop = row.getTranslationY(); if (getClipTopAmount() != 0) { @@ -868,10 +938,6 @@ public class NotificationShelf extends ActivatableNotificationView implements return mShelfIcons.getIconState(icon); } - private float getFullyClosedTranslation() { - return -(getIntrinsicHeight() - mStatusBarHeight) / 2; - } - @Override public boolean hasNoContentHeight() { return true; @@ -893,7 +959,6 @@ public class NotificationShelf extends ActivatableNotificationView implements @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - updateRelativeOffset(); // we always want to clip to our sides, such that nothing can draw outside of these bounds int height = getResources().getDisplayMetrics().heightPixels; @@ -903,13 +968,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } } - private void updateRelativeOffset() { - if (mCollapsedIcons != null) { - mCollapsedIcons.getLocationOnScreen(mTmp); - } - getLocationOnScreen(mTmp); - } - /** * @return the index of the notification at which the shelf visually resides */ @@ -924,33 +982,29 @@ public class NotificationShelf extends ActivatableNotificationView implements } } - /** - * @return whether the shelf has any icons in it when a potential animation has finished, i.e - * if the current state would be applied right now - */ - public boolean hasItemsInStableShelf() { - return mHasItemsInStableShelf; - } - - public void setCollapsedIcons(NotificationIconContainer collapsedIcons) { - mCollapsedIcons = collapsedIcons; - mCollapsedIcons.addOnLayoutChangeListener(this); - } - @Override public void onStateChanged(int newState) { + assertRefactorFlagDisabled(); mStatusBarState = newState; updateInteractiveness(); } private void updateInteractiveness() { - mInteractive = mStatusBarState == StatusBarState.KEYGUARD && mHasItemsInStableShelf; + mInteractive = canInteract() && mHasItemsInStableShelf; setClickable(mInteractive); setFocusable(mInteractive); setImportantForAccessibility(mInteractive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); } + private boolean canInteract() { + if (mShelfRefactorFlagEnabled) { + return mCanInteract; + } else { + return mStatusBarState == StatusBarState.KEYGUARD; + } + } + @Override protected boolean isInteractive() { return mInteractive; @@ -983,22 +1037,50 @@ public class NotificationShelf extends ActivatableNotificationView implements } @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, - int oldTop, int oldRight, int oldBottom) { - updateRelativeOffset(); - } - - @Override public boolean needsClippingToShelf() { return false; } + private void assertRefactorFlagDisabled() { + if (mShelfRefactorFlagEnabled) { + NotificationShelfController.throwIllegalFlagStateError(false); + } + } + + private boolean checkRefactorFlagEnabled() { + if (!mShelfRefactorFlagEnabled) { + Log.wtf(TAG, + "Code path not supported when Flags.NOTIFICATION_SHELF_REFACTOR is disabled."); + } + return mShelfRefactorFlagEnabled; + } + public void setController(NotificationShelfController notificationShelfController) { + assertRefactorFlagDisabled(); mController = notificationShelfController; } + public void setCanModifyColorOfNotifications(boolean canModifyColorOfNotifications) { + if (!checkRefactorFlagEnabled()) return; + mCanModifyColorOfNotifications = canModifyColorOfNotifications; + } + + public void setCanInteract(boolean canInteract) { + if (!checkRefactorFlagEnabled()) return; + mCanInteract = canInteract; + updateInteractiveness(); + } + public void setIndexOfFirstViewInShelf(ExpandableView firstViewInShelf) { - mIndexOfFirstViewInShelf = mHostLayoutController.indexOfChild(firstViewInShelf); + mIndexOfFirstViewInShelf = getIndexOfViewInHostLayout(firstViewInShelf); + } + + private int getIndexOfViewInHostLayout(ExpandableView child) { + if (mShelfRefactorFlagEnabled) { + return mHostLayout.indexOfChild(child); + } else { + return mHostLayoutController.indexOfChild(child); + } } /** @@ -1009,6 +1091,15 @@ public class NotificationShelf extends ActivatableNotificationView implements mSensitiveRevealAnimEndabled = enabled; } + public void setRefactorFlagEnabled(boolean enabled) { + mShelfRefactorFlagEnabled = enabled; + } + + public void requestRoundnessResetFor(ExpandableView child) { + if (!checkRefactorFlagEnabled()) return; + child.requestRoundnessReset(SHELF_SCROLL); + } + /** * This method resets the OnScroll roundness of a view to 0f * <p> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt new file mode 100644 index 000000000000..07cfd0d8019c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.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.systemui.statusbar + +import android.util.Log +import android.view.View +import android.view.View.OnClickListener +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView.OnActivatedListener +import com.android.systemui.statusbar.notification.row.ExpandableView +import com.android.systemui.statusbar.notification.stack.AmbientState +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.phone.NotificationIconContainer + +/** Controller interface for [NotificationShelf]. */ +interface NotificationShelfController { + /** The [NotificationShelf] controlled by this Controller. */ + val view: NotificationShelf + + /** @see ExpandableView.getIntrinsicHeight */ + val intrinsicHeight: Int + + /** Container view for icons displayed in the shelf. */ + val shelfIcons: NotificationIconContainer + + /** Whether or not the shelf can modify the color of notifications in the shade. */ + fun canModifyColorOfNotifications(): Boolean + + /** @see ActivatableNotificationView.setOnActivatedListener */ + fun setOnActivatedListener(listener: OnActivatedListener) + + /** Binds the shelf to the host [NotificationStackScrollLayout], via its Controller. */ + fun bind( + ambientState: AmbientState, + notificationStackScrollLayoutController: NotificationStackScrollLayoutController, + ) + + /** @see View.setOnClickListener */ + fun setOnClickListener(listener: OnClickListener) + + companion object { + @JvmStatic + fun assertRefactorFlagDisabled(featureFlags: FeatureFlags) { + if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { + throwIllegalFlagStateError(expected = false) + } + } + + @JvmStatic + fun checkRefactorFlagEnabled(featureFlags: FeatureFlags): Boolean = + featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR).also { enabled -> + if (!enabled) { + Log.wtf("NotifShelf", getErrorMessage(expected = true)) + } + } + + @JvmStatic + fun throwIllegalFlagStateError(expected: Boolean): Nothing = + error(getErrorMessage(expected)) + + private fun getErrorMessage(expected: Boolean): String = + "Code path not supported when Flags.NOTIFICATION_SHELF_REFACTOR is " + + if (expected) "disabled" else "enabled" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java index 565c0a9426ab..34300c731343 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java @@ -38,8 +38,8 @@ import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteracto import com.android.systemui.media.controls.pipeline.MediaDataManager; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.qs.carrier.QSCarrierGroupController; import com.android.systemui.settings.DisplayTracker; +import com.android.systemui.shade.carrier.ShadeCarrierGroupController; import com.android.systemui.statusbar.ActionClickLogger; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.MediaArtworkProcessor; @@ -78,14 +78,14 @@ import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.time.SystemClock; +import java.util.Optional; +import java.util.concurrent.Executor; + import dagger.Binds; import dagger.Lazy; import dagger.Module; import dagger.Provides; -import java.util.Optional; -import java.util.concurrent.Executor; - /** * This module provides instances needed to construct {@link CentralSurfacesImpl}. These are moved to * this separate from {@link CentralSurfacesModule} module so that components that wish to build @@ -271,8 +271,8 @@ public interface CentralSurfacesDependenciesModule { /** */ @Binds - QSCarrierGroupController.SlotIndexResolver provideSlotIndexResolver( - QSCarrierGroupController.SubscriptionManagerSlotIndexResolver impl); + ShadeCarrierGroupController.SlotIndexResolver provideSlotIndexResolver( + ShadeCarrierGroupController.SubscriptionManagerSlotIndexResolver impl); /** */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java index ecd0c41ff82d..fcff4376811e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java @@ -48,6 +48,10 @@ public abstract class AnimatableProperty { View.SCALE_Y, R.id.scale_y_animator_tag, R.id.scale_y_animator_start_value_tag, R.id.scale_y_animator_end_value_tag); + public static final AnimatableProperty ALPHA = AnimatableProperty.from( + View.ALPHA, R.id.alpha_animator_tag, R.id.alpha_animator_start_value_tag, + R.id.alpha_animator_end_value_tag); + /** * Similar to X, however this doesn't allow for any other modifications other than from this * property. When using X, it's possible that the view is laid out during the animation, 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 f7790e861e27..789873675bfa 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 @@ -22,7 +22,6 @@ import static android.app.Notification.CATEGORY_EVENT; import static android.app.Notification.CATEGORY_MESSAGE; import static android.app.Notification.CATEGORY_REMINDER; import static android.app.Notification.FLAG_BUBBLE; -import static android.app.Notification.FLAG_FOREGROUND_SERVICE; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; @@ -825,8 +824,7 @@ public final class NotificationEntry extends ListEntry { return false; } - if ((mSbn.getNotification().flags - & FLAG_FOREGROUND_SERVICE) != 0) { + if (mSbn.getNotification().isFgsOrUij()) { return true; } if (mSbn.getNotification().isMediaNotification()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt index 15ad312b413e..1631ae28bf5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt @@ -24,6 +24,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner +import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider import com.android.systemui.statusbar.notification.collection.render.NodeController import com.android.systemui.statusbar.notification.dagger.PeopleHeader import com.android.systemui.statusbar.notification.icon.ConversationIconManager @@ -40,27 +41,28 @@ import javax.inject.Inject */ @CoordinatorScope class ConversationCoordinator @Inject constructor( - private val peopleNotificationIdentifier: PeopleNotificationIdentifier, - private val conversationIconManager: ConversationIconManager, - @PeopleHeader peopleHeaderController: NodeController + private val peopleNotificationIdentifier: PeopleNotificationIdentifier, + private val conversationIconManager: ConversationIconManager, + private val highPriorityProvider: HighPriorityProvider, + @PeopleHeader private val peopleHeaderController: NodeController, ) : Coordinator { private val promotedEntriesToSummaryOfSameChannel = - mutableMapOf<NotificationEntry, NotificationEntry>() + mutableMapOf<NotificationEntry, NotificationEntry>() private val onBeforeRenderListListener = OnBeforeRenderListListener { _ -> val unimportantSummaries = promotedEntriesToSummaryOfSameChannel - .mapNotNull { (promoted, summary) -> - val originalGroup = summary.parent - when { - originalGroup == null -> null - originalGroup == promoted.parent -> null - originalGroup.parent == null -> null - originalGroup.summary != summary -> null - originalGroup.children.any { it.channel == summary.channel } -> null - else -> summary.key + .mapNotNull { (promoted, summary) -> + val originalGroup = summary.parent + when { + originalGroup == null -> null + originalGroup == promoted.parent -> null + originalGroup.parent == null -> null + originalGroup.summary != summary -> null + originalGroup.children.any { it.channel == summary.channel } -> null + else -> summary.key + } } - } conversationIconManager.setUnimportantConversations(unimportantSummaries) promotedEntriesToSummaryOfSameChannel.clear() } @@ -78,21 +80,23 @@ class ConversationCoordinator @Inject constructor( } } - val sectioner = object : NotifSectioner("People", BUCKET_PEOPLE) { + val peopleAlertingSectioner = object : NotifSectioner("People(alerting)", BUCKET_PEOPLE) { override fun isInSection(entry: ListEntry): Boolean = - isConversation(entry) + highPriorityProvider.isHighPriorityConversation(entry) - override fun getComparator() = object : NotifComparator("People") { - override fun compare(entry1: ListEntry, entry2: ListEntry): Int { - val type1 = getPeopleType(entry1) - val type2 = getPeopleType(entry2) - return type2.compareTo(type1) - } - } + override fun getComparator(): NotifComparator = notifComparator - override fun getHeaderNodeController() = - // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and peopleHeaderController - if (RankingCoordinator.SHOW_ALL_SECTIONS) peopleHeaderController else null + override fun getHeaderNodeController(): NodeController? = conversationHeaderNodeController + } + + val peopleSilentSectioner = object : NotifSectioner("People(silent)", BUCKET_PEOPLE) { + // Because the peopleAlertingSectioner is above this one, it will claim all conversations that are alerting. + // All remaining conversations must be silent. + override fun isInSection(entry: ListEntry): Boolean = isConversation(entry) + + override fun getComparator(): NotifComparator = notifComparator + + override fun getHeaderNodeController(): NodeController? = conversationHeaderNodeController } override fun attach(pipeline: NotifPipeline) { @@ -101,15 +105,27 @@ class ConversationCoordinator @Inject constructor( } private fun isConversation(entry: ListEntry): Boolean = - getPeopleType(entry) != TYPE_NON_PERSON + getPeopleType(entry) != TYPE_NON_PERSON @PeopleNotificationType private fun getPeopleType(entry: ListEntry): Int = - entry.representativeEntry?.let { - peopleNotificationIdentifier.getPeopleNotificationType(it) - } ?: TYPE_NON_PERSON + entry.representativeEntry?.let { + peopleNotificationIdentifier.getPeopleNotificationType(it) + } ?: TYPE_NON_PERSON + + private val notifComparator: NotifComparator = object : NotifComparator("People") { + override fun compare(entry1: ListEntry, entry2: ListEntry): Int { + val type1 = getPeopleType(entry1) + val type2 = getPeopleType(entry2) + return type2.compareTo(type1) + } + } + + // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and peopleHeaderController + private val conversationHeaderNodeController: NodeController? = + if (RankingCoordinator.SHOW_ALL_SECTIONS) peopleHeaderController else null - companion object { + private companion object { private const val TAG = "ConversationCoordinator" } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt index 82bd45ce2279..6322edf5a1b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt @@ -24,6 +24,10 @@ import androidx.annotation.VisibleForTesting import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.expansionChanges @@ -40,22 +44,26 @@ import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow -import javax.inject.Inject -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.yield +import javax.inject.Inject +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds /** * Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section @@ -69,6 +77,7 @@ constructor( private val headsUpManager: HeadsUpManager, private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider, private val keyguardRepository: KeyguardRepository, + private val keyguardTransitionRepository: KeyguardTransitionRepository, private val notifPipelineFlags: NotifPipelineFlags, @Application private val scope: CoroutineScope, private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider, @@ -99,21 +108,46 @@ constructor( } private suspend fun trackUnseenNotificationsWhileUnlocked() { + // Whether or not we're actively tracking unseen notifications to mark them as seen when + // appropriate. + val isTrackingUnseen: Flow<Boolean> = + keyguardRepository.isKeyguardShowing + // transformLatest so that we can cancel listening to keyguard transitions once + // isKeyguardShowing changes (after a successful transition to the keyguard). + .transformLatest { isShowing -> + if (isShowing) { + // If the keyguard is showing, we're not tracking unseen. + emit(false) + } else { + // If the keyguard stops showing, then start tracking unseen notifications. + emit(true) + // If the screen is turning off, stop tracking, but if that transition is + // cancelled, then start again. + emitAll( + keyguardTransitionRepository.transitions + .map { step -> !step.isScreenTurningOff } + ) + } + } + // Prevent double emit of `false` caused by transition to AOD, followed by keyguard + // showing + .distinctUntilChanged() + // Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is // showing again - var clearUnseenOnUnlock = false - keyguardRepository.isKeyguardShowing.collectLatest { isKeyguardShowing -> - if (isKeyguardShowing) { + var clearUnseenOnBeginTracking = false + isTrackingUnseen.collectLatest { trackingUnseen -> + if (!trackingUnseen) { // Wait for the user to spend enough time on the lock screen before clearing unseen // set when unlocked awaitTimeSpentNotDozing(SEEN_TIMEOUT) - clearUnseenOnUnlock = true + clearUnseenOnBeginTracking = true } else { - unseenNotifFilter.invalidateList("keyguard no longer showing") - if (clearUnseenOnUnlock) { - clearUnseenOnUnlock = false + if (clearUnseenOnBeginTracking) { + clearUnseenOnBeginTracking = false unseenNotifications.clear() } + unseenNotifFilter.invalidateList("keyguard no longer showing") trackUnseenNotifications() } } @@ -142,7 +176,10 @@ constructor( } private suspend fun clearUnseenNotificationsWhenShadeIsExpanded() { - statusBarStateController.expansionChanges.collect { isExpanded -> + statusBarStateController.expansionChanges.collectLatest { isExpanded -> + // Give keyguard events time to propagate, in case this expansion is part of the + // keyguard transition and not the user expanding the shade + yield() if (isExpanded) { unseenNotifications.clear() } @@ -276,3 +313,6 @@ constructor( private val SEEN_TIMEOUT = 5.seconds } } + +private val TransitionStep.isScreenTurningOff: Boolean get() = + transitionState == TransitionState.STARTED && to != KeyguardState.GONE
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt index 6bb5b9218ed7..02ce0d46ead8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt @@ -21,6 +21,7 @@ import com.android.systemui.statusbar.notification.collection.PipelineDumpable import com.android.systemui.statusbar.notification.collection.PipelineDumper import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner +import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider import javax.inject.Inject /** @@ -32,6 +33,7 @@ interface NotifCoordinators : Coordinator, PipelineDumpable @CoordinatorScope class NotifCoordinatorsImpl @Inject constructor( notifPipelineFlags: NotifPipelineFlags, + sectionStyleProvider: SectionStyleProvider, dataStoreCoordinator: DataStoreCoordinator, hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator, hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator, @@ -56,7 +58,7 @@ class NotifCoordinatorsImpl @Inject constructor( viewConfigCoordinator: ViewConfigCoordinator, visualStabilityCoordinator: VisualStabilityCoordinator, sensitiveContentCoordinator: SensitiveContentCoordinator, - dismissibilityCoordinator: DismissibilityCoordinator + dismissibilityCoordinator: DismissibilityCoordinator, ) : NotifCoordinators { private val mCoordinators: MutableList<Coordinator> = ArrayList() @@ -99,13 +101,20 @@ class NotifCoordinatorsImpl @Inject constructor( mCoordinators.add(dismissibilityCoordinator) // Manually add Ordered Sections - // HeadsUp > FGS > People > Alerting > Silent > Minimized > Unknown/Default - mOrderedSections.add(headsUpCoordinator.sectioner) + mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp mOrderedSections.add(appOpsCoordinator.sectioner) // ForegroundService - mOrderedSections.add(conversationCoordinator.sectioner) // People + mOrderedSections.add(conversationCoordinator.peopleAlertingSectioner) // People Alerting + mOrderedSections.add(conversationCoordinator.peopleSilentSectioner) // People Silent mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting mOrderedSections.add(rankingCoordinator.silentSectioner) // Silent mOrderedSections.add(rankingCoordinator.minimizedSectioner) // Minimized + + sectionStyleProvider.setMinimizedSections(setOf(rankingCoordinator.minimizedSectioner)) + sectionStyleProvider.setSilentSections(listOf( + conversationCoordinator.peopleSilentSectioner, + rankingCoordinator.silentSectioner, + rankingCoordinator.minimizedSectioner, + )) } /** 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 ea5cb308a2d0..1d37dcf13037 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 @@ -27,15 +27,12 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger 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.provider.HighPriorityProvider; -import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider; import com.android.systemui.statusbar.notification.collection.render.NodeController; import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; import com.android.systemui.statusbar.notification.dagger.AlertingHeader; import com.android.systemui.statusbar.notification.dagger.SilentHeader; import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import javax.inject.Inject; @@ -52,7 +49,6 @@ public class RankingCoordinator implements Coordinator { public static final boolean SHOW_ALL_SECTIONS = false; private final StatusBarStateController mStatusBarStateController; private final HighPriorityProvider mHighPriorityProvider; - private final SectionStyleProvider mSectionStyleProvider; private final NodeController mSilentNodeController; private final SectionHeaderController mSilentHeaderController; private final NodeController mAlertingHeaderController; @@ -63,13 +59,11 @@ public class RankingCoordinator implements Coordinator { public RankingCoordinator( StatusBarStateController statusBarStateController, HighPriorityProvider highPriorityProvider, - SectionStyleProvider sectionStyleProvider, @AlertingHeader NodeController alertingHeaderController, @SilentHeader SectionHeaderController silentHeaderController, @SilentHeader NodeController silentNodeController) { mStatusBarStateController = statusBarStateController; mHighPriorityProvider = highPriorityProvider; - mSectionStyleProvider = sectionStyleProvider; mAlertingHeaderController = alertingHeaderController; mSilentNodeController = silentNodeController; mSilentHeaderController = silentHeaderController; @@ -78,9 +72,6 @@ public class RankingCoordinator implements Coordinator { @Override public void attach(NotifPipeline pipeline) { mStatusBarStateController.addCallback(mStatusBarStateCallback); - mSectionStyleProvider.setMinimizedSections(Collections.singleton(mMinimizedNotifSectioner)); - mSectionStyleProvider.setSilentSections( - Arrays.asList(mSilentNotifSectioner, mMinimizedNotifSectioner)); pipeline.addPreGroupFilter(mSuspendedFilter); pipeline.addPreGroupFilter(mDndVisualEffectsFilter); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java index e7ef2ec084b7..731ec80817ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java @@ -16,10 +16,13 @@ package com.android.systemui.statusbar.notification.collection.provider; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Notification; import android.app.NotificationManager; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; @@ -63,7 +66,7 @@ public class HighPriorityProvider { * A GroupEntry is considered high priority if its representativeEntry (summary) or children are * high priority */ - public boolean isHighPriority(ListEntry entry) { + public boolean isHighPriority(@Nullable ListEntry entry) { if (entry == null) { return false; } @@ -78,6 +81,36 @@ public class HighPriorityProvider { || hasHighPriorityChild(entry); } + /** + * @return true if the ListEntry is high priority conversation, else false + */ + public boolean isHighPriorityConversation(@NonNull ListEntry entry) { + final NotificationEntry notifEntry = entry.getRepresentativeEntry(); + if (notifEntry == null) { + return false; + } + + if (!isPeopleNotification(notifEntry)) { + return false; + } + + if (notifEntry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_DEFAULT) { + return true; + } + + return isNotificationEntryWithAtLeastOneImportantChild(entry); + } + + private boolean isNotificationEntryWithAtLeastOneImportantChild(@NonNull ListEntry entry) { + if (!(entry instanceof GroupEntry)) { + return false; + } + final GroupEntry groupEntry = (GroupEntry) entry; + return groupEntry.getChildren().stream().anyMatch( + childEntry -> + childEntry.getRanking().getImportance() + >= NotificationManager.IMPORTANCE_DEFAULT); + } private boolean hasHighPriorityChild(ListEntry entry) { if (entry instanceof NotificationEntry @@ -93,7 +126,6 @@ public class HighPriorityProvider { } } } - return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 8eef3f36433d..0ed41758f215 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -20,7 +20,6 @@ import android.service.notification.StatusBarNotification import com.android.systemui.ForegroundServiceNotificationListener import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.people.widget.PeopleSpaceWidgetManager import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption import com.android.systemui.statusbar.NotificationListener @@ -117,9 +116,7 @@ class NotificationsControllerImpl @Inject constructor( notificationLogger.setUpWithContainer(listContainer) peopleSpaceWidgetManager.attach(notificationListener) fgsNotifListener.init() - if (featureFlags.isEnabled(Flags.NOTIFICATION_MEMORY_MONITOR_ENABLED)) { - memoryMonitor.get().init() - } + memoryMonitor.get().init() } // TODO: Convert all functions below this line into listeners instead of public methods 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 ca762fc1ddc2..a48870ba9f45 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 @@ -630,6 +630,11 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter return false; } + if (notification.isUserInitiatedJob()) { + if (log) mLogger.logMaybeHeadsUpDespiteOldWhen(entry, when, age, "user initiated job"); + return false; + } + if (log) mLogger.logNoHeadsUpOldWhen(entry, when, age); final int uid = entry.getSbn().getUid(); final String packageName = entry.getSbn().getPackageName(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapper.kt new file mode 100644 index 000000000000..f2216fce6fef --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapper.kt @@ -0,0 +1,75 @@ +/* + * 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.notification.interruption + +import com.android.internal.annotations.VisibleForTesting +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider.Decision +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider.FullScreenIntentDecision + +/** + * Wraps a [NotificationInterruptStateProvider] to convert it to the new + * [VisualInterruptionDecisionProvider] interface. + */ +@SysUISingleton +class NotificationInterruptStateProviderWrapper( + private val wrapped: NotificationInterruptStateProvider +) : VisualInterruptionDecisionProvider { + + @VisibleForTesting + enum class DecisionImpl(override val shouldInterrupt: Boolean) : Decision { + SHOULD_INTERRUPT(shouldInterrupt = true), + SHOULD_NOT_INTERRUPT(shouldInterrupt = false); + + companion object { + fun of(booleanDecision: Boolean) = + if (booleanDecision) SHOULD_INTERRUPT else SHOULD_NOT_INTERRUPT + } + } + + @VisibleForTesting + class FullScreenIntentDecisionImpl( + val originalEntry: NotificationEntry, + val originalDecision: NotificationInterruptStateProvider.FullScreenIntentDecision + ) : FullScreenIntentDecision { + override val shouldInterrupt = originalDecision.shouldLaunch + override val wouldInterruptWithoutDnd = originalDecision == NO_FSI_SUPPRESSED_ONLY_BY_DND + } + + override fun addSuppressor(suppressor: NotificationInterruptSuppressor) { + wrapped.addSuppressor(suppressor) + } + + override fun makeUnloggedHeadsUpDecision(entry: NotificationEntry): Decision = + wrapped.checkHeadsUp(entry, /* log= */ false).let { DecisionImpl.of(it) } + + override fun makeAndLogHeadsUpDecision(entry: NotificationEntry): Decision = + wrapped.checkHeadsUp(entry, /* log= */ true).let { DecisionImpl.of(it) } + + override fun makeUnloggedFullScreenIntentDecision(entry: NotificationEntry) = + wrapped.getFullScreenIntentDecision(entry).let { FullScreenIntentDecisionImpl(entry, it) } + + override fun logFullScreenIntentDecision(decision: FullScreenIntentDecision) { + (decision as FullScreenIntentDecisionImpl).let { + wrapped.logFullScreenIntentDecision(it.originalEntry, it.originalDecision) + } + } + + override fun makeAndLogBubbleDecision(entry: NotificationEntry): Decision = + wrapped.shouldBubbleUp(entry).let { DecisionImpl.of(it) } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt new file mode 100644 index 000000000000..c0f4fcda56bb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt @@ -0,0 +1,112 @@ +/* + * 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.notification.interruption + +import com.android.systemui.statusbar.notification.collection.NotificationEntry + +/** + * Decides whether a notification should visually interrupt the user in various ways. + * + * These include displaying the notification as heads-up (peeking while the device is awake or + * pulsing while the device is dozing), displaying the notification as a bubble, and launching a + * full-screen intent for the notification. + */ +interface VisualInterruptionDecisionProvider { + /** + * Represents the decision to visually interrupt or not. + * + * Used for heads-up and bubble decisions; subclassed by [FullScreenIntentDecision] for + * full-screen intent decisions. + * + * @property[shouldInterrupt] whether a visual interruption should be triggered + */ + interface Decision { + val shouldInterrupt: Boolean + } + + /** + * Represents the decision to launch a full-screen intent for a notification or not. + * + * @property[wouldInterruptWithoutDnd] whether a full-screen intent should not be launched only + * because Do Not Disturb has suppressed it + */ + interface FullScreenIntentDecision : Decision { + val wouldInterruptWithoutDnd: Boolean + } + + /** + * Adds a [component][suppressor] that can suppress visual interruptions. + * + * This class may call suppressors in any order. + * + * @param[suppressor] the suppressor to add + */ + fun addSuppressor(suppressor: NotificationInterruptSuppressor) + + /** + * Decides whether a [notification][entry] should display as heads-up or not, but does not log + * that decision. + * + * @param[entry] the notification that this decision is about + * @return the decision to display that notification as heads-up or not + */ + fun makeUnloggedHeadsUpDecision(entry: NotificationEntry): Decision + + /** + * Decides whether a [notification][entry] should display as heads-up or not, and logs that + * decision. + * + * If the device is awake, the decision will consider whether the notification should "peek" + * (slide in from the top of the screen over the current activity). + * + * If the device is dozing, the decision will consider whether the notification should "pulse" + * (wake the screen up and display the ambient view of the notification). + * + * @see[makeUnloggedHeadsUpDecision] + * + * @param[entry] the notification that this decision is about + * @return the decision to display that notification as heads-up or not + */ + fun makeAndLogHeadsUpDecision(entry: NotificationEntry): Decision + + /** + * Decides whether a [notification][entry] should launch a full-screen intent or not, but does + * not log that decision. + * + * The returned decision can be logged by passing it to [logFullScreenIntentDecision]. + * + * @see[makeAndLogHeadsUpDecision] + * + * @param[entry] the notification that this decision is about + * @return the decision to launch a full-screen intent for that notification or not + */ + fun makeUnloggedFullScreenIntentDecision(entry: NotificationEntry): FullScreenIntentDecision + + /** + * Logs a previous [decision] to launch a full-screen intent or not. + * + * @param[decision] the decision to log + */ + fun logFullScreenIntentDecision(decision: FullScreenIntentDecision) + + /** + * Decides whether a [notification][entry] should display as a bubble or not. + * + * @param[entry] the notification that this decision is about + * @return the decision to display that notification as a bubble or not + */ + fun makeAndLogBubbleDecision(entry: NotificationEntry): Decision +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index a9d125508397..950ab5d2f5ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -299,6 +299,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView */ private boolean mShowGroupBackgroundWhenExpanded; + /** + * True if we always show the collapsed layout on lockscreen because vertical space is low. + */ + private boolean mSaveSpaceOnLockscreen; + + /** + * True if we use intrinsic height regardless of vertical space available on lockscreen. + */ + private boolean mIgnoreLockscreenConstraints; + private OnClickListener mExpandClickListener = new OnClickListener() { @Override public void onClick(View v) { @@ -394,6 +404,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mGroupExpansionChanging; } + public void setSaveSpaceOnLockscreen(boolean saveSpace) { + mSaveSpaceOnLockscreen = saveSpace; + } + + public boolean getSaveSpaceOnLockscreen() { + return mSaveSpaceOnLockscreen; + } + public void setGroupExpansionChanging(boolean changing) { mGroupExpansionChanging = changing; } @@ -419,15 +437,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView */ public void setAnimationRunning(boolean running) { // Sets animations running in the private/public layouts. - if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ANIMATE_BIG_PICTURE)) { - for (NotificationContentView l : mLayouts) { - if (l != null) { - l.setContentAnimationRunning(running); - setIconAnimationRunning(running, l); - } - } - } else { - for (NotificationContentView l : mLayouts) { + for (NotificationContentView l : mLayouts) { + if (l != null) { + l.setContentAnimationRunning(running); setIconAnimationRunning(running, l); } } @@ -2553,11 +2565,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } @Override + public int getHeightWithoutLockscreenConstraints() { + mIgnoreLockscreenConstraints = true; + final int height = getIntrinsicHeight(); + mIgnoreLockscreenConstraints = false; + return height; + } + + @Override public int getIntrinsicHeight() { if (isUserLocked()) { return getActualHeight(); - } - if (mGuts != null && mGuts.isExposed()) { + } else if (mGuts != null && mGuts.isExposed()) { return mGuts.getIntrinsicHeight(); } else if ((isChildInGroup() && !isGroupExpanded())) { return mPrivateLayout.getMinHeight(); @@ -2579,13 +2598,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return getCollapsedHeight(); } } - /** * @return {@code true} if the notification can show it's heads up layout. This is mostly true * except for legacy use cases. */ public boolean canShowHeadsUp() { - if (mOnKeyguard && !isDozing() && !isBypassEnabled() && !mEntry.isStickyAndNotDemoted()) { + if (mOnKeyguard && !isDozing() && !isBypassEnabled() && + (!mEntry.isStickyAndNotDemoted() + || (!mIgnoreLockscreenConstraints && mSaveSpaceOnLockscreen))) { return false; } return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index 9df6ba9910cc..5edff5f4e5d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -291,6 +291,11 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro long duration) { } + public int getHeightWithoutLockscreenConstraints() { + // ExpandableNotificationRow overrides this. + return getHeight(); + } + /** * @return The desired notification height. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java index af8d6ec727d1..98cd84dde199 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java @@ -16,8 +16,8 @@ package com.android.systemui.statusbar.notification.row.dagger; +import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl; import com.android.systemui.statusbar.NotificationShelf; -import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import dagger.Binds; @@ -46,7 +46,8 @@ public interface NotificationShelfComponent { * Creates a NotificationShelfController. */ @NotificationRowScope - NotificationShelfController getNotificationShelfController(); + LegacyNotificationShelfControllerImpl getNotificationShelfController(); + /** * Dagger Module that extracts interesting properties from a NotificationShelf. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt new file mode 100644 index 000000000000..8ba65f7a1418 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt @@ -0,0 +1,48 @@ +/* + * 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.notification.shelf.domain.interactor + +import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository +import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.statusbar.NotificationShelf +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine + +/** Interactor for the [NotificationShelf] */ +@CentralSurfacesComponent.CentralSurfacesScope +class NotificationShelfInteractor +@Inject +constructor( + private val keyguardRepository: KeyguardRepository, + private val deviceEntryFaceAuthRepository: DeviceEntryFaceAuthRepository, +) { + /** Is the shelf showing on the keyguard? */ + val isShowingOnKeyguard: Flow<Boolean> + get() = keyguardRepository.isKeyguardShowing + + /** Is the system in a state where the shelf is just a static display of notification icons? */ + val isShelfStatic: Flow<Boolean> + get() = + combine( + keyguardRepository.isKeyguardShowing, + deviceEntryFaceAuthRepository.isBypassEnabled, + ) { isKeyguardShowing, isBypassEnabled -> + isKeyguardShowing && isBypassEnabled + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt new file mode 100644 index 000000000000..b190cf658fa8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt @@ -0,0 +1,135 @@ +/* + * 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.notification.shelf.ui.viewbinder + +import android.view.View +import android.view.accessibility.AccessibilityManager +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl +import com.android.systemui.statusbar.NotificationShelf +import com.android.systemui.statusbar.NotificationShelfController +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView +import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController +import com.android.systemui.statusbar.notification.row.ExpandableOutlineViewController +import com.android.systemui.statusbar.notification.row.ExpandableViewController +import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel +import com.android.systemui.statusbar.notification.stack.AmbientState +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.phone.NotificationIconContainer +import com.android.systemui.statusbar.phone.NotificationTapHelper +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope +import com.android.systemui.util.kotlin.getValue +import dagger.Lazy +import javax.inject.Inject +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +/** + * Controller class for [NotificationShelf]. This implementation serves as a temporary wrapper + * around a [NotificationShelfViewBinder], so that external code can continue to depend on the + * [NotificationShelfController] interface. Once the [LegacyNotificationShelfControllerImpl] is + * removed, this class can go away and the ViewBinder can be used directly. + */ +@CentralSurfacesScope +class NotificationShelfViewBinderWrapperControllerImpl +@Inject +constructor( + private val shelf: NotificationShelf, + private val viewModel: NotificationShelfViewModel, + featureFlags: FeatureFlags, + private val notifTapHelperFactory: NotificationTapHelper.Factory, + private val a11yManager: AccessibilityManager, + private val falsingManager: FalsingManager, + private val falsingCollector: FalsingCollector, + hostControllerLazy: Lazy<NotificationStackScrollLayoutController>, +) : NotificationShelfController { + + private val hostController: NotificationStackScrollLayoutController by hostControllerLazy + + override val view: NotificationShelf + get() = unsupported + + init { + shelf.apply { + setRefactorFlagEnabled(featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) + useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)) + setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM)) + } + } + + fun init() { + NotificationShelfViewBinder.bind(viewModel, shelf) + + ActivatableNotificationViewController( + shelf, + notifTapHelperFactory, + ExpandableOutlineViewController(shelf, ExpandableViewController(shelf)), + a11yManager, + falsingManager, + falsingCollector, + ) + .init() + hostController.setShelf(shelf) + hostController.setOnNotificationRemovedListener { child, _ -> + view.requestRoundnessResetFor(child) + } + } + + override val intrinsicHeight: Int + get() = shelf.intrinsicHeight + + override val shelfIcons: NotificationIconContainer + get() = shelf.shelfIcons + + override fun canModifyColorOfNotifications(): Boolean = unsupported + + override fun setOnActivatedListener(listener: ActivatableNotificationView.OnActivatedListener) { + shelf.setOnActivatedListener(listener) + } + + override fun bind( + ambientState: AmbientState, + notificationStackScrollLayoutController: NotificationStackScrollLayoutController, + ) = unsupported + + override fun setOnClickListener(listener: View.OnClickListener) { + shelf.setOnClickListener(listener) + } + + private val unsupported: Nothing + get() = NotificationShelfController.throwIllegalFlagStateError(expected = true) +} + +/** Binds a [NotificationShelf] to its backend. */ +object NotificationShelfViewBinder { + fun bind(viewModel: NotificationShelfViewModel, shelf: NotificationShelf) { + shelf.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.canModifyColorOfNotifications + .onEach(shelf::setCanModifyColorOfNotifications) + .launchIn(this) + viewModel.isClickable.onEach(shelf::setCanInteract).launchIn(this) + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt new file mode 100644 index 000000000000..5e297c89dd2f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt @@ -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.systemui.statusbar.notification.shelf.ui.viewmodel + +import com.android.systemui.statusbar.NotificationShelf +import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor +import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +/** ViewModel for [NotificationShelf]. */ +@CentralSurfacesScope +class NotificationShelfViewModel +@Inject +constructor( + private val interactor: NotificationShelfInteractor, +) { + /** Is the shelf allowed to be clickable when it has content? */ + val isClickable: Flow<Boolean> + get() = interactor.isShowingOnKeyguard + + /** Is the shelf allowed to modify the color of notifications in the host layout? */ + val canModifyColorOfNotifications: Flow<Boolean> + get() = interactor.isShelfStatic.map { static -> !static } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java index 112d48c115c2..00b9aa42ab26 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java @@ -32,6 +32,7 @@ public class AnimationProperties { public long duration; public long delay; private ArrayMap<Property, Interpolator> mInterpolatorMap; + private Consumer<Property> mAnimationCancelAction; private Consumer<Property> mAnimationEndAction; /** @@ -50,27 +51,43 @@ public class AnimationProperties { * @return a listener that will be added for a given property during its animation. */ public AnimatorListenerAdapter getAnimationFinishListener(Property property) { - if (mAnimationEndAction == null) { + if (mAnimationEndAction == null && mAnimationCancelAction == null) { return null; } + Consumer<Property> cancelAction = mAnimationCancelAction; Consumer<Property> endAction = mAnimationEndAction; return new AnimatorListenerAdapter() { private boolean mCancelled; @Override public void onAnimationCancel(Animator animation) { - mCancelled = true; + mCancelled = true; + if (cancelAction != null) { + cancelAction.accept(property); + } } @Override public void onAnimationEnd(Animator animation) { - if (!mCancelled) { + if (!mCancelled && endAction != null) { endAction.accept(property); } } }; } + /** + * Add a callback for animation cancellation. + */ + public AnimationProperties setAnimationCancelAction(Consumer<Property> listener) { + mAnimationCancelAction = listener; + return this; + } + + /** + * Add a callback for animation ending successfully. The callback will not be called when the + * animations is cancelled. + */ public AnimationProperties setAnimationEndAction(Consumer<Property> listener) { mAnimationEndAction = listener; 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 e47e4146d4c0..af608a7f3a64 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 @@ -5137,8 +5137,26 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable requestChildrenUpdate(); } + public void setShelf(NotificationShelf shelf) { + if (!NotificationShelfController.checkRefactorFlagEnabled( + mAmbientState.getFeatureFlags())) { + return; + } + int index = -1; + if (mShelf != null) { + index = indexOfChild(mShelf); + removeView(mShelf); + } + mShelf = shelf; + addView(mShelf, index); + mAmbientState.setShelf(mShelf); + mStateAnimator.setShelf(mShelf); + shelf.bind(mAmbientState, this, mController.getNotificationRoundnessManager()); + } + @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void setShelfController(NotificationShelfController notificationShelfController) { + NotificationShelfController.assertRefactorFlagDisabled(mAmbientState.getFeatureFlags()); int index = -1; if (mShelf != null) { index = indexOfChild(mShelf); 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 792746c60134..1c8727f1b092 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 @@ -73,6 +73,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; @@ -1382,6 +1383,7 @@ public class NotificationStackScrollLayoutController { } public void setShelfController(NotificationShelfController notificationShelfController) { + NotificationShelfController.assertRefactorFlagDisabled(mFeatureFlags); mView.setShelfController(notificationShelfController); } @@ -1593,6 +1595,11 @@ public class NotificationStackScrollLayoutController { mView.setOnNotificationRemovedListener(listener); } + public void setShelf(NotificationShelf shelf) { + if (!NotificationShelfController.checkRefactorFlagEnabled(mFeatureFlags)) return; + mView.setShelf(shelf); + } + /** * Enum for UiEvent logged from this class */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt index 092242814869..c7cb70c1da05 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt @@ -23,12 +23,14 @@ import androidx.annotation.VisibleForTesting import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.statusbar.LockscreenShadeTransitionController import com.android.systemui.statusbar.StatusBarState.KEYGUARD import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView import com.android.systemui.util.Compile +import com.android.systemui.util.LargeScreenUtils.shouldUseSplitNotificationShade import com.android.systemui.util.children import java.io.PrintWriter import javax.inject.Inject @@ -51,11 +53,10 @@ class NotificationStackSizeCalculator constructor( private val statusBarStateController: SysuiStatusBarStateController, private val lockscreenShadeTransitionController: LockscreenShadeTransitionController, + private val mediaDataManager: MediaDataManager, @Main private val resources: Resources ) { - private lateinit var lastComputeHeightLog : String - /** * Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow shelf. * If there are exactly 1 + mMaxKeyguardNotifications, and they fit in the available space @@ -67,67 +68,157 @@ constructor( /** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */ private var dividerHeight by notNull<Float>() + /** + * True when there is not enough vertical space to show at least one notification with heads up + * layout. When true, notifications always show collapsed layout. + */ + private var saveSpaceOnLockscreen = false + init { updateResources() } /** * Returns whether notifications and (shelf if visible) can fit in total space available. - * [spaceForShelf] is extra vertical space allowed for the shelf to overlap the lock icon. + * [shelfSpace] is extra vertical space allowed for the shelf to overlap the lock icon. */ private fun canStackFitInSpace( stackHeight: StackHeight, - spaceForNotifications: Float, - spaceForShelf: Float, - ): Boolean { - - val (notificationsHeight, shelfHeightWithSpaceBefore) = stackHeight - var canFit: Boolean + notifSpace: Float, + shelfSpace: Float, + ): FitResult { + val (notifHeight, notifHeightSaveSpace, shelfHeightWithSpaceBefore) = stackHeight if (shelfHeightWithSpaceBefore == 0f) { - canFit = notificationsHeight <= spaceForNotifications + if (notifHeight <= notifSpace) { + log { + "\tcanStackFitInSpace[FIT] = notifHeight[$notifHeight]" + + " <= notifSpace[$notifSpace]" + } + return FitResult.FIT + } + if (notifHeightSaveSpace <= notifSpace) { + log { + "\tcanStackFitInSpace[FIT_IF_SAVE_SPACE]" + + " = notifHeightSaveSpace[$notifHeightSaveSpace]" + + " <= notifSpace[$notifSpace]" + } + return FitResult.FIT_IF_SAVE_SPACE + } log { - "canStackFitInSpace[$canFit] = notificationsHeight[$notificationsHeight]" + - " <= spaceForNotifications[$spaceForNotifications]" + "\tcanStackFitInSpace[NO_FIT]" + + " = notifHeightSaveSpace[$notifHeightSaveSpace] > notifSpace[$notifSpace]" } + return FitResult.NO_FIT } else { - canFit = - (notificationsHeight + shelfHeightWithSpaceBefore) <= - (spaceForNotifications + spaceForShelf) - log { - "canStackFitInSpace[$canFit] = (notificationsHeight[$notificationsHeight]" + - " + shelfHeightWithSpaceBefore[$shelfHeightWithSpaceBefore])" + - " <= (spaceForNotifications[$spaceForNotifications] " + - " + spaceForShelf[$spaceForShelf])" + if ((notifHeight + shelfHeightWithSpaceBefore) <= (notifSpace + shelfSpace)) { + log { + "\tcanStackFitInSpace[FIT] = (notifHeight[$notifHeight]" + + " + shelfHeightWithSpaceBefore[$shelfHeightWithSpaceBefore])" + + " <= (notifSpace[$notifSpace] " + + " + spaceForShelf[$shelfSpace])" + } + return FitResult.FIT + } else if ( + (notifHeightSaveSpace + shelfHeightWithSpaceBefore) <= (notifSpace + shelfSpace) + ) { + log { + "\tcanStackFitInSpace[FIT_IF_SAVE_SPACE]" + + " = (notifHeightSaveSpace[$notifHeightSaveSpace]" + + " + shelfHeightWithSpaceBefore[$shelfHeightWithSpaceBefore])" + + " <= (notifSpace[$notifSpace] + shelfSpace[$shelfSpace])" + } + return FitResult.FIT_IF_SAVE_SPACE + } else { + log { + "\tcanStackFitInSpace[NO_FIT]" + + " = (notifHeightSaveSpace[$notifHeightSaveSpace]" + + " + shelfHeightWithSpaceBefore[$shelfHeightWithSpaceBefore])" + + " > (notifSpace[$notifSpace] + shelfSpace[$shelfSpace])" + } + return FitResult.NO_FIT } } - return canFit } /** - * Given the [spaceForNotifications] and [spaceForShelf] constraints, calculate how many - * notifications to show. This number is only valid in keyguard. + * Given the [notifSpace] and [shelfSpace] constraints, calculate how many notifications to + * show. This number is only valid in keyguard. * * @param totalAvailableSpace space for notifications. This includes the space for the shelf. */ fun computeMaxKeyguardNotifications( stack: NotificationStackScrollLayout, - spaceForNotifications: Float, - spaceForShelf: Float, - shelfIntrinsicHeight: Float + notifSpace: Float, + shelfSpace: Float, + shelfHeight: Float, ): Int { + log { "\n " } + log { + "computeMaxKeyguardNotifications ---" + + "\n\tnotifSpace $notifSpace" + + "\n\tspaceForShelf $shelfSpace" + + "\n\tshelfIntrinsicHeight $shelfHeight" + } + if (notifSpace + shelfSpace <= 0f) { + log { "--- No space to show anything. maxNotifs=0" } + return 0 + } log { "\n" } - val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight, - /* computeHeight= */ false) + val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfHeight) + val isMediaShowing = mediaDataManager.hasActiveMediaOrRecommendation() - var maxNotifications = + log { "\tGet maxNotifWithoutSavingSpace ---" } + val maxNotifWithoutSavingSpace = stackHeightSequence.lastIndexWhile { heightResult -> canStackFitInSpace( heightResult, - spaceForNotifications = spaceForNotifications, - spaceForShelf = spaceForShelf) + notifSpace = notifSpace, + shelfSpace = shelfSpace + ) == FitResult.FIT + } + + // How many notifications we can show at heightWithoutLockscreenConstraints + var minCountAtHeightWithoutConstraints = + if (isMediaShowing && !shouldUseSplitNotificationShade(resources)) 2 else 1 + log { + "\t---maxNotifWithoutSavingSpace=$maxNotifWithoutSavingSpace " + + "isMediaShowing=$isMediaShowing" + + "minCountAtHeightWithoutConstraints=$minCountAtHeightWithoutConstraints" + } + log { "\n" } + + var maxNotifications: Int + if (maxNotifWithoutSavingSpace >= minCountAtHeightWithoutConstraints) { + saveSpaceOnLockscreen = false + maxNotifications = maxNotifWithoutSavingSpace + log { + "\tDo NOT save space. maxNotifications=maxNotifWithoutSavingSpace=$maxNotifications" + } + } else { + log { "\tSAVE space ---" } + saveSpaceOnLockscreen = true + maxNotifications = + stackHeightSequence.lastIndexWhile { heightResult -> + canStackFitInSpace( + heightResult, + notifSpace = notifSpace, + shelfSpace = shelfSpace + ) != FitResult.NO_FIT + } + log { "\t--- maxNotifications=$maxNotifications" } + } + + // Must update views immediately to avoid mismatches between initial HUN layout height + // and the height adapted to lockscreen space constraints, which causes jump cuts. + stack.showableChildren().toList().forEach { currentNotification -> + run { + if (currentNotification is ExpandableNotificationRow) { + currentNotification.saveSpaceOnLockscreen = saveSpaceOnLockscreen + } } + } if (onLockscreen()) { maxNotifications = min(maxKeyguardNotifications, maxNotifications) @@ -137,53 +228,80 @@ constructor( maxNotifications = max(0, maxNotifications) log { val sequence = if (SPEW) " stackHeightSequence=${stackHeightSequence.toList()}" else "" - "computeMaxKeyguardNotifications(" + - " spaceForNotifications=$spaceForNotifications" + - " spaceForShelf=$spaceForShelf" + - " shelfHeight=$shelfIntrinsicHeight) -> $maxNotifications$sequence" + "--- computeMaxKeyguardNotifications(" + + " notifSpace=$notifSpace" + + " shelfSpace=$shelfSpace" + + " shelfHeight=$shelfHeight) -> $maxNotifications$sequence" } + log { "\n" } return maxNotifications } /** - * Given the [maxNotifications] constraint, calculates the height of the + * Given the [maxNotifs] constraint, calculates the height of the * [NotificationStackScrollLayout]. This might or might not be in keyguard. * * @param stack stack containing notifications as children. - * @param maxNotifications Maximum number of notifications. When reached, the others will go - * into the shelf. - * @param shelfIntrinsicHeight height of the shelf, without any padding. It might be zero. - * + * @param maxNotifs Maximum number of notifications. When reached, the others will go into the + * shelf. + * @param shelfHeight height of the shelf, without any padding. It might be zero. * @return height of the stack, including shelf height, if needed. */ fun computeHeight( stack: NotificationStackScrollLayout, - maxNotifications: Int, - shelfIntrinsicHeight: Float + maxNotifs: Int, + shelfHeight: Float ): Float { log { "\n" } - lastComputeHeightLog = "" - val heightPerMaxNotifications = - computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight, - /* computeHeight= */ true) - - val (notificationsHeight, shelfHeightWithSpaceBefore) = - heightPerMaxNotifications.elementAtOrElse(maxNotifications) { - heightPerMaxNotifications.last() // Height with all notifications visible. + log { "computeHeight ---" } + + val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfHeight) + + val (notifsHeight, notifsHeightSavingSpace, shelfHeightWithSpaceBefore) = + stackHeightSequence.elementAtOrElse(maxNotifs) { + stackHeightSequence.last() // Height with all notifications visible. + } + + var height: Float + if (saveSpaceOnLockscreen) { + height = notifsHeightSavingSpace + shelfHeightWithSpaceBefore + log { + "--- computeHeight(maxNotifs=$maxNotifs, shelfHeight=$shelfHeight)" + + " -> $height=($notifsHeightSavingSpace+$shelfHeightWithSpaceBefore)," + + " | saveSpaceOnLockscreen=$saveSpaceOnLockscreen" + } + } else { + height = notifsHeight + shelfHeightWithSpaceBefore + log { + "--- computeHeight(maxNotifs=$maxNotifs, shelfHeight=$shelfHeight)" + + " -> ${height}=($notifsHeight+$shelfHeightWithSpaceBefore)" + + " | saveSpaceOnLockscreen=$saveSpaceOnLockscreen" } - lastComputeHeightLog += "\ncomputeHeight(maxNotifications=$maxNotifications," + - "shelfIntrinsicHeight=$shelfIntrinsicHeight) -> " + - "${notificationsHeight + shelfHeightWithSpaceBefore}" + - " = ($notificationsHeight + $shelfHeightWithSpaceBefore)" - log { - lastComputeHeightLog } - return notificationsHeight + shelfHeightWithSpaceBefore + return height } + private enum class FitResult { + FIT, + FIT_IF_SAVE_SPACE, + NO_FIT + } + + data class SpaceNeeded( + // Float height of spaceNeeded when showing heads up layout for FSI HUNs. + val whenEnoughSpace: Float, + + // Float height of space needed when showing collapsed layout for FSI HUNs. + val whenSavingSpace: Float + ) + private data class StackHeight( // Float height with ith max notifications (not including shelf) - val notificationsHeight: Float, + val notifsHeight: Float, + + // Float height with ith max notifications + // (not including shelf, using collapsed layout for FSI HUN) + val notifsHeightSavingSpace: Float, // Float height of shelf (0 if shelf is not showing), and space before the shelf that // changes during the lockscreen <=> full shade transition. @@ -193,20 +311,27 @@ constructor( private fun computeHeightPerNotificationLimit( stack: NotificationStackScrollLayout, shelfHeight: Float, - computeHeight: Boolean ): Sequence<StackHeight> = sequence { - log { "computeHeightPerNotificationLimit" } - val children = stack.showableChildren().toList() var notifications = 0f + var notifsWithCollapsedHun = 0f var previous: ExpandableView? = null val onLockscreen = onLockscreen() // Only shelf. This should never happen, since we allow 1 view minimum (EmptyViewState). - yield(StackHeight(notificationsHeight = 0f, shelfHeightWithSpaceBefore = shelfHeight)) + yield( + StackHeight( + notifsHeight = 0f, + notifsHeightSavingSpace = 0f, + shelfHeightWithSpaceBefore = shelfHeight + ) + ) children.forEachIndexed { i, currentNotification -> - notifications += spaceNeeded(currentNotification, i, previous, stack, onLockscreen) + val space = getSpaceNeeded(currentNotification, i, previous, stack, onLockscreen) + notifications += space.whenEnoughSpace + notifsWithCollapsedHun += space.whenSavingSpace + previous = currentNotification val shelfWithSpaceBefore = @@ -219,22 +344,23 @@ constructor( stack, previous = currentNotification, current = children[firstViewInShelfIndex], - currentIndex = firstViewInShelfIndex) + currentIndex = firstViewInShelfIndex + ) spaceBeforeShelf + shelfHeight } - val currentLog = "computeHeight | i=$i notificationsHeight=$notifications " + - "shelfHeightWithSpaceBefore=$shelfWithSpaceBefore" - if (computeHeight) { - lastComputeHeightLog += "\n" + currentLog - } log { - currentLog + "\tcomputeHeightPerNotificationLimit i=$i notifs=$notifications " + + "notifsHeightSavingSpace=$notifsWithCollapsedHun" + + " shelfWithSpaceBefore=$shelfWithSpaceBefore" } yield( StackHeight( - notificationsHeight = notifications, - shelfHeightWithSpaceBefore = shelfWithSpaceBefore)) + notifsHeight = notifications, + notifsHeightSavingSpace = notifsWithCollapsedHun, + shelfHeightWithSpaceBefore = shelfWithSpaceBefore + ) + ) } } @@ -256,32 +382,46 @@ constructor( } @VisibleForTesting - fun spaceNeeded( + fun getSpaceNeeded( view: ExpandableView, visibleIndex: Int, previousView: ExpandableView?, stack: NotificationStackScrollLayout, - onLockscreen: Boolean - ): Float { + onLockscreen: Boolean, + ): SpaceNeeded { assert(view.isShowable(onLockscreen)) + // Must use heightWithoutLockscreenConstraints because intrinsicHeight references + // mSaveSpaceOnLockscreen and using intrinsicHeight here will result in stack overflow. + val height = view.heightWithoutLockscreenConstraints.toFloat() + val gapAndDividerHeight = + calculateGapAndDividerHeight(stack, previousView, current = view, visibleIndex) + var size = if (onLockscreen) { if (view is ExpandableNotificationRow && view.entry.isStickyAndNotDemoted) { - view.intrinsicHeight.toFloat() + height } else { view.getMinHeight(/* ignoreTemporaryStates= */ true).toFloat() } } else { - view.intrinsicHeight.toFloat() + height + } + size += gapAndDividerHeight + + var sizeWhenSavingSpace = + if (onLockscreen) { + view.getMinHeight(/* ignoreTemporaryStates= */ true).toFloat() + } else { + height } + sizeWhenSavingSpace += gapAndDividerHeight - size += calculateGapAndDividerHeight(stack, previousView, current = view, visibleIndex) - return size + return SpaceNeeded(size, sizeWhenSavingSpace) } fun dump(pw: PrintWriter, args: Array<out String>) { - pw.println("NotificationStackSizeCalculator lastComputeHeightLog = $lastComputeHeightLog") + pw.println("NotificationStackSizeCalculator saveSpaceOnLockscreen=$saveSpaceOnLockscreen") } private fun ExpandableView.isShowable(onLockscreen: Boolean): Boolean { 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 0195d4532ae0..3a1272fa32e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -326,6 +326,13 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn @Nullable ActivityLaunchAnimator.Controller animationController, UserHandle userHandle); + /** Starts an activity intent that dismisses keyguard. */ + void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned, + boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching, + Callback callback, int flags, + @Nullable ActivityLaunchAnimator.Controller animationController, + UserHandle userHandle, @Nullable String customMessage); + void readyForKeyguardDone(); void executeRunnableDismissingKeyguard(Runnable runnable, @@ -339,7 +346,8 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn boolean dismissShade, boolean afterKeyguardGone, boolean deferred, - boolean willAnimateOnKeyguard); + boolean willAnimateOnKeyguard, + @Nullable String customMessage); void resetUserExpandedStates(); 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 0c8e9e56b04a..0960efb7388f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -192,6 +192,7 @@ import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeExpansionChangeEvent; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shade.ShadeLogger; import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.CircleReveal; @@ -505,6 +506,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { /** Controller for the Shade. */ @VisibleForTesting NotificationPanelViewController mNotificationPanelViewController; + private final ShadeLogger mShadeLogger; // settings private QSPanelController mQSPanelController; @@ -738,6 +740,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { KeyguardViewMediator keyguardViewMediator, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, + ShadeLogger shadeLogger, @UiBackground Executor uiBgExecutor, NotificationMediaManager notificationMediaManager, NotificationLockscreenUserManager lockScreenUserManager, @@ -830,6 +833,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mKeyguardViewMediator = keyguardViewMediator; mDisplayMetrics = displayMetrics; mMetricsLogger = metricsLogger; + mShadeLogger = shadeLogger; mUiBgExecutor = uiBgExecutor; mMediaManager = notificationMediaManager; mLockscreenUserManager = lockScreenUserManager; @@ -2410,11 +2414,22 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } @Override + public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned, + boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching, + Callback callback, int flags, + @androidx.annotation.Nullable ActivityLaunchAnimator.Controller animationController, + UserHandle userHandle) { + startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, + disallowEnterPictureInPictureWhileLaunching, callback, flags, animationController, + userHandle, null /* customMessage */); + } + + @Override public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching, final Callback callback, int flags, @Nullable ActivityLaunchAnimator.Controller animationController, - final UserHandle userHandle) { + final UserHandle userHandle, @Nullable String customMessage) { if (onlyProvisioned && !mDeviceProvisionedController.isDeviceProvisioned()) return; final boolean willLaunchResolverActivity = @@ -2501,7 +2516,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { && mKeyguardStateController.isOccluded(); boolean deferred = !occluded; executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShadeDirectly, - willLaunchResolverActivity, deferred /* deferred */, animate); + willLaunchResolverActivity, deferred /* deferred */, animate, + customMessage /* customMessage */); } /** @@ -2554,7 +2570,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { final boolean afterKeyguardGone, final boolean deferred) { executeRunnableDismissingKeyguard(runnable, cancelAction, dismissShade, afterKeyguardGone, - deferred, false /* willAnimateOnKeyguard */); + deferred, false /* willAnimateOnKeyguard */, null /* customMessage */); } @Override @@ -2563,7 +2579,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { final boolean dismissShade, final boolean afterKeyguardGone, final boolean deferred, - final boolean willAnimateOnKeyguard) { + final boolean willAnimateOnKeyguard, + @Nullable String customMessage) { OnDismissAction onDismissAction = new OnDismissAction() { @Override public boolean onDismiss() { @@ -2592,7 +2609,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { return willAnimateOnKeyguard; } }; - dismissKeyguardThenExecute(onDismissAction, cancelAction, afterKeyguardGone); + dismissKeyguardThenExecute(onDismissAction, cancelAction, afterKeyguardGone, customMessage); } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -2610,6 +2627,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } mRemoteInputManager.closeRemoteInputs(); if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) { + mShadeLogger.d("ACTION_CLOSE_SYSTEM_DIALOGS intent: closing shade"); int flags = CommandQueue.FLAG_EXCLUDE_NONE; if (reason != null) { if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { @@ -2624,6 +2642,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } } mShadeController.animateCollapseShade(flags); + } else { + mShadeLogger.d("ACTION_CLOSE_SYSTEM_DIALOGS intent: non-matching user ID"); } } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { if (mNotificationShadeWindowController != null) { @@ -2670,6 +2690,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone) { + dismissKeyguardThenExecute(action, cancelAction, afterKeyguardGone, null); + } + + @Override + public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, + boolean afterKeyguardGone, String customMessage) { if (!action.willRunAnimationOnKeyguard() && mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP && mKeyguardStateController.canDismissLockScreen() @@ -2682,7 +2708,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } if (mKeyguardStateController.isShowing()) { mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, - afterKeyguardGone); + afterKeyguardGone, customMessage); } else { // If the keyguard isn't showing but the device is dreaming, we should exit the dream. if (mKeyguardUpdateMonitor.isDreaming()) { @@ -2690,7 +2716,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } action.onDismiss(); } + } + /** * Notify the shade controller that the current user changed * @@ -2895,6 +2923,14 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void postStartActivityDismissingKeyguard(Intent intent, int delay, @Nullable ActivityLaunchAnimator.Controller animationController) { + postStartActivityDismissingKeyguard(intent, delay, animationController, + null /* customMessage */); + } + + @Override + public void postStartActivityDismissingKeyguard(Intent intent, int delay, + @Nullable ActivityLaunchAnimator.Controller animationController, + @Nullable String customMessage) { mMainExecutor.executeDelayed( () -> startActivityDismissingKeyguard(intent, true /* onlyProvisioned */, @@ -2903,7 +2939,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { null /* callback */, 0 /* flags */, animationController, - getActivityUserHandle(intent)), + getActivityUserHandle(intent), customMessage), delay); } @@ -3672,6 +3708,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { boolean disabled = (!mDeviceInteractive && !mDozeServiceHost.isPulsing()) || goingToSleepWithoutAnimation || mDeviceProvisionedController.isFrpActive(); + mShadeLogger.logUpdateNotificationPanelTouchState(disabled, isGoingToSleep(), + !mDozeParameters.shouldControlScreenOff(), !mDeviceInteractive, + !mDozeServiceHost.isPulsing(), mDeviceProvisionedController.isFrpActive()); + mNotificationPanelViewController.setTouchAndAnimationDisabled(disabled); mNotificationIconAreaController.setAnimationsEnabled(!disabled); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt index e4227dce94e7..d433814d7ce4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt @@ -29,6 +29,7 @@ import com.android.systemui.R import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper @@ -57,7 +58,7 @@ constructor( } private var ambientIndicationArea: View? = null - private lateinit var binding: KeyguardBottomAreaViewBinder.Binding + private var binding: KeyguardBottomAreaViewBinder.Binding? = null private var lockIconViewController: LockIconViewController? = null /** Initializes the view. */ @@ -67,13 +68,16 @@ constructor( lockIconViewController: LockIconViewController? = null, messageDisplayer: MessageDisplayer? = null, vibratorHelper: VibratorHelper? = null, + activityStarter: ActivityStarter? = null, ) { + binding?.destroy() binding = bind( this, viewModel, falsingManager, vibratorHelper, + activityStarter, ) { messageDisplayer?.display(it) } @@ -114,12 +118,12 @@ constructor( override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - binding.onConfigurationChanged() + binding?.onConfigurationChanged() } /** Returns a list of animators to use to animate the indication areas. */ val indicationAreaAnimators: List<ViewPropertyAnimator> - get() = binding.getIndicationAreaAnimators() + get() = checkNotNull(binding).getIndicationAreaAnimators() override fun hasOverlappingRendering(): Boolean { return false @@ -139,7 +143,7 @@ constructor( super.onLayout(changed, left, top, right, bottom) findViewById<View>(R.id.ambient_indication_container)?.let { val (ambientLeft, ambientTop) = it.locationOnScreen - if (binding.shouldConstrainToTopOfLockIcon()) { + if (binding?.shouldConstrainToTopOfLockIcon() == true) { // make top of ambient indication view the bottom of the lock icon it.layout( ambientLeft, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt index 8ee2c6f2c399..74ab47ff27a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt @@ -29,6 +29,7 @@ import com.android.systemui.CoreStartable import com.android.systemui.Dumpable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.util.Assert import com.android.systemui.util.sensors.AsyncSensorManager @@ -46,6 +47,7 @@ class KeyguardLiftController @Inject constructor( private val statusBarStateController: StatusBarStateController, private val asyncSensorManager: AsyncSensorManager, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val keyguardFaceAuthInteractor: KeyguardFaceAuthInteractor, private val dumpManager: DumpManager ) : Dumpable, CoreStartable { @@ -72,6 +74,7 @@ class KeyguardLiftController @Inject constructor( // Not listening anymore since trigger events unregister themselves isListening = false updateListeningState() + keyguardFaceAuthInteractor.onDeviceLifted() keyguardUpdateMonitor.requestFaceAuth( FaceAuthApiRequestReason.PICK_UP_GESTURE_TRIGGERED ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java deleted file mode 100644 index 076e5f1c1ce7..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.view.WindowInsets; -import android.widget.FrameLayout; - -/** - * A view group which contains the preview of phone/camera and draws a black bar at the bottom as - * the fake navigation bar. - */ -public class KeyguardPreviewContainer extends FrameLayout { - - private Drawable mBlackBarDrawable = new Drawable() { - @Override - public void draw(Canvas canvas) { - canvas.save(); - canvas.clipRect(0, getHeight() - getPaddingBottom(), getWidth(), getHeight()); - canvas.drawColor(Color.BLACK); - canvas.restore(); - } - - @Override - public void setAlpha(int alpha) { - // noop - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - // noop - } - - @Override - public int getOpacity() { - return android.graphics.PixelFormat.OPAQUE; - } - }; - - public KeyguardPreviewContainer(Context context, AttributeSet attrs) { - super(context, attrs); - setBackground(mBlackBarDrawable); - } - - @Override - public WindowInsets onApplyWindowInsets(WindowInsets insets) { - setPadding(0, 0, 0, insets.getStableInsetBottom()); - return super.onApplyWindowInsets(insets); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index 3268032becf8..2814e8d8f97b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -49,6 +49,7 @@ import com.android.systemui.plugins.log.LogLevel; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.disableflags.DisableStateTracker; @@ -119,6 +120,9 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat private final Object mLock = new Object(); private final KeyguardLogger mLogger; + // TODO(b/273443374): remove + private NotificationMediaManager mNotificationMediaManager; + private final ConfigurationController.ConfigurationListener mConfigurationListener = new ConfigurationController.ConfigurationListener() { @Override @@ -283,7 +287,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat SecureSettings secureSettings, CommandQueue commandQueue, @Main Executor mainExecutor, - KeyguardLogger logger + KeyguardLogger logger, + NotificationMediaManager notificationMediaManager ) { super(view); mCarrierTextController = carrierTextController; @@ -335,6 +340,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat /* mask2= */ DISABLE2_SYSTEM_ICONS, this::updateViewState ); + mNotificationMediaManager = notificationMediaManager; } @Override @@ -484,8 +490,11 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat * (1.0f - mKeyguardHeadsUpShowingAmount); } - if (mSystemEventAnimator.isAnimationRunning()) { + if (mSystemEventAnimator.isAnimationRunning() + && !mNotificationMediaManager.isLockscreenWallpaperOnNotificationShade()) { newAlpha = Math.min(newAlpha, mSystemEventAnimatorAlpha); + } else { + mView.setTranslationX(0); } boolean hideForBypass = @@ -625,11 +634,21 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat private StatusBarSystemEventDefaultAnimator getSystemEventAnimator(boolean isAnimationRunning) { return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> { - mSystemEventAnimatorAlpha = alpha; + // TODO(b/273443374): remove if-else condition + if (!mNotificationMediaManager.isLockscreenWallpaperOnNotificationShade()) { + mSystemEventAnimatorAlpha = alpha; + } else { + mSystemEventAnimatorAlpha = 1f; + } updateViewState(); return Unit.INSTANCE; }, (translationX) -> { - mView.setTranslationX(translationX); + // TODO(b/273443374): remove if-else condition + if (!mNotificationMediaManager.isLockscreenWallpaperOnNotificationShade()) { + mView.setTranslationX(translationX); + } else { + mView.setTranslationX(0); + } return Unit.INSTANCE; }, isAnimationRunning); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt index 398985402e76..f7426451fa50 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt @@ -26,10 +26,10 @@ import android.view.WindowInsetsController.Appearance import com.android.internal.statusbar.LetterboxDetails import com.android.internal.util.ContrastColorUtil import com.android.internal.view.AppearanceRegion +import com.android.systemui.Dumpable +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent import java.io.PrintWriter import java.util.Arrays @@ -50,24 +50,20 @@ class LetterboxAppearance( * Responsible for calculating the [Appearance] and [AppearanceRegion] for the status bar when apps * are letterboxed. */ -@CentralSurfacesScope +@SysUISingleton class LetterboxAppearanceCalculator @Inject constructor( private val lightBarController: LightBarController, - private val dumpManager: DumpManager, + dumpManager: DumpManager, private val letterboxBackgroundProvider: LetterboxBackgroundProvider, -) : OnStatusBarViewInitializedListener, CentralSurfacesComponent.Startable { +) : OnStatusBarViewInitializedListener, Dumpable { - private var statusBarBoundsProvider: StatusBarBoundsProvider? = null - - override fun start() { - dumpManager.registerCriticalDumpable(javaClass.simpleName) { pw, _ -> dump(pw) } + init { + dumpManager.registerCriticalDumpable(this) } - override fun stop() { - dumpManager.unregisterDumpable(javaClass.simpleName) - } + private var statusBarBoundsProvider: StatusBarBoundsProvider? = null private var lastAppearance: Int? = null private var lastAppearanceRegions: Array<AppearanceRegion>? = null @@ -216,8 +212,8 @@ constructor( return this.intersect(other) } - private fun dump(printWriter: PrintWriter) { - printWriter.println( + override fun dump(pw: PrintWriter, args: Array<out String>) { + pw.println( """ lastAppearance: ${lastAppearance?.toAppearanceString()} lastAppearanceRegion: ${Arrays.toString(lastAppearanceRegions)}, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt index 276375004f76..34c7059ec991 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt @@ -22,28 +22,25 @@ import android.graphics.Color import android.os.Handler import android.os.RemoteException import android.view.IWindowManager +import com.android.systemui.CoreStartable import com.android.systemui.Dumpable +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.dump.DumpManager -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent -import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope import java.io.PrintWriter import java.util.concurrent.Executor import javax.inject.Inject /** Responsible for providing information about the background of letterboxed apps. */ -@CentralSurfacesScope +@SysUISingleton class LetterboxBackgroundProvider @Inject constructor( private val windowManager: IWindowManager, @Background private val backgroundExecutor: Executor, - private val dumpManager: DumpManager, private val wallpaperManager: WallpaperManager, @Main private val mainHandler: Handler, -) : CentralSurfacesComponent.Startable, Dumpable { - +) : CoreStartable, Dumpable { @ColorInt var letterboxBackgroundColor: Int = Color.BLACK private set @@ -57,7 +54,6 @@ constructor( } override fun start() { - dumpManager.registerDumpable(javaClass.simpleName, this) fetchBackgroundColorInfo() wallpaperManager.addOnColorsChangedListener(wallpaperColorsListener, mainHandler) } @@ -74,11 +70,6 @@ constructor( } } - override fun stop() { - dumpManager.unregisterDumpable(javaClass.simpleName) - wallpaperManager.removeOnColorsChangedListener(wallpaperColorsListener) - } - override fun dump(pw: PrintWriter, args: Array<out String>) { pw.println( """ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardSettingsPopupMenuModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxModule.kt index 7c61e7108265..2e3f0d0abc0a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardSettingsPopupMenuModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxModule.kt @@ -15,16 +15,18 @@ * */ -package com.android.systemui.keyguard.domain.model +package com.android.systemui.statusbar.phone -import com.android.systemui.common.shared.model.Position +import com.android.systemui.CoreStartable +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap -/** Models a settings popup menu for the lock screen. */ -data class KeyguardSettingsPopupMenuModel( - /** Where the menu should be anchored, roughly in screen space. */ - val position: Position, - /** Callback to invoke when the menu gets clicked by the user. */ - val onClicked: () -> Unit, - /** Callback to invoke when the menu gets dismissed by the user. */ - val onDismissed: () -> Unit, -) +@Module +abstract class LetterboxModule { + @Binds + @IntoMap + @ClassKey(LetterboxBackgroundProvider::class) + abstract fun bindFeature(impl: LetterboxBackgroundProvider): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java index 0814ea593a0b..c16877a999f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java @@ -233,6 +233,11 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } + // TODO(b/273443374): remove + public boolean isLockscreenLiveWallpaperEnabled() { + return mWallpaperManager.isLockscreenLiveWallpaperEnabled(); + } + @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println(getClass().getSimpleName() + ":"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index eb19c0d2ad71..057fa42bd347 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -193,7 +193,6 @@ public class NotificationIconAreaController implements public void setupShelf(NotificationShelfController notificationShelfController) { mShelfIcons = notificationShelfController.getShelfIcons(); - notificationShelfController.setCollapsedIcons(mNotificationIcons); } public void onDensityOrFontScaleChanged(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt index b3031515ae9d..c8174669cc65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt @@ -85,17 +85,16 @@ class ScreenOffAnimationController @Inject constructor( /** * Called when keyguard is about to be displayed and allows to perform custom animation - * - * @return A handle that can be used for cancelling the animation, if necessary */ - fun animateInKeyguard(keyguardView: View, after: Runnable): AnimatorHandle? { - animations.forEach { + fun animateInKeyguard(keyguardView: View, after: Runnable) = + animations.firstOrNull { if (it.shouldAnimateInKeyguard()) { - return@animateInKeyguard it.animateInKeyguard(keyguardView, after) + it.animateInKeyguard(keyguardView, after) + true + } else { + false } } - return null - } /** * If returns true it will disable propagating touches to apps and keyguard @@ -212,10 +211,7 @@ interface ScreenOffAnimation { fun onAlwaysOnChanged(alwaysOn: Boolean) {} fun shouldAnimateInKeyguard(): Boolean = false - fun animateInKeyguard(keyguardView: View, after: Runnable): AnimatorHandle? { - after.run() - return null - } + fun animateInKeyguard(keyguardView: View, after: Runnable) = after.run() fun shouldDelayKeyguardShow(): Boolean = false fun isKeyguardShowDelayed(): Boolean = false @@ -228,7 +224,3 @@ interface ScreenOffAnimation { fun shouldAnimateDozingChange(): Boolean = true fun shouldAnimateClockChange(): Boolean = true } - -interface AnimatorHandle { - fun cancel() -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 30d2295206d8..a8a834f1e8f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -558,8 +558,10 @@ public interface StatusBarIconController { mGroup.addView(view, index, onCreateLayoutParams()); if (mIsInDemoMode) { + Context mobileContext = mMobileContextProvider + .getMobileContextForSub(subId, mContext); mDemoStatusIcons.addModernMobileView( - mContext, + mobileContext, mMobileIconsViewModel.getLogger(), subId); } 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 49b58df23fdb..70aab61ffed0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -656,9 +656,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } updateAlternateBouncerShowing(mAlternateBouncerInteractor.show()); + setKeyguardMessage(message, null); return; } + mViewMediatorCallback.setCustomMessage(message); if (afterKeyguardGone) { // we'll handle the dismiss action after keyguard is gone, so just show the // bouncer diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index edfc95fcc2e7..c623201b2a6b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -618,9 +618,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) { return false; } - if ((flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { - return false; - } return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index de7bf3c021dd..d731f8886536 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -230,7 +230,7 @@ public class StatusBarSignalPolicy implements SignalCallback, if (state == null) { return; } - if (statusIcon.icon == R.drawable.ic_qs_no_calling_sms) { + if (statusIcon.icon == R.drawable.ic_shade_no_calling_sms) { state.isNoCalling = statusIcon.visible; state.noCallingDescription = statusIcon.contentDescription; } else { @@ -422,7 +422,7 @@ public class StatusBarSignalPolicy implements SignalCallback, private CallIndicatorIconState(int subId) { this.subId = subId; - this.noCallingResId = R.drawable.ic_qs_no_calling_sms; + this.noCallingResId = R.drawable.ic_shade_no_calling_sms; this.callStrengthResId = TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[0]; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java index 50cce45cd87a..6dc8065b2822 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java @@ -16,6 +16,12 @@ package com.android.systemui.statusbar.phone; public interface StatusBarWindowCallback { - void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing, - boolean isDozing, boolean panelExpanded, boolean isDreaming); + /** + * Invoked when the internal state of NotificationShadeWindowControllerImpl changes. + * Some of the flags passed as argument to the callback might have changed, but this is not + * guaranteed. + */ + void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, + boolean keyguardGoingAway, boolean bouncerShowing, boolean isDozing, + boolean panelExpanded, boolean isDreaming); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 2027305fdb99..bb223650facc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -191,7 +191,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh } @Override - protected void onStart() { + protected final void onStart() { super.onStart(); if (mDismissReceiver != null) { @@ -204,10 +204,18 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh mDialogManager.setShowing(this, true); mSysUiState.setFlag(QuickStepContract.SYSUI_STATE_DIALOG_SHOWING, true) .commitUpdate(mContext.getDisplayId()); + + start(); } + /** + * Called when {@link #onStart} is called. Subclasses wishing to override {@link #onStart()} + * should override this method instead. + */ + protected void start() {} + @Override - protected void onStop() { + protected final void onStop() { super.onStop(); if (mDismissReceiver != null) { @@ -218,8 +226,16 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh mDialogManager.setShowing(this, false); mSysUiState.setFlag(QuickStepContract.SYSUI_STATE_DIALOG_SHOWING, false) .commitUpdate(mContext.getDisplayId()); + + stop(); } + /** + * Called when {@link #onStop} is called. Subclasses wishing to override {@link #onStop()} + * should override this method instead. + */ + protected void stop() {} + public void setShowForAllUsers(boolean show) { setShowForAllUsers(this, show); } 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 deb041454da4..0cd3401ae541 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -160,7 +160,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( * Animates in the provided keyguard view, ending in the same position that it will be in on * AOD. */ - override fun animateInKeyguard(keyguardView: View, after: Runnable): AnimatorHandle { + override fun animateInKeyguard(keyguardView: View, after: Runnable) { shouldAnimateInKeyguard = false keyguardView.alpha = 0f keyguardView.visibility = View.VISIBLE @@ -175,40 +175,19 @@ class UnlockedScreenOffAnimationController @Inject constructor( // We animate the Y properly separately using the PropertyAnimator, as the panel // view also needs to update the end position. PropertyAnimator.cancelAnimation(keyguardView, AnimatableProperty.Y) + PropertyAnimator.setProperty(keyguardView, AnimatableProperty.Y, currentY, + AnimationProperties().setDuration(duration.toLong()), + true /* animate */) - // Start the animation on the next frame using Choreographer APIs. animateInKeyguard() is - // called while the system is busy processing lots of requests, so delaying the animation a - // frame will mitigate jank. In the event the animation is cancelled before the next frame - // is called, this callback will be removed - val keyguardAnimator = keyguardView.animate() - val nextFrameCallback = TraceUtils.namedRunnable("startAnimateInKeyguard") { - PropertyAnimator.setProperty(keyguardView, AnimatableProperty.Y, currentY, - AnimationProperties().setDuration(duration.toLong()), - true /* animate */) - keyguardAnimator.start() - } - DejankUtils.postAfterTraversal(nextFrameCallback) - val animatorHandle = object : AnimatorHandle { - private var hasCancelled = false - override fun cancel() { - if (!hasCancelled) { - DejankUtils.removeCallbacks(nextFrameCallback) - // If we're cancelled, reset state flags/listeners. The end action above - // will not be called, which is what we want since that will finish the - // screen off animation and show the lockscreen, which we don't want if we - // were cancelled. - aodUiAnimationPlaying = false - decidedToAnimateGoingToSleep = null - keyguardView.animate().setListener(null) - hasCancelled = true - } - } - } - keyguardAnimator + // Cancel any existing CUJs before starting the animation + interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD) + + PropertyAnimator.setProperty( + keyguardView, AnimatableProperty.ALPHA, 1f, + AnimationProperties() + .setDelay(0) .setDuration(duration.toLong()) - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .alpha(1f) - .withEndAction { + .setAnimationEndAction { aodUiAnimationPlaying = false // Lock the keyguard if it was waiting for the screen off animation to end. @@ -224,23 +203,23 @@ class UnlockedScreenOffAnimationController @Inject constructor( // Done going to sleep, reset this flag. decidedToAnimateGoingToSleep = null - // We need to unset the listener. These are persistent for future animators - keyguardView.animate().setListener(null) interactionJankMonitor.end(CUJ_SCREEN_OFF_SHOW_AOD) } - .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationCancel(animation: Animator?) { - animatorHandle.cancel() - interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD) - } - - override fun onAnimationStart(animation: Animator?) { - interactionJankMonitor.begin( - mCentralSurfaces.notificationShadeWindowView, - CUJ_SCREEN_OFF_SHOW_AOD) - } - }) - return animatorHandle + .setAnimationCancelAction { + // If we're cancelled, reset state flags/listeners. The end action above + // will not be called, which is what we want since that will finish the + // screen off animation and show the lockscreen, which we don't want if we + // were cancelled. + aodUiAnimationPlaying = false + decidedToAnimateGoingToSleep = null + interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD) + } + .setCustomInterpolator(View.ALPHA, Interpolators.FAST_OUT_SLOW_IN), + true /* animate */) + interactionJankMonitor.begin( + mCentralSurfaces.notificationShadeWindowView, + CUJ_SCREEN_OFF_SHOW_AOD + ) } override fun onStartedWakingUp() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java index b0532d773f7b..f72e74b77aea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java @@ -16,17 +16,15 @@ package com.android.systemui.statusbar.phone.dagger; -import com.android.systemui.statusbar.phone.LetterboxAppearanceCalculator; -import com.android.systemui.statusbar.phone.LetterboxBackgroundProvider; import com.android.systemui.statusbar.phone.SystemBarAttributesListener; -import java.util.Set; - import dagger.Binds; import dagger.Module; import dagger.multibindings.IntoSet; import dagger.multibindings.Multibinds; +import java.util.Set; + @Module interface CentralSurfacesStartableModule { @Multibinds @@ -34,16 +32,6 @@ interface CentralSurfacesStartableModule { @Binds @IntoSet - CentralSurfacesComponent.Startable letterboxAppearanceCalculator( - LetterboxAppearanceCalculator letterboxAppearanceCalculator); - - @Binds - @IntoSet CentralSurfacesComponent.Startable sysBarAttrsListener( SystemBarAttributesListener systemBarAttributesListener); - - @Binds - @IntoSet - CentralSurfacesComponent.Startable letterboxBgProvider( - LetterboxBackgroundProvider letterboxBackgroundProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index 0929233feb88..5d4addab240a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -33,6 +33,7 @@ import com.android.systemui.biometrics.AuthRippleView; 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.plugins.statusbar.StatusBarStateController; import com.android.systemui.privacy.OngoingPrivacyChip; import com.android.systemui.settings.UserTracker; @@ -44,12 +45,14 @@ import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.NotificationsQuickSettingsContainer; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.OperatorNameViewController; import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; +import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.KeyguardBottomAreaView; import com.android.systemui.statusbar.phone.LetterboxAppearanceCalculator; @@ -76,6 +79,7 @@ import com.android.systemui.util.settings.SecureSettings; import java.util.concurrent.Executor; import javax.inject.Named; +import javax.inject.Provider; import dagger.Binds; import dagger.Module; @@ -130,16 +134,24 @@ public abstract class StatusBarViewModule { @Provides @CentralSurfacesComponent.CentralSurfacesScope public static NotificationShelfController providesStatusBarWindowView( + FeatureFlags featureFlags, + Provider<NotificationShelfViewBinderWrapperControllerImpl> newImpl, NotificationShelfComponent.Builder notificationShelfComponentBuilder, NotificationShelf notificationShelf) { - NotificationShelfComponent component = notificationShelfComponentBuilder - .notificationShelf(notificationShelf) - .build(); - NotificationShelfController notificationShelfController = - component.getNotificationShelfController(); - notificationShelfController.init(); - - return notificationShelfController; + if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { + NotificationShelfViewBinderWrapperControllerImpl impl = newImpl.get(); + impl.init(); + return impl; + } else { + NotificationShelfComponent component = notificationShelfComponentBuilder + .notificationShelf(notificationShelf) + .build(); + LegacyNotificationShelfControllerImpl notificationShelfController = + component.getNotificationShelfController(); + notificationShelfController.init(); + + return notificationShelfController; + } } /** */ 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 eaa145582ba3..b3d246164e87 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 @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupR import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter +import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel 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 @@ -53,6 +54,9 @@ import dagger.Module import dagger.Provides import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap +import kotlinx.coroutines.flow.Flow +import java.util.function.Supplier +import javax.inject.Named @Module abstract class StatusBarPipelineModule { @@ -115,6 +119,17 @@ abstract class StatusBarPipelineModule { @Provides @SysUISingleton + @Named(FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON) + fun provideFirstMobileSubShowingNetworkTypeIconProvider( + mobileIconsViewModel: MobileIconsViewModel, + ): Supplier<Flow<Boolean>> { + return Supplier<Flow<Boolean>> { + mobileIconsViewModel.firstMobileSubShowingNetworkTypeIcon + } + } + + @Provides + @SysUISingleton @WifiInputLog fun provideWifiInputLogBuffer(factory: LogBufferFactory): LogBuffer { return factory.create("WifiInputLog", 50) @@ -168,5 +183,8 @@ abstract class StatusBarPipelineModule { fun provideVerboseMobileViewLogBuffer(factory: LogBufferFactory): LogBuffer { return factory.create("VerboseMobileViewLog", 100) } + + const val FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON = + "FirstMobileSubShowingNetworkTypeIcon" } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt index 90c32dc08045..3a11635f75c3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt @@ -40,6 +40,9 @@ interface MobileConnectionRepository { /** The subscriptionId that this connection represents */ val subId: Int + /** The carrierId for this connection. See [TelephonyManager.getSimCarrierId] */ + val carrierId: StateFlow<Int> + /** * The table log buffer created for this connection. Will have the name "MobileConnectionLog * [subId]" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt index fa712872eb13..ea77163f0556 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt @@ -60,6 +60,13 @@ interface MobileConnectionsRepository { */ val mobileIsDefault: StateFlow<Boolean> + /** + * True if the device currently has a carrier merged connection. + * + * See [CarrierMergedConnectionRepository] for more info. + */ + val hasCarrierMergedConnection: Flow<Boolean> + /** True if the default network connection is validated and false otherwise. */ val defaultConnectionIsValidated: StateFlow<Boolean> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt index 44b5b3fa2591..eb20bba0d21f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt @@ -159,6 +159,15 @@ constructor( .flatMapLatest { it.mobileIsDefault } .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.mobileIsDefault.value) + override val hasCarrierMergedConnection: StateFlow<Boolean> = + activeRepo + .flatMapLatest { it.hasCarrierMergedConnection } + .stateIn( + scope, + SharingStarted.WhileSubscribed(), + realRepository.hasCarrierMergedConnection.value, + ) + override val defaultConnectionIsValidated: StateFlow<Boolean> = activeRepo .flatMapLatest { it.defaultConnectionIsValidated } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt index 809772eec2f0..6b86432b8171 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo import android.telephony.CellSignalStrength +import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.telephony.TelephonyManager import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.log.table.logDiffsForTable @@ -25,6 +26,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel +import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_ID import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_NETWORK_CHANGE import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CDMA_LEVEL import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY @@ -52,6 +54,17 @@ class DemoMobileConnectionRepository( override val tableLogBuffer: TableLogBuffer, val scope: CoroutineScope, ) : MobileConnectionRepository { + private val _carrierId = MutableStateFlow(INVALID_SUBSCRIPTION_ID) + override val carrierId = + _carrierId + .logDiffsForTable( + tableLogBuffer, + columnPrefix = "", + columnName = COL_CARRIER_ID, + _carrierId.value, + ) + .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierId.value) + private val _isEmergencyOnly = MutableStateFlow(false) override val isEmergencyOnly = _isEmergencyOnly @@ -186,6 +199,8 @@ class DemoMobileConnectionRepository( dataEnabled.value = true networkName.value = NetworkNameModel.IntentDerived(event.name) + _carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID + cdmaRoaming.value = event.roaming _isRoaming.value = event.roaming // TODO(b/261029387): not yet supported @@ -208,6 +223,8 @@ class DemoMobileConnectionRepository( // This is always true here, because we split out disabled states at the data-source level dataEnabled.value = true networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME) + // TODO(b/276943904): is carrierId a thing with carrier merged networks? + _carrierId.value = INVALID_SUBSCRIPTION_ID numberOfLevels.value = event.numberOfLevels cdmaRoaming.value = false _primaryLevel.value = event.level diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index 737bc6826d08..0e4ceebcc854 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -160,6 +160,9 @@ constructor( override val mobileIsDefault: StateFlow<Boolean> = MutableStateFlow(true) // TODO(b/261029387): not yet supported + override val hasCarrierMergedConnection = MutableStateFlow(false) + + // TODO(b/261029387): not yet supported override val defaultConnectionIsValidated: StateFlow<Boolean> = MutableStateFlow(true) override fun getRepoForSubId(subId: Int): DemoMobileConnectionRepository { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt index 94d6d0b1db44..a609917351d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN +import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.telephony.TelephonyManager import android.util.Log import com.android.systemui.dagger.SysUISingleton @@ -157,6 +158,7 @@ class CarrierMergedConnectionRepository( .stateIn(scope, SharingStarted.WhileSubscribed(), DataConnectionState.Disconnected) override val isRoaming = MutableStateFlow(false).asStateFlow() + override val carrierId = MutableStateFlow(INVALID_SUBSCRIPTION_ID).asStateFlow() override val isEmergencyOnly = MutableStateFlow(false).asStateFlow() override val operatorAlphaShort = MutableStateFlow(null).asStateFlow() override val isInService = MutableStateFlow(true).asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt index b3737ecd1e0b..8869dfe02697 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt @@ -109,6 +109,11 @@ class FullMobileConnectionRepository( .stateIn(scope, SharingStarted.WhileSubscribed(), initial) } + override val carrierId = + activeRepo + .flatMapLatest { it.carrierId } + .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierId.value) + override val cdmaRoaming = activeRepo .flatMapLatest { it.cdmaRoaming } @@ -321,13 +326,14 @@ class FullMobileConnectionRepository( } companion object { + const val COL_CARRIER_ID = "carrierId" + const val COL_CARRIER_NETWORK_CHANGE = "carrierNetworkChangeActive" + const val COL_CDMA_LEVEL = "cdmaLevel" const val COL_EMERGENCY = "emergencyOnly" - const val COL_ROAMING = "roaming" - const val COL_OPERATOR = "operatorName" - const val COL_IS_IN_SERVICE = "isInService" const val COL_IS_GSM = "isGsm" - const val COL_CDMA_LEVEL = "cdmaLevel" + const val COL_IS_IN_SERVICE = "isInService" + const val COL_OPERATOR = "operatorName" const val COL_PRIMARY_LEVEL = "primaryLevel" - const val COL_CARRIER_NETWORK_CHANGE = "carrierNetworkChangeActive" + const val COL_ROAMING = "roaming" } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index d0c6215a55d8..b475183d98c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod -import android.content.Context +import android.content.Intent import android.content.IntentFilter import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN import android.telephony.CellSignalStrengthCdma @@ -31,6 +31,7 @@ import android.telephony.TelephonyManager.ERI_FLASH import android.telephony.TelephonyManager.ERI_ON import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN +import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID import com.android.settingslib.Utils import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.qualifiers.Application @@ -65,6 +66,7 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.scan import kotlinx.coroutines.flow.stateIn @@ -75,7 +77,6 @@ import kotlinx.coroutines.flow.stateIn @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") @OptIn(ExperimentalCoroutinesApi::class) class MobileConnectionRepositoryImpl( - private val context: Context, override val subId: Int, defaultNetworkName: NetworkNameModel, networkNameSeparator: String, @@ -293,6 +294,23 @@ class MobileConnectionRepositoryImpl( } .stateIn(scope, SharingStarted.WhileSubscribed(), false) + override val carrierId = + broadcastDispatcher + .broadcastFlow( + filter = + IntentFilter(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED), + map = { intent, _ -> intent }, + ) + .filter { intent -> + intent.getIntExtra(EXTRA_SUBSCRIPTION_ID, INVALID_SUBSCRIPTION_ID) == subId + } + .map { it.carrierId() } + .onStart { + // Make sure we get the initial carrierId + emit(telephonyManager.simCarrierId) + } + .stateIn(scope, SharingStarted.WhileSubscribed(), telephonyManager.simCarrierId) + override val networkName: StateFlow<NetworkNameModel> = broadcastDispatcher .broadcastFlow( @@ -317,7 +335,6 @@ class MobileConnectionRepositoryImpl( @Inject constructor( private val broadcastDispatcher: BroadcastDispatcher, - private val context: Context, private val telephonyManager: TelephonyManager, private val logger: MobileInputLogger, private val carrierConfigRepository: CarrierConfigRepository, @@ -332,7 +349,6 @@ class MobileConnectionRepositoryImpl( networkNameSeparator: String, ): MobileConnectionRepository { return MobileConnectionRepositoryImpl( - context, subId, defaultNetworkName, networkNameSeparator, @@ -349,6 +365,9 @@ class MobileConnectionRepositoryImpl( } } +private fun Intent.carrierId(): Int = + getIntExtra(TelephonyManager.EXTRA_CARRIER_ID, UNKNOWN_CARRIER_ID) + /** * Wrap every [TelephonyCallback] we care about in a data class so we can accept them in a single * shared flow and then split them back out into other flows. 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 45d50c103909..0e9b6c56437e 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 @@ -59,6 +59,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map @@ -257,18 +258,32 @@ constructor( override val mobileIsDefault: StateFlow<Boolean> = connectivityRepository.defaultConnections - // Because carrier merged networks are displayed as mobile networks, they're - // part of the `isDefault` calculation. See b/272586234. - .map { it.mobile.isDefault || it.carrierMerged.isDefault } + .map { it.mobile.isDefault } .distinctUntilChanged() .logDiffsForTable( tableLogger, - columnPrefix = "", + columnPrefix = LOGGING_PREFIX, columnName = "mobileIsDefault", initialValue = false, ) .stateIn(scope, SharingStarted.WhileSubscribed(), false) + override val hasCarrierMergedConnection: StateFlow<Boolean> = + combine( + connectivityRepository.defaultConnections, + carrierMergedSubId, + ) { defaultConnections, carrierMergedSubId -> + defaultConnections.carrierMerged.isDefault || carrierMergedSubId != null + } + .distinctUntilChanged() + .logDiffsForTable( + tableLogger, + columnPrefix = LOGGING_PREFIX, + columnName = "hasCarrierMergedConnection", + initialValue = false, + ) + .stateIn(scope, SharingStarted.WhileSubscribed(), false) + override val defaultConnectionIsValidated: StateFlow<Boolean> = connectivityRepository.defaultConnections .map { it.isValidated } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 22351f8b2821..b36ba3845fe9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -16,15 +16,21 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor +import android.content.Context import android.telephony.CarrierConfigManager import com.android.settingslib.SignalIcon.MobileIconGroup -import com.android.settingslib.mobile.TelephonyIcons.NOT_DEFAULT_DATA +import com.android.settingslib.mobile.MobileIconCarrierIdOverrides +import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository +import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel +import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel.DefaultIcon +import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel.OverriddenIcon import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -34,8 +40,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.mapLatest -import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn interface MobileIconInteractor { @@ -76,7 +80,7 @@ interface MobileIconInteractor { val alwaysUseCdmaLevel: StateFlow<Boolean> /** Observable for RAT type (network type) indicator */ - val networkTypeIconGroup: StateFlow<MobileIconGroup> + val networkTypeIconGroup: StateFlow<NetworkTypeIconModel> /** * Provider name for this network connection. The name can be one of 3 values: @@ -119,10 +123,11 @@ class MobileIconInteractorImpl( override val mobileIsDefault: StateFlow<Boolean>, defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>, defaultMobileIconGroup: StateFlow<MobileIconGroup>, - defaultDataSubId: StateFlow<Int>, override val isDefaultConnectionFailed: StateFlow<Boolean>, override val isForceHidden: Flow<Boolean>, connectionRepository: MobileConnectionRepository, + private val context: Context, + val carrierIdOverrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl() ) : MobileIconInteractor { override val tableLogBuffer: TableLogBuffer = connectionRepository.tableLogBuffer @@ -130,14 +135,14 @@ class MobileIconInteractorImpl( override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled - private val isDefault = - defaultDataSubId - .mapLatest { connectionRepository.subId == it } - .stateIn( - scope, - SharingStarted.WhileSubscribed(), - connectionRepository.subId == defaultDataSubId.value - ) + // True if there exists _any_ icon override for this carrierId. Note that overrides can include + // any or none of the icon groups defined in MobileMappings, so we still need to check on a + // per-network-type basis whether or not the given icon group is overridden + private val carrierIdIconOverrideExists = + connectionRepository.carrierId + .map { carrierIdOverrides.carrierIdEntryExists(it) } + .distinctUntilChanged() + .stateIn(scope, SharingStarted.WhileSubscribed(), false) override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled @@ -157,36 +162,57 @@ class MobileIconInteractorImpl( connectionRepository.networkName.value ) - /** Observable for the current RAT indicator icon ([MobileIconGroup]) */ - override val networkTypeIconGroup: StateFlow<MobileIconGroup> = + /** What the mobile icon would be before carrierId overrides */ + private val defaultNetworkType: StateFlow<MobileIconGroup> = combine( connectionRepository.resolvedNetworkType, defaultMobileIconMapping, defaultMobileIconGroup, - isDefault, - ) { resolvedNetworkType, mapping, defaultGroup, isDefault -> - if (!isDefault) { - return@combine NOT_DEFAULT_DATA - } - + ) { resolvedNetworkType, mapping, defaultGroup -> when (resolvedNetworkType) { is ResolvedNetworkType.CarrierMergedNetworkType -> resolvedNetworkType.iconGroupOverride - else -> mapping[resolvedNetworkType.lookupKey] ?: defaultGroup + else -> { + mapping[resolvedNetworkType.lookupKey] ?: defaultGroup + } } } - .distinctUntilChanged() - .onEach { - // Doesn't use [logDiffsForTable] because [MobileIconGroup] can't implement the - // [Diffable] interface. - tableLogBuffer.logChange( - prefix = "", - columnName = "networkTypeIcon", - value = it.name - ) - } .stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value) + override val networkTypeIconGroup = + combine( + defaultNetworkType, + carrierIdIconOverrideExists, + ) { networkType, overrideExists -> + // DefaultIcon comes out of the icongroup lookup, we check for overrides here + if (overrideExists) { + val iconOverride = + carrierIdOverrides.getOverrideFor( + connectionRepository.carrierId.value, + networkType.name, + context.resources, + ) + if (iconOverride > 0) { + OverriddenIcon(networkType, iconOverride) + } else { + DefaultIcon(networkType) + } + } else { + DefaultIcon(networkType) + } + } + .distinctUntilChanged() + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnPrefix = "", + initialValue = DefaultIcon(defaultMobileIconGroup.value), + ) + .stateIn( + scope, + SharingStarted.WhileSubscribed(), + DefaultIcon(defaultMobileIconGroup.value), + ) + override val isEmergencyOnly = connectionRepository.isEmergencyOnly override val isRoaming: StateFlow<Boolean> = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt index 6c8310ac3d29..eec91a0bca82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor +import android.content.Context import android.telephony.CarrierConfigManager import android.telephony.SubscriptionManager import com.android.settingslib.SignalIcon.MobileIconGroup @@ -75,9 +76,6 @@ interface MobileIconsInteractor { /** True if the CDMA level should be preferred over the primary level. */ val alwaysUseCdmaLevel: StateFlow<Boolean> - /** Tracks the subscriptionId set as the default for data connections */ - val defaultDataSubId: StateFlow<Int> - /** The icon mapping from network type to [MobileIconGroup] for the default subscription */ val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> @@ -112,9 +110,25 @@ constructor( connectivityRepository: ConnectivityRepository, userSetupRepo: UserSetupRepository, @Application private val scope: CoroutineScope, + private val context: Context, ) : MobileIconsInteractor { - override val mobileIsDefault = mobileConnectionsRepo.mobileIsDefault + override val mobileIsDefault = + combine( + mobileConnectionsRepo.mobileIsDefault, + mobileConnectionsRepo.hasCarrierMergedConnection, + ) { mobileIsDefault, hasCarrierMergedConnection -> + // Because carrier merged networks are displayed as mobile networks, they're part of + // the `isDefault` calculation. See b/272586234. + mobileIsDefault || hasCarrierMergedConnection + } + .logDiffsForTable( + tableLogger, + LOGGING_PREFIX, + columnName = "mobileIsDefault", + initialValue = false, + ) + .stateIn(scope, SharingStarted.WhileSubscribed(), false) override val activeDataConnectionHasDataEnabled: StateFlow<Boolean> = mobileConnectionsRepo.activeMobileDataRepository @@ -184,8 +198,6 @@ constructor( ) .stateIn(scope, SharingStarted.WhileSubscribed(), listOf()) - override val defaultDataSubId = mobileConnectionsRepo.defaultDataSubId - /** * Copied from the old pipeline. We maintain a 2s period of time where we will keep the * validated bit from the old active network (A) while data is changing to the new one (B). @@ -282,10 +294,10 @@ constructor( mobileIsDefault, defaultMobileIconMapping, defaultMobileIconGroup, - defaultDataSubId, isDefaultConnectionFailed, isForceHidden, mobileConnectionsRepo.getRepoForSubId(subId), + context, ) companion object { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/model/NetworkTypeIconModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/model/NetworkTypeIconModel.kt new file mode 100644 index 000000000000..6ea5f90ddc71 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/model/NetworkTypeIconModel.kt @@ -0,0 +1,69 @@ +/* + * 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.domain.model + +import com.android.settingslib.SignalIcon.MobileIconGroup +import com.android.systemui.log.table.Diffable +import com.android.systemui.log.table.TableRowLogger + +/** + * A data wrapper class for [MobileIconGroup]. One lingering nuance of this pipeline is its + * dependency on MobileMappings for its lookup from NetworkType -> NetworkTypeIcon. And because + * MobileMappings is a static map of (netType, icon) that knows nothing of `carrierId`, we need the + * concept of a "default" or "overridden" icon type. + * + * Until we can remove that dependency on MobileMappings, we should just allow for the composition + * of overriding an icon id using the lookup defined in [MobileIconCarrierIdOverrides]. By using the + * [overrideIcon] method defined below, we can create any arbitrarily overridden network type icon. + */ +sealed interface NetworkTypeIconModel : Diffable<NetworkTypeIconModel> { + val contentDescription: Int + val iconId: Int + val name: String + + data class DefaultIcon( + val iconGroup: MobileIconGroup, + ) : NetworkTypeIconModel { + override val contentDescription = iconGroup.dataContentDescription + override val iconId = iconGroup.dataType + override val name = iconGroup.name + + override fun logDiffs(prevVal: NetworkTypeIconModel, row: TableRowLogger) { + if (prevVal !is DefaultIcon || prevVal.name != name) { + row.logChange(COL_NETWORK_ICON, name) + } + } + } + + data class OverriddenIcon( + val iconGroup: MobileIconGroup, + override val iconId: Int, + ) : NetworkTypeIconModel { + override val contentDescription = iconGroup.dataContentDescription + override val name = iconGroup.name + + override fun logDiffs(prevVal: NetworkTypeIconModel, row: TableRowLogger) { + if (prevVal !is OverriddenIcon || prevVal.name != name || prevVal.iconId != iconId) { + row.logChange(COL_NETWORK_ICON, "Ovrd($name)") + } + } + } + + companion object { + const val COL_NETWORK_ICON = "networkTypeIcon" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt index 075e6ec11ae7..a05ab849088d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt @@ -26,15 +26,7 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsVi import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.mapLatest -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** @@ -46,39 +38,16 @@ import kotlinx.coroutines.launch * the list of available mobile lines of service for which we want to show icons. */ @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") -@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class MobileUiAdapter @Inject constructor( - interactor: MobileIconsInteractor, private val iconController: StatusBarIconController, - private val iconsViewModelFactory: MobileIconsViewModel.Factory, + val mobileIconsViewModel: MobileIconsViewModel, private val logger: MobileViewLogger, @Application private val scope: CoroutineScope, private val statusBarPipelineFlags: StatusBarPipelineFlags, ) : CoreStartable { - private val mobileSubIds: Flow<List<Int>> = - interactor.filteredSubscriptions.mapLatest { subscriptions -> - subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId } - } - - /** - * We expose the list of tracked subscriptions as a flow of a list of ints, where each int is - * the subscriptionId of the relevant subscriptions. These act as a key into the layouts which - * house the mobile infos. - * - * NOTE: this should go away as the view presenter learns more about this data pipeline - */ - private val mobileSubIdsState: StateFlow<List<Int>> = - mobileSubIds - .distinctUntilChanged() - .onEach { logger.logUiAdapterSubIdsUpdated(it) } - .stateIn(scope, SharingStarted.WhileSubscribed(), listOf()) - - /** In order to keep the logs tame, we will reuse the same top-level mobile icons view model */ - val mobileIconsViewModel = iconsViewModelFactory.create(mobileSubIdsState) - private var isCollecting: Boolean = false private var lastValue: List<Int>? = null @@ -90,7 +59,7 @@ constructor( if (statusBarPipelineFlags.useNewMobileIcons()) { scope.launch { isCollecting = true - mobileSubIds.collectLatest { + mobileIconsViewModel.subscriptionIdsFlow.collectLatest { logger.logUiAdapterSubIdsSentToIconController(it) lastValue = it iconController.setNewMobileIconSubIds(it) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt index 90dff23c637c..f2f91430eba6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt @@ -41,15 +41,6 @@ constructor( private val collectionStatuses = mutableMapOf<String, Boolean>() - fun logUiAdapterSubIdsUpdated(subs: List<Int>) { - buffer.log( - TAG, - LogLevel.INFO, - { str1 = subs.toString() }, - { "Sub IDs in MobileUiAdapter updated internally: $str1" }, - ) - } - fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) { buffer.log( TAG, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt index 62bc27f9dd4e..bfd133e6830c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt @@ -37,7 +37,6 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.stateIn /** Common interface for all of the location-based mobile icon view models. */ @@ -80,7 +79,12 @@ constructor( ) : MobileIconViewModelCommon { /** Whether or not to show the error state of [SignalDrawable] */ private val showExclamationMark: Flow<Boolean> = - iconInteractor.isDefaultDataEnabled.mapLatest { !it } + combine( + iconInteractor.isDefaultDataEnabled, + iconInteractor.isDefaultConnectionFailed, + ) { isDefaultDataEnabled, isDefaultConnectionFailed -> + !isDefaultDataEnabled || isDefaultConnectionFailed + } override val isVisible: StateFlow<Boolean> = if (!constants.hasDataCapabilities) { @@ -146,11 +150,10 @@ constructor( combine( iconInteractor.isDataConnected, iconInteractor.isDataEnabled, - iconInteractor.isDefaultConnectionFailed, iconInteractor.alwaysShowDataRatIcon, iconInteractor.mobileIsDefault, - ) { dataConnected, dataEnabled, failedConnection, alwaysShow, mobileIsDefault -> - alwaysShow || (dataConnected && dataEnabled && !failedConnection && mobileIsDefault) + ) { dataConnected, dataEnabled, alwaysShow, mobileIsDefault -> + alwaysShow || (dataEnabled && dataConnected && mobileIsDefault) } .distinctUntilChanged() .logDiffsForTable( @@ -167,12 +170,12 @@ constructor( showNetworkTypeIcon, ) { networkTypeIconGroup, shouldShow -> val desc = - if (networkTypeIconGroup.dataContentDescription != 0) - ContentDescription.Resource(networkTypeIconGroup.dataContentDescription) + if (networkTypeIconGroup.contentDescription != 0) + ContentDescription.Resource(networkTypeIconGroup.contentDescription) else null val icon = - if (networkTypeIconGroup.dataType != 0) - Icon.Resource(networkTypeIconGroup.dataType, desc) + if (networkTypeIconGroup.iconId != 0) + Icon.Resource(networkTypeIconGroup.iconId, desc) else null return@combine when { !shouldShow -> null diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt index 2b90065284d0..40b8c90fb9f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt @@ -29,18 +29,26 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMob import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** * View model for describing the system's current mobile cellular connections. The result is a list * of [MobileIconViewModel]s which describe the individual icons and can be bound to - * [ModernStatusBarMobileView] + * [ModernStatusBarMobileView]. */ +@OptIn(ExperimentalCoroutinesApi::class) +@SysUISingleton class MobileIconsViewModel @Inject constructor( - val subscriptionIdsFlow: StateFlow<List<Int>>, val logger: MobileViewLogger, private val verboseLogger: VerboseMobileViewLogger, private val interactor: MobileIconsInteractor, @@ -51,22 +59,43 @@ constructor( ) { @VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>() + val subscriptionIdsFlow: StateFlow<List<Int>> = + interactor.filteredSubscriptions + .mapLatest { subscriptions -> + subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId } + } + .stateIn(scope, SharingStarted.WhileSubscribed(), listOf()) + + private val firstMobileSubViewModel: StateFlow<MobileIconViewModelCommon?> = + subscriptionIdsFlow + .map { + if (it.isEmpty()) { + null + } else { + // Mobile icons get reversed by [StatusBarIconController], so the last element + // in this list will show up visually first. + commonViewModelForSub(it.last()) + } + } + .stateIn(scope, SharingStarted.WhileSubscribed(), null) + + /** + * A flow that emits `true` if the mobile sub that's displayed first visually is showing its + * network type icon and `false` otherwise. + */ + val firstMobileSubShowingNetworkTypeIcon: StateFlow<Boolean> = + firstMobileSubViewModel + .flatMapLatest { firstMobileSubViewModel -> + firstMobileSubViewModel?.networkTypeIcon?.map { it != null } ?: flowOf(false) + } + .stateIn(scope, SharingStarted.WhileSubscribed(), false) + init { scope.launch { subscriptionIdsFlow.collect { removeInvalidModelsFromCache(it) } } } fun viewModelForSub(subId: Int, location: StatusBarLocation): LocationBasedMobileViewModel { - val common = - mobileIconSubIdCache[subId] - ?: MobileIconViewModel( - subId, - interactor.createMobileConnectionInteractorForSubId(subId), - airplaneModeInteractor, - constants, - scope, - ) - .also { mobileIconSubIdCache[subId] = it } - + val common = commonViewModelForSub(subId) return LocationBasedMobileViewModel.viewModelForLocation( common, statusBarPipelineFlags, @@ -75,34 +104,20 @@ constructor( ) } + private fun commonViewModelForSub(subId: Int): MobileIconViewModelCommon { + return mobileIconSubIdCache[subId] + ?: MobileIconViewModel( + subId, + interactor.createMobileConnectionInteractorForSubId(subId), + airplaneModeInteractor, + constants, + scope, + ) + .also { mobileIconSubIdCache[subId] = it } + } + private fun removeInvalidModelsFromCache(subIds: List<Int>) { val subIdsToRemove = mobileIconSubIdCache.keys.filter { !subIds.contains(it) } subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) } } - - @SysUISingleton - class Factory - @Inject - constructor( - private val logger: MobileViewLogger, - private val verboseLogger: VerboseMobileViewLogger, - private val interactor: MobileIconsInteractor, - private val airplaneModeInteractor: AirplaneModeInteractor, - private val constants: ConnectivityConstants, - @Application private val scope: CoroutineScope, - private val statusBarPipelineFlags: StatusBarPipelineFlags, - ) { - fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel { - return MobileIconsViewModel( - subscriptionIdsFlow, - logger, - verboseLogger, - interactor, - airplaneModeInteractor, - constants, - scope, - statusBarPipelineFlags, - ) - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt index 6479f3d9f8a6..731f1e028470 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt @@ -44,11 +44,11 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnecti import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel.Ethernet import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel.Mobile import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel.Wifi +import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo import com.android.systemui.tuner.TunerService import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -68,12 +68,12 @@ interface ConnectivityRepository { val defaultConnections: StateFlow<DefaultConnectionModel> } -@OptIn(ExperimentalCoroutinesApi::class) +@SuppressLint("MissingPermission") @SysUISingleton class ConnectivityRepositoryImpl @Inject constructor( - connectivityManager: ConnectivityManager, + private val connectivityManager: ConnectivityManager, private val connectivitySlots: ConnectivitySlots, context: Context, dumpManager: DumpManager, @@ -144,15 +144,14 @@ constructor( ) { logger.logOnDefaultCapabilitiesChanged(network, networkCapabilities) + val wifiInfo = + networkCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + val isWifiDefault = - networkCapabilities.hasTransport(TRANSPORT_WIFI) || - networkCapabilities.getMainOrUnderlyingWifiInfo() != null + networkCapabilities.hasTransport(TRANSPORT_WIFI) || wifiInfo != null val isMobileDefault = networkCapabilities.hasTransport(TRANSPORT_CELLULAR) - val isCarrierMergedDefault = - networkCapabilities - .getMainOrUnderlyingWifiInfo() - ?.isCarrierMerged == true + val isCarrierMergedDefault = wifiInfo?.isCarrierMerged == true val isEthernetDefault = networkCapabilities.hasTransport(TRANSPORT_ETHERNET) @@ -209,7 +208,32 @@ constructor( * always use [WifiInfo] if it's available, so we need to check the underlying transport * info. */ - fun NetworkCapabilities.getMainOrUnderlyingWifiInfo(): WifiInfo? { + fun NetworkCapabilities.getMainOrUnderlyingWifiInfo( + connectivityManager: ConnectivityManager, + ): WifiInfo? { + val mainWifiInfo = this.getMainWifiInfo() + if (mainWifiInfo != null) { + return mainWifiInfo + } + // Only CELLULAR networks may have underlying wifi information that's relevant to SysUI, + // so skip the underlying network check if it's not CELLULAR. + if (!this.hasTransport(TRANSPORT_CELLULAR)) { + return mainWifiInfo + } + + // Some connections, like VPN connections, may have underlying networks that are + // eventually traced to a wifi or carrier merged connection. So, check those underlying + // networks for possible wifi information as well. See b/225902574. + return this.underlyingNetworks?.firstNotNullOfOrNull { underlyingNetwork -> + connectivityManager.getNetworkCapabilities(underlyingNetwork)?.getMainWifiInfo() + } + } + + /** + * Checks the network capabilities for wifi info, but does *not* check the underlying + * networks. See [getMainOrUnderlyingWifiInfo]. + */ + private fun NetworkCapabilities.getMainWifiInfo(): WifiInfo? { // Wifi info can either come from a WIFI Transport, or from a CELLULAR transport for // virtual networks like VCN. val canHaveWifiInfo = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt index 08c14e743bb6..f800cf496ca9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt @@ -33,6 +33,15 @@ interface WifiRepository { /** Observable for the current wifi network activity. */ val wifiActivity: StateFlow<DataActivityModel> + + /** + * Returns true if the device is currently connected to a wifi network with a valid SSID and + * false otherwise. + */ + fun isWifiConnectedWithValidSsid(): Boolean { + val currentNetwork = wifiNetwork.value + return currentNetwork is WifiNetworkModel.Active && currentNetwork.hasValidSsid() + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt index f80aa688268f..b37c44a2f8cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt @@ -138,7 +138,8 @@ constructor( wifiNetworkChangeEvents.tryEmit(Unit) - val wifiInfo = networkCapabilities.getMainOrUnderlyingWifiInfo() + val wifiInfo = + networkCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) if (wifiInfo?.isPrimary == true) { val wifiNetworkModel = createWifiNetworkModel( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt index 96ab074c6e56..1a41abf031bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.pipeline.wifi.domain.interactor -import android.net.wifi.WifiManager import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel @@ -76,7 +75,7 @@ constructor( when { info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint -> info.passpointProviderFriendlyName - info.ssid != WifiManager.UNKNOWN_SSID -> info.ssid + info.hasValidSsid() -> info.ssid else -> null } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt index 0923d7848d8c..4b33c88cea30 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.wifi.shared.model +import android.net.wifi.WifiManager.UNKNOWN_SSID import android.telephony.SubscriptionManager import androidx.annotation.VisibleForTesting import com.android.systemui.log.table.Diffable @@ -223,6 +224,11 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> { } } + /** Returns true if this network has a valid SSID and false otherwise. */ + fun hasValidSsid(): Boolean { + return ssid != null && ssid != UNKNOWN_SSID + } + override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) { if (prevVal !is Active) { logFull(row) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt index 9e8c814ca2a9..e819c4fc96ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt @@ -36,7 +36,6 @@ import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch @@ -64,6 +63,7 @@ object WifiViewBinder { val activityOutView = view.requireViewById<ImageView>(R.id.wifi_out) val activityContainerView = view.requireViewById<View>(R.id.inout_container) val airplaneSpacer = view.requireViewById<View>(R.id.wifi_airplane_spacer) + val signalSpacer = view.requireViewById<View>(R.id.wifi_signal_spacer) view.isVisible = true iconView.isVisible = true @@ -133,6 +133,12 @@ object WifiViewBinder { } } + launch { + viewModel.isSignalSpacerVisible.distinctUntilChanged().collect { visible -> + signalSpacer.isVisible = visible + } + } + try { awaitCancellation() } finally { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt index c9a0786acc72..d9c214452ef1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt @@ -30,8 +30,8 @@ import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK -import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel +import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule.Companion.FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel @@ -39,7 +39,9 @@ import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiIntera import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon +import java.util.function.Supplier import javax.inject.Inject +import javax.inject.Named import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted @@ -53,24 +55,24 @@ import kotlinx.coroutines.flow.stateIn /** * Models the UI state for the status bar wifi icon. * - * This class exposes three view models, one per status bar location: [home], [keyguard], and [qs]. - * In order to get the UI state for the wifi icon, you must use one of those view models (whichever - * is correct for your location). - * - * Internally, this class maintains the current state of the wifi icon and notifies those three view - * models of any changes. + * This is a singleton so that we don't have duplicate logs and should *not* be used directly to + * control views. Instead, use an instance of [LocationBasedWifiViewModel]. See + * [LocationBasedWifiViewModel.viewModelForLocation]. */ @SysUISingleton class WifiViewModel @Inject constructor( airplaneModeViewModel: AirplaneModeViewModel, + // TODO(b/238425913): The wifi icon shouldn't need to consume mobile information. A + // container-level view model should do the work instead. + @Named(FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON) + shouldShowSignalSpacerProvider: Supplier<Flow<Boolean>>, connectivityConstants: ConnectivityConstants, private val context: Context, @WifiTableLog wifiTableLogBuffer: TableLogBuffer, interactor: WifiInteractor, @Application private val scope: CoroutineScope, - statusBarPipelineFlags: StatusBarPipelineFlags, wifiConstants: WifiConstants, ) : WifiViewModelCommon { /** Returns the icon to use based on the given network. */ @@ -183,6 +185,8 @@ constructor( override val isAirplaneSpacerVisible: Flow<Boolean> = airplaneModeViewModel.isAirplaneModeIconVisible + override val isSignalSpacerVisible: Flow<Boolean> = shouldShowSignalSpacerProvider.get() + companion object { @StringRes @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt index eccf02397a82..617e19200a0a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelCommon.kt @@ -39,4 +39,7 @@ interface WifiViewModelCommon { /** True if the airplane spacer view should be visible. */ val isAirplaneSpacerVisible: Flow<Boolean> + + /** True if the spacer between the wifi icon and the RAT icon should be visible. */ + val isSignalSpacerVisible: Flow<Boolean> } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 654ba04eba7a..1e63b2a4b3e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -21,6 +21,8 @@ import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN; import static android.os.BatteryManager.EXTRA_HEALTH; import static android.os.BatteryManager.EXTRA_PRESENT; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_QS; + import android.annotation.WorkerThread; import android.content.BroadcastReceiver; import android.content.Context; @@ -169,7 +171,8 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @Override public void setPowerSaveMode(boolean powerSave, View view) { if (powerSave) mPowerSaverStartView.set(new WeakReference<>(view)); - BatterySaverUtils.setPowerSaveMode(mContext, powerSave, /*needFirstTimeWarning*/ true); + BatterySaverUtils.setPowerSaveMode(mContext, powerSave, /*needFirstTimeWarning*/ true, + SAVER_ENABLED_QS); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index f1269f2b012a..673819b20e4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -38,14 +38,14 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; +import dagger.Lazy; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Objects; import javax.inject.Inject; -import dagger.Lazy; - /** */ @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java index e9f0dcb4eb51..928e0115287d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java @@ -61,6 +61,7 @@ import javax.inject.Inject; * Manages the user switcher on the Keyguard. */ @KeyguardUserSwitcherScope +@Deprecated public class KeyguardUserSwitcherController extends ViewController<KeyguardUserSwitcherView> { private static final String TAG = "KeyguardUserSwitcherController"; diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt index a20a5b2fdbbc..e819f946a6d6 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt @@ -31,6 +31,7 @@ import android.view.WindowManager import android.view.accessibility.AccessibilityManager import android.widget.ImageView import android.widget.TextView +import androidx.annotation.DimenRes import androidx.annotation.IdRes import androidx.annotation.VisibleForTesting import com.android.internal.widget.CachingIconView @@ -180,8 +181,9 @@ constructor( // Button val buttonView = currentView.requireViewById<TextView>(R.id.end_button) - if (newInfo.endItem is ChipbarEndItem.Button) { - TextViewBinder.bind(buttonView, newInfo.endItem.text) + val hasButton = newInfo.endItem is ChipbarEndItem.Button + if (hasButton) { + TextViewBinder.bind(buttonView, (newInfo.endItem as ChipbarEndItem.Button).text) val onClickListener = View.OnClickListener { clickedView -> @@ -196,6 +198,12 @@ constructor( buttonView.visibility = View.GONE } + currentView + .getInnerView() + .setEndPadding( + if (hasButton) R.dimen.chipbar_outer_padding_half else R.dimen.chipbar_outer_padding + ) + // ---- Overall accessibility ---- val iconDesc = newInfo.startIcon.icon.contentDescription val loadedIconDesc = @@ -309,6 +317,15 @@ constructor( viewUtil.setRectToViewWindowLocation(view, outRect) } + private fun View.setEndPadding(@DimenRes endPaddingDimen: Int) { + this.setPaddingRelative( + this.paddingStart, + this.paddingTop, + context.resources.getDimensionPixelSize(endPaddingDimen), + this.paddingBottom, + ) + } + private fun Boolean.visibleIfTrue(): Int { return if (this) { View.VISIBLE diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt index 6e58f2296c86..52f2d11f814e 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt @@ -18,7 +18,7 @@ package com.android.systemui.temporarydisplay.chipbar import android.os.VibrationEffect import android.view.View -import androidx.annotation.ColorRes +import androidx.annotation.AttrRes import com.android.systemui.R import com.android.systemui.common.shared.model.Text import com.android.systemui.common.shared.model.TintedIcon @@ -49,7 +49,9 @@ data class ChipbarInfo( override val priority: ViewPriority, ) : TemporaryViewInfo() { companion object { - @ColorRes val DEFAULT_ICON_TINT = R.color.chipbar_text_and_icon_color + // LINT.IfChange + @AttrRes val DEFAULT_ICON_TINT = com.android.internal.R.attr.materialColorOnSecondaryFixed + // LINT.ThenChange(systemui/res/layout/chipbar.xml) } } diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java index 05e566690f57..29f16c7b924a 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java +++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java @@ -272,10 +272,10 @@ public class SystemUIToast implements ToastPlugin.Toast { private static boolean showApplicationIcon(ApplicationInfo appInfo, PackageManager packageManager) { - if (hasFlag(appInfo.flags, FLAG_UPDATED_SYSTEM_APP)) { + if (hasFlag(appInfo.flags, FLAG_UPDATED_SYSTEM_APP | FLAG_SYSTEM)) { return packageManager.getLaunchIntentForPackage(appInfo.packageName) != null; } - return !hasFlag(appInfo.flags, FLAG_SYSTEM); + return true; } private static boolean hasFlag(int flags, int flag) { diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Dagger.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Dagger.kt new file mode 100644 index 000000000000..c587f2edd601 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Dagger.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.kotlin + +import dagger.Lazy +import kotlin.reflect.KProperty + +/** + * Extension operator that allows developers to use [dagger.Lazy] as a property delegate: + * ```kotlin + * class MyClass @Inject constructor( + * lazyDependency: dagger.Lazy<Foo>, + * ) { + * val dependency: Foo by lazyDependency + * } + * ``` + */ +operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = get() diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java index 209ea41fed61..58cffa761a66 100644 --- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java @@ -58,6 +58,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -418,6 +419,7 @@ public class GarbageMonitor implements Dumpable { @Inject public MemoryTile( QSHost host, + QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, @@ -428,7 +430,7 @@ public class GarbageMonitor implements Dumpable { GarbageMonitor monitor, PanelInteractor panelInteractor ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); gm = monitor; mPanelInteractor = panelInteractor; diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java index e4ebea9483c7..972895d4a192 100644 --- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java @@ -62,6 +62,7 @@ public class DelayedWakeLock implements WakeLock { */ public static class Builder { private final Context mContext; + private final WakeLockLogger mLogger; private String mTag; private Handler mHandler; @@ -69,8 +70,9 @@ public class DelayedWakeLock implements WakeLock { * Constructor for DelayedWakeLock.Builder */ @Inject - public Builder(Context context) { + public Builder(Context context, WakeLockLogger logger) { mContext = context; + mLogger = logger; } /** @@ -95,7 +97,7 @@ public class DelayedWakeLock implements WakeLock { * Build the DelayedWakeLock. */ public DelayedWakeLock build() { - return new DelayedWakeLock(mHandler, WakeLock.createPartial(mContext, mTag)); + return new DelayedWakeLock(mHandler, WakeLock.createPartial(mContext, mLogger, mTag)); } } } diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java index 283be867ffd9..dcc943531565 100644 --- a/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java @@ -33,7 +33,7 @@ public class KeepAwakeAnimationListener extends AnimatorListenerAdapter public KeepAwakeAnimationListener(Context context) { Assert.isMainThread(); if (sWakeLock == null) { - sWakeLock = WakeLock.createPartial(context, "animation"); + sWakeLock = WakeLock.createPartial(context, null, "animation"); } } diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java index f320d071b54f..6128feee8116 100644 --- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java @@ -29,8 +29,8 @@ import javax.inject.Inject; /** WakeLock wrapper for testability */ public interface WakeLock { - static final String TAG = "WakeLock"; - static final String REASON_WRAP = "wrap"; + String TAG = "WakeLock"; + String REASON_WRAP = "wrap"; /** * Default wake-lock timeout in milliseconds, to avoid battery regressions. @@ -57,22 +57,32 @@ public interface WakeLock { /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */ Runnable wrap(Runnable r); - static WakeLock createPartial(Context context, String tag) { - return createPartial(context, tag, DEFAULT_MAX_TIMEOUT); + /** + * Creates a {@link WakeLock} that has a default release timeout and flags. + * @see android.os.PowerManager.WakeLock#acquire(long) + */ + static WakeLock createPartial(Context context, WakeLockLogger logger, String tag) { + return createPartial(context, logger, tag, DEFAULT_MAX_TIMEOUT); } /** - * Creates a {@link WakeLock} that has a default release timeout. - * @see android.os.PowerManager.WakeLock#acquire(long) */ - static WakeLock createPartial(Context context, String tag, long maxTimeout) { - return wrap(createWakeLockInner(context, tag, DEFAULT_LEVELS_AND_FLAGS), maxTimeout); + * Creates a {@link WakeLock} that has default flags. + * @see android.os.PowerManager.WakeLock#acquire(long) + */ + static WakeLock createPartial( + Context context, WakeLockLogger logger, String tag, long maxTimeout) { + return wrap( + createWakeLockInner(context, tag, DEFAULT_LEVELS_AND_FLAGS), logger, maxTimeout); } /** - * Creates a {@link WakeLock} that has a default release timeout and flags. + * Creates a {@link WakeLock}. + * @see android.os.PowerManager.WakeLock#acquire(long) */ - static WakeLock createWakeLock(Context context, String tag, int flags, long maxTimeout) { - return wrap(createWakeLockInner(context, tag, flags), maxTimeout); + static WakeLock createWakeLock( + Context context, WakeLockLogger logger, String tag, int flags, long maxTimeout) { + return wrap( + createWakeLockInner(context, tag, flags), logger, maxTimeout); } @VisibleForTesting @@ -100,14 +110,19 @@ public interface WakeLock { * @return The new wake lock. */ @VisibleForTesting - static WakeLock wrap(final PowerManager.WakeLock inner, long maxTimeout) { + static WakeLock wrap( + final PowerManager.WakeLock inner, WakeLockLogger logger, long maxTimeout) { return new WakeLock() { private final HashMap<String, Integer> mActiveClients = new HashMap<>(); /** @see PowerManager.WakeLock#acquire() */ public void acquire(String why) { mActiveClients.putIfAbsent(why, 0); - mActiveClients.put(why, mActiveClients.get(why) + 1); + int count = mActiveClients.get(why) + 1; + mActiveClients.put(why, count); + if (logger != null) { + logger.logAcquire(inner, why, count); + } inner.acquire(maxTimeout); } @@ -118,10 +133,15 @@ public interface WakeLock { Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why, new Throwable()); return; - } else if (count == 1) { + } + count--; + if (count == 0) { mActiveClients.remove(why); } else { - mActiveClients.put(why, count - 1); + mActiveClients.put(why, count); + } + if (logger != null) { + logger.logRelease(inner, why, count); } inner.release(); } @@ -133,7 +153,7 @@ public interface WakeLock { @Override public String toString() { - return "active clients= " + mActiveClients.toString(); + return "active clients= " + mActiveClients; } }; } @@ -143,13 +163,15 @@ public interface WakeLock { */ class Builder { private final Context mContext; + private final WakeLockLogger mLogger; private String mTag; private int mLevelsAndFlags = DEFAULT_LEVELS_AND_FLAGS; private long mMaxTimeout = DEFAULT_MAX_TIMEOUT; @Inject - public Builder(Context context) { + public Builder(Context context, WakeLockLogger logger) { mContext = context; + mLogger = logger; } public Builder setTag(String tag) { @@ -168,7 +190,7 @@ public interface WakeLock { } public WakeLock build() { - return WakeLock.createWakeLock(mContext, mTag, mLevelsAndFlags, mMaxTimeout); + return WakeLock.createWakeLock(mContext, mLogger, mTag, mLevelsAndFlags, mMaxTimeout); } } } diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java new file mode 100644 index 000000000000..59cb0525a7e9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLog.java @@ -0,0 +1,33 @@ +/* + * 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.util.wakelock; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +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 BroadcastSender-related messages. */ +@Qualifier +@Documented +@Retention(RUNTIME) +public @interface WakeLockLog { +} diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt new file mode 100644 index 000000000000..951903dc29bd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.wakelock + +import android.os.PowerManager +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import javax.inject.Inject + +class WakeLockLogger @Inject constructor(@WakeLockLog private val buffer: LogBuffer) { + fun logAcquire(wakeLock: PowerManager.WakeLock, reason: String, count: Int) { + buffer.log( + WakeLock.TAG, + LogLevel.DEBUG, + { + str1 = wakeLock.tag + str2 = reason + int1 = count + }, + { "Acquire tag=$str1 reason=$str2 count=$int1" } + ) + } + + fun logRelease(wakeLock: PowerManager.WakeLock, reason: String, count: Int) { + buffer.log( + WakeLock.TAG, + LogLevel.DEBUG, + { + str1 = wakeLock.tag + str2 = reason + int1 = count + }, + { "Release tag=$str1 reason=$str2 count=$int1" } + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java index 35af44442ca9..db7fa14b4cff 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java @@ -16,20 +16,34 @@ package com.android.systemui.volume; +import static android.app.PendingIntent.FLAG_IMMUTABLE; + import android.annotation.StringRes; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; -import android.os.CountDownTimer; +import android.provider.Settings; import android.util.Log; import android.view.KeyEvent; import android.view.WindowManager; import com.android.internal.annotations.GuardedBy; +import com.android.internal.messages.nano.SystemMessageProto; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.statusbar.phone.SystemUIDialog; +import com.android.systemui.util.NotificationChannels; +import com.android.systemui.util.concurrency.DelayableExecutor; + +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; /** * A class that implements the four Computed Sound Dose-related warnings defined in {@link AudioManager}: @@ -53,34 +67,58 @@ import com.android.systemui.statusbar.phone.SystemUIDialog; * communication between the native audio framework that implements the dose computation and the * audio service. */ -public abstract class CsdWarningDialog extends SystemUIDialog +public class CsdWarningDialog extends SystemUIDialog implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { private static final String TAG = Util.logTag(CsdWarningDialog.class); private static final int KEY_CONFIRM_ALLOWED_AFTER_MS = 1000; // milliseconds // time after which action is taken when the user hasn't ack'd or dismissed the dialog - private static final int NO_ACTION_TIMEOUT_MS = 5000; + public static final int NO_ACTION_TIMEOUT_MS = 5000; private final Context mContext; private final AudioManager mAudioManager; private final @AudioManager.CsdWarning int mCsdWarning; private final Object mTimerLock = new Object(); + /** * Timer to keep track of how long the user has before an action (here volume reduction) is * taken on their behalf. */ @GuardedBy("mTimerLock") - private final CountDownTimer mNoUserActionTimer; + private Runnable mNoUserActionRunnable; + private Runnable mCancelScheduledNoUserActionRunnable = null; + + private final DelayableExecutor mDelayableExecutor; + private NotificationManager mNotificationManager; + private Runnable mOnCleanup; private long mShowTime; - public CsdWarningDialog(@AudioManager.CsdWarning int csdWarning, Context context, - AudioManager audioManager) { + /** + * To inject dependencies and allow for easier testing + */ + @AssistedFactory + public interface Factory { + /** + * Create a dialog object + */ + CsdWarningDialog create(int csdWarning, Runnable onCleanup); + } + + @AssistedInject + public CsdWarningDialog(@Assisted @AudioManager.CsdWarning int csdWarning, Context context, + AudioManager audioManager, NotificationManager notificationManager, + @Background DelayableExecutor delayableExecutor, @Assisted Runnable onCleanup) { super(context); mCsdWarning = csdWarning; mContext = context; mAudioManager = audioManager; + mNotificationManager = notificationManager; + mOnCleanup = onCleanup; + + mDelayableExecutor = delayableExecutor; + getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); setShowForAllUsers(true); setMessage(mContext.getString(getStringForWarning(csdWarning))); @@ -95,25 +133,24 @@ public abstract class CsdWarningDialog extends SystemUIDialog Context.RECEIVER_EXPORTED_UNAUDITED); if (csdWarning == AudioManager.CSD_WARNING_DOSE_REACHED_1X) { - mNoUserActionTimer = new CountDownTimer(NO_ACTION_TIMEOUT_MS, NO_ACTION_TIMEOUT_MS) { - @Override - public void onTick(long millisUntilFinished) { } - - @Override - public void onFinish() { - if (mCsdWarning == AudioManager.CSD_WARNING_DOSE_REACHED_1X) { - // unlike on the 5x dose repeat, level is only reduced to RS1 - // when the warning is not acknowledged quick enough - mAudioManager.lowerVolumeToRs1(); - } + mNoUserActionRunnable = () -> { + if (mCsdWarning == AudioManager.CSD_WARNING_DOSE_REACHED_1X) { + // unlike on the 5x dose repeat, level is only reduced to RS1 when the warning + // is not acknowledged quickly enough + mAudioManager.lowerVolumeToRs1(); + sendNotification(); } }; } else { - mNoUserActionTimer = null; + mNoUserActionRunnable = null; } } - protected abstract void cleanUp(); + private void cleanUp() { + if (mOnCleanup != null) { + mOnCleanup.run(); + } + } // NOT overriding onKeyDown as we're not allowing a dismissal on any key other than // VOLUME_DOWN, and for this, we don't need to track if it's the start of a new @@ -149,25 +186,21 @@ public abstract class CsdWarningDialog extends SystemUIDialog } @Override - protected void onStart() { - super.onStart(); + protected void start() { mShowTime = System.currentTimeMillis(); synchronized (mTimerLock) { - if (mNoUserActionTimer != null) { - new Thread(() -> { - synchronized (mTimerLock) { - mNoUserActionTimer.start(); - } - }).start(); + if (mNoUserActionRunnable != null) { + mCancelScheduledNoUserActionRunnable = mDelayableExecutor.executeDelayed( + mNoUserActionRunnable, NO_ACTION_TIMEOUT_MS); } } } @Override - protected void onStop() { + protected void stop() { synchronized (mTimerLock) { - if (mNoUserActionTimer != null) { - mNoUserActionTimer.cancel(); + if (mCancelScheduledNoUserActionRunnable != null) { + mCancelScheduledNoUserActionRunnable.run(); } } } @@ -212,4 +245,32 @@ public abstract class CsdWarningDialog extends SystemUIDialog Log.e(TAG, "Invalid CSD warning event " + csdWarning, new Exception()); return com.android.internal.R.string.csd_dose_reached_warning; } + + + /** + * In case user did not respond to the dialog, they still need to know volume was lowered. + */ + private void sendNotification() { + Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS); + PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, + FLAG_IMMUTABLE); + + String text = mContext.getString(R.string.csd_system_lowered_text); + String title = mContext.getString(R.string.csd_lowered_title); + + Notification.Builder builder = + new Notification.Builder(mContext, NotificationChannels.ALERTS) + .setSmallIcon(R.drawable.hearing) + .setContentTitle(title) + .setContentText(text) + .setContentIntent(pendingIntent) + .setStyle(new Notification.BigTextStyle().bigText(text)) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setLocalOnly(true) + .setAutoCancel(true) + .setCategory(Notification.CATEGORY_SYSTEM); + + mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_CSD_LOWER_AUDIO, + builder.build()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java index 5b188b24d7dd..d42b964d593b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java @@ -95,8 +95,7 @@ abstract public class SafetyWarningDialog extends SystemUIDialog } @Override - protected void onStart() { - super.onStart(); + protected void start() { mShowTime = System.currentTimeMillis(); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 95cc12a48bb2..aa26e688c490 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -263,6 +263,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private final ConfigurationController mConfigurationController; private final MediaOutputDialogFactory mMediaOutputDialogFactory; private final VolumePanelFactory mVolumePanelFactory; + private final CsdWarningDialog.Factory mCsdWarningDialogFactory; private final ActivityStarter mActivityStarter; private boolean mShowing; @@ -311,6 +312,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, InteractionJankMonitor interactionJankMonitor, DeviceConfigProxy deviceConfigProxy, Executor executor, + CsdWarningDialog.Factory csdWarningDialogFactory, DumpManager dumpManager) { mContext = new ContextThemeWrapper(context, R.style.volume_dialog_theme); @@ -322,6 +324,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mConfigurationController = configurationController; mMediaOutputDialogFactory = mediaOutputDialogFactory; mVolumePanelFactory = volumePanelFactory; + mCsdWarningDialogFactory = csdWarningDialogFactory; mActivityStarter = activityStarter; mShowActiveStreamOnly = showActiveStreamOnly(); mHasSeenODICaptionsTooltip = @@ -2084,21 +2087,21 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, rescheduleTimeoutH(); } - private void showCsdWarningH(int csdWarning, int durationMs) { + @VisibleForTesting void showCsdWarningH(int csdWarning, int durationMs) { synchronized (mSafetyWarningLock) { + if (mCsdDialog != null) { return; } - mCsdDialog = new CsdWarningDialog(csdWarning, - mContext, mController.getAudioManager()) { - @Override - protected void cleanUp() { - synchronized (mSafetyWarningLock) { - mCsdDialog = null; - } - recheckH(null); + + final Runnable cleanUp = () -> { + synchronized (mSafetyWarningLock) { + mCsdDialog = null; } + recheckH(null); }; + + mCsdDialog = mCsdWarningDialogFactory.create(csdWarning, cleanUp); mCsdDialog.show(); } recheckH(null); @@ -2340,6 +2343,13 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, } } + @VisibleForTesting + void clearInternalHandleAfterTest() { + if (mHandler != null) { + mHandler.removeCallbacksAndMessages(null); + } + } + private final class CustomDialog extends Dialog implements DialogInterface { public CustomDialog(Context context) { super(context, R.style.volume_dialog_theme); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java index 87a167baf9bf..96936e3eb5f0 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java @@ -196,16 +196,14 @@ public class VolumePanelDialog extends SystemUIDialog implements LifecycleOwner } @Override - protected void onStart() { - super.onStart(); + protected void start() { Log.d(TAG, "onStart"); mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED); mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED); } @Override - protected void onStop() { - super.onStop(); + protected void stop() { Log.d(TAG, "onStop"); mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java index 0ab6c690e1e1..14d3ca334073 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java @@ -30,17 +30,18 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.volume.CsdWarningDialog; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.volume.VolumeDialogComponent; import com.android.systemui.volume.VolumeDialogImpl; import com.android.systemui.volume.VolumePanelFactory; -import java.util.concurrent.Executor; - import dagger.Binds; import dagger.Module; import dagger.Provides; +import java.util.concurrent.Executor; + /** Dagger Module for code in the volume package. */ @Module @@ -63,6 +64,7 @@ public interface VolumeModule { InteractionJankMonitor interactionJankMonitor, DeviceConfigProxy deviceConfigProxy, @Main Executor executor, + CsdWarningDialog.Factory csdFactory, DumpManager dumpManager) { VolumeDialogImpl impl = new VolumeDialogImpl( context, @@ -76,6 +78,7 @@ public interface VolumeModule { interactionJankMonitor, deviceConfigProxy, executor, + csdFactory, dumpManager); impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false); impl.setAutomute(true); diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index 08f7eaee3011..a4b093d1832a 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java @@ -241,8 +241,8 @@ public class BubblesManager { // Store callback in a field so it won't get GC'd mStatusBarWindowCallback = - (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded, - isDreaming) -> + (keyguardShowing, keyguardOccluded, keyguardGoingAway, bouncerShowing, isDozing, + panelExpanded, isDreaming) -> mBubbles.onNotificationPanelExpandedChanged(panelExpanded); notificationShadeWindowController.registerCallback(mStatusBarWindowCallback); diff --git a/packages/SystemUI/tests/robolectric/config/robolectric.properties b/packages/SystemUI/tests/robolectric/config/robolectric.properties index 2a75bd98bfe8..438d54c5a200 100644 --- a/packages/SystemUI/tests/robolectric/config/robolectric.properties +++ b/packages/SystemUI/tests/robolectric/config/robolectric.properties @@ -13,4 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -sdk=NEWEST_SDK
\ No newline at end of file +sdk=NEWEST_SDK +shadows=\ + com.android.systemui.testutils.shadow.ShadowLockPatternUtils \ + com.android.systemui.testutils.shadow.ShadowTestableLooper
\ No newline at end of file diff --git a/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowLockPatternUtils.java b/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowLockPatternUtils.java new file mode 100644 index 000000000000..b248ce356394 --- /dev/null +++ b/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowLockPatternUtils.java @@ -0,0 +1,33 @@ +/* + * 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.testutils.shadow; + +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; + +import com.android.internal.widget.LockPatternUtils; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(LockPatternUtils.class) +public class ShadowLockPatternUtils { + + @Implementation + protected int getCredentialTypeForUser(int userHandle) { + return CREDENTIAL_TYPE_NONE; + } +} diff --git a/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowTestableLooper.java b/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowTestableLooper.java new file mode 100644 index 000000000000..a9b8bc044554 --- /dev/null +++ b/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowTestableLooper.java @@ -0,0 +1,37 @@ +/* + * 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.testutils.shadow; + +import static org.robolectric.Shadows.shadowOf; + +import android.testing.TestableLooper; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.RealObject; + +@Implements(TestableLooper.class) +public class ShadowTestableLooper { + @RealObject private TestableLooper mRealTestableLooper; + /** + * Process messages in the queue until no more are found. + */ + @Implementation + protected void processAllMessages() { + shadowOf(mRealTestableLooper.getLooper()).idle(); + } +} diff --git a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRule2.java b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRule2.java deleted file mode 100644 index e93e86291535..000000000000 --- a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRule2.java +++ /dev/null @@ -1,174 +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 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 index bddd60b5970a..e7738aff6278 100644 --- a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleTest.kt +++ b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleTest.kt @@ -30,7 +30,7 @@ import org.junit.runner.RunWith @RunWithLooper(setAsMainLooper = true) class AnimatorTestRuleTest : SysuiTestCase() { - @get:Rule val animatorTestRule = AnimatorTestRule2() + @get:Rule val animatorTestRule = AnimatorTestRule() @Test fun testA() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java index ecf7e0d46373..5557efa97e3e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java @@ -38,8 +38,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.pm.PackageManager; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; import android.provider.Settings; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; @@ -52,6 +50,8 @@ import android.text.TextUtils; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository; +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel; import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -88,8 +88,7 @@ public class CarrierTextManagerTest extends SysuiTestCase { private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0, TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_CARRIER_ID, 0xFFFFFF, "", DATA_ROAMING_ENABLE, null, null, null, null, false, null, ""); - @Mock - private WifiManager mWifiManager; + private FakeWifiRepository mWifiRepository = new FakeWifiRepository(); @Mock private WakefulnessLifecycle mWakefulnessLifecycle; @Mock @@ -121,7 +120,6 @@ public class CarrierTextManagerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); - mContext.addMockSystemService(WifiManager.class, mWifiManager); mContext.addMockSystemService(PackageManager.class, mPackageManager); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true); mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); @@ -144,7 +142,7 @@ public class CarrierTextManagerTest extends SysuiTestCase { when(mTelephonyManager.getActiveModemCount()).thenReturn(3); mCarrierTextManager = new CarrierTextManager.Builder( - mContext, mContext.getResources(), mWifiManager, + mContext, mContext.getResources(), mWifiRepository, mTelephonyManager, mTelephonyListenerManager, mWakefulnessLifecycle, mMainExecutor, mBgExecutor, mKeyguardUpdateMonitor) .setShowAirplaneMode(true) @@ -364,7 +362,11 @@ public class CarrierTextManagerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( TelephonyManager.SIM_STATE_READY); when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list); - mockWifi(); + + assertFalse(mWifiRepository.isWifiConnectedWithValidSsid()); + mWifiRepository.setWifiNetwork( + new WifiNetworkModel.Active(0, false, 0, "", false, false, null)); + assertTrue(mWifiRepository.isWifiConnectedWithValidSsid()); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ServiceState ss = mock(ServiceState.class); @@ -385,13 +387,6 @@ public class CarrierTextManagerTest extends SysuiTestCase { assertNotEquals(AIRPLANE_MODE_TEXT, captor.getValue().carrierText); } - private void mockWifi() { - when(mWifiManager.isWifiEnabled()).thenReturn(true); - WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.getBSSID()).thenReturn(""); - when(mWifiManager.getConnectionInfo()).thenReturn(wifiInfo); - } - @Test public void testCreateInfo_noSubscriptions() { reset(mCarrierTextCallback); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index 2f627cb5d9d7..fc906dedfa1d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -48,8 +48,10 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.plugins.ClockAnimations; import com.android.systemui.plugins.ClockController; import com.android.systemui.plugins.ClockEvents; +import com.android.systemui.plugins.ClockFaceConfig; import com.android.systemui.plugins.ClockFaceController; import com.android.systemui.plugins.ClockFaceEvents; +import com.android.systemui.plugins.ClockTickRate; import com.android.systemui.plugins.log.LogBuffer; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.clocks.AnimatableClockView; @@ -185,6 +187,10 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { when(mClockController.getAnimations()).thenReturn(mClockAnimations); when(mClockRegistry.createCurrentClock()).thenReturn(mClockController); when(mClockEventController.getClock()).thenReturn(mClockController); + when(mSmallClockController.getConfig()) + .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false)); + when(mLargeClockController.getConfig()) + .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false)); mSliceView = new View(getContext()); when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView); @@ -367,6 +373,28 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { } @Test + public void testChangeClockDateWeatherEnabled_SetsDateWeatherViewVisibility() { + ArgumentCaptor<ClockRegistry.ClockChangeListener> listenerArgumentCaptor = + ArgumentCaptor.forClass(ClockRegistry.ClockChangeListener.class); + when(mSmartspaceController.isEnabled()).thenReturn(true); + when(mSmartspaceController.isDateWeatherDecoupled()).thenReturn(true); + when(mSmartspaceController.isWeatherEnabled()).thenReturn(true); + mController.init(); + mExecutor.runAllReady(); + assertEquals(View.VISIBLE, mFakeDateView.getVisibility()); + + when(mSmallClockController.getConfig()) + .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true)); + when(mLargeClockController.getConfig()) + .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true)); + verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture()); + listenerArgumentCaptor.getValue().onCurrentClockChanged(); + + mExecutor.runAllReady(); + assertEquals(View.INVISIBLE, mFakeDateView.getVisibility()); + } + + @Test public void testGetClock_nullClock_returnsNull() { when(mClockEventController.getClock()).thenReturn(null); assertNull(mController.getClock()); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index d760189bcfd6..f4df26dec89e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -16,8 +16,6 @@ package com.android.keyguard; -import static android.view.WindowInsets.Type.ime; - import static com.android.keyguard.KeyguardSecurityContainer.MODE_DEFAULT; import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED; @@ -29,9 +27,9 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -67,6 +65,7 @@ import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; @@ -163,6 +162,10 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Captor private ArgumentCaptor<KeyguardSecurityContainer.SwipeListener> mSwipeListenerArgumentCaptor; + @Captor + private ArgumentCaptor<KeyguardSecurityViewFlipperController.OnViewInflatedCallback> + mOnViewInflatedCallbackArgumentCaptor; + private KeyguardSecurityContainerController mKeyguardSecurityContainerController; private KeyguardPasswordViewController mKeyguardPasswordViewController; private KeyguardPasswordView mKeyguardPasswordView; @@ -183,8 +186,6 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class))) .thenReturn(mAdminSecondaryLockScreenController); when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); - when(mKeyguardSecurityViewFlipperController.getSecurityView(any(SecurityMode.class), - any(KeyguardSecurityCallback.class))).thenReturn(mInputViewController); mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate( R.layout.keyguard_password_view, null)); when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper); @@ -208,7 +209,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mConfigurationController, mFalsingCollector, mFalsingManager, mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate, - mTelephonyManager, mViewMediatorCallback, mAudioManager); + mTelephonyManager, mViewMediatorCallback, mAudioManager, + mock(KeyguardFaceAuthInteractor.class)); } @Test @@ -228,29 +230,19 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mKeyguardSecurityContainerController.showSecurityScreen(mode); if (mode == SecurityMode.Invalid) { verify(mKeyguardSecurityViewFlipperController, never()).getSecurityView( - any(SecurityMode.class), any(KeyguardSecurityCallback.class)); + any(SecurityMode.class), any(KeyguardSecurityCallback.class), any( + KeyguardSecurityViewFlipperController.OnViewInflatedCallback.class) + ); } else { verify(mKeyguardSecurityViewFlipperController).getSecurityView( - eq(mode), any(KeyguardSecurityCallback.class)); + eq(mode), any(KeyguardSecurityCallback.class), any( + KeyguardSecurityViewFlipperController.OnViewInflatedCallback.class) + ); } } } @Test - public void startDisappearAnimation_animatesKeyboard() { - when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn( - SecurityMode.Password); - when(mKeyguardSecurityViewFlipperController.getSecurityView( - eq(SecurityMode.Password), any(KeyguardSecurityCallback.class))) - .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); - mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); - - mKeyguardSecurityContainerController.startDisappearAnimation(null); - verify(mWindowInsetsController).controlWindowInsetsAnimation( - eq(ime()), anyLong(), any(), any(), any()); - } - - @Test public void onResourcesUpdate_callsThroughOnRotationChange() { clearInvocations(mView); @@ -298,9 +290,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Test public void showSecurityScreen_oneHandedMode_flagDisabled_noOneHandedMode() { mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, false); - when(mKeyguardSecurityViewFlipperController.getSecurityView( - eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) - .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); + setupGetSecurityView(SecurityMode.Pattern); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager), @@ -312,11 +302,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Test public void showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode() { mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true); - when(mKeyguardSecurityViewFlipperController.getSecurityView( - eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class))) - .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); - - mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); + setupGetSecurityView(SecurityMode.Pattern); verify(mView).initMode(eq(MODE_ONE_HANDED), eq(mGlobalSettings), eq(mFalsingManager), eq(mUserSwitcherController), any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class), @@ -326,9 +312,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Test public void showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() { mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true); - setupGetSecurityView(); + setupGetSecurityView(SecurityMode.Password); - mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager), eq(mUserSwitcherController), any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class), @@ -340,17 +325,18 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { ArgumentCaptor<KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback> captor = ArgumentCaptor.forClass( KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class); + setupGetSecurityView(SecurityMode.Password); - setupGetSecurityView(); - - mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); verify(mView).initMode(anyInt(), any(GlobalSettings.class), any(FalsingManager.class), any(UserSwitcherController.class), captor.capture(), eq(mFalsingA11yDelegate)); captor.getValue().showUnlockToContinueMessage(); + getViewControllerImmediately(); verify(mKeyguardPasswordViewControllerMock).showMessage( - getContext().getString(R.string.keyguard_unlock_to_continue), null); + /* message= */ getContext().getString(R.string.keyguard_unlock_to_continue), + /* colorState= */ null, + /* animated= */ true); } @Test @@ -453,7 +439,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { KeyguardSecurityContainer.SwipeListener registeredSwipeListener = getRegisteredSwipeListener(); when(mKeyguardUpdateMonitor.isFaceDetectionRunning()).thenReturn(false); - setupGetSecurityView(); + setupGetSecurityView(SecurityMode.Password); registeredSwipeListener.onSwipeUp(); @@ -479,11 +465,14 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { getRegisteredSwipeListener(); when(mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)) .thenReturn(true); - setupGetSecurityView(); + setupGetSecurityView(SecurityMode.Password); + clearInvocations(mKeyguardSecurityViewFlipperController); registeredSwipeListener.onSwipeUp(); + getViewControllerImmediately(); - verify(mKeyguardPasswordViewControllerMock).showMessage(null, null); + verify(mKeyguardPasswordViewControllerMock).showMessage(/* message= */ + null, /* colorState= */ null, /* animated= */ true); } @Test @@ -492,11 +481,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { getRegisteredSwipeListener(); when(mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)) .thenReturn(false); - setupGetSecurityView(); + setupGetSecurityView(SecurityMode.Password); registeredSwipeListener.onSwipeUp(); - verify(mKeyguardPasswordViewControllerMock, never()).showMessage(null, null); + verify(mKeyguardPasswordViewControllerMock, never()).showMessage(/* message= */ + null, /* colorState= */ null, /* animated= */ true); } @Test @@ -510,10 +500,15 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { configurationListenerArgumentCaptor.getValue().onDensityOrFontScaleChanged(); - verify(mView).onDensityOrFontScaleChanged(); verify(mKeyguardSecurityViewFlipperController).clearViews(); - verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN), - any(KeyguardSecurityCallback.class)); + verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView( + eq(SecurityMode.PIN), + any(KeyguardSecurityCallback.class), + mOnViewInflatedCallbackArgumentCaptor.capture()); + + mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(mInputViewController); + + verify(mView).onDensityOrFontScaleChanged(); } @Test @@ -527,12 +522,17 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { configurationListenerArgumentCaptor.getValue().onThemeChanged(); - verify(mView).reloadColors(); verify(mKeyguardSecurityViewFlipperController).clearViews(); - verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN), - any(KeyguardSecurityCallback.class)); + verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView( + eq(SecurityMode.PIN), + any(KeyguardSecurityCallback.class), + mOnViewInflatedCallbackArgumentCaptor.capture()); + + mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(mInputViewController); + verify(mView).reset(); verify(mKeyguardSecurityViewFlipperController).reset(); + verify(mView).reloadColors(); } @Test @@ -546,10 +546,15 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { configurationListenerArgumentCaptor.getValue().onUiModeChanged(); - verify(mView).reloadColors(); verify(mKeyguardSecurityViewFlipperController).clearViews(); - verify(mKeyguardSecurityViewFlipperController).getSecurityView(eq(SecurityMode.PIN), - any(KeyguardSecurityCallback.class)); + verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView( + eq(SecurityMode.PIN), + any(KeyguardSecurityCallback.class), + mOnViewInflatedCallbackArgumentCaptor.capture()); + + mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(mInputViewController); + + verify(mView).reloadColors(); } @Test @@ -612,6 +617,11 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Test public void testOnStartingToHide() { mKeyguardSecurityContainerController.onStartingToHide(); + verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class), + any(KeyguardSecurityCallback.class), + mOnViewInflatedCallbackArgumentCaptor.capture()); + + mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(mInputViewController); verify(mInputViewController).onStartingToHide(); } @@ -671,26 +681,17 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { verify(mView).updatePositionByTouchX(1.0f); } - - @Test - public void testReinflateViewFlipper() { - mKeyguardSecurityContainerController.reinflateViewFlipper(() -> {}); - verify(mKeyguardSecurityViewFlipperController).clearViews(); - verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class), - any(KeyguardSecurityCallback.class)); - } - @Test public void testReinflateViewFlipper_asyncBouncerFlagOn() { when(mFeatureFlags.isEnabled(Flags.ASYNC_INFLATE_BOUNCER)).thenReturn(true); - KeyguardSecurityViewFlipperController.OnViewInflatedListener onViewInflatedListener = - () -> { + KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback = + controller -> { }; - mKeyguardSecurityContainerController.reinflateViewFlipper(onViewInflatedListener); + mKeyguardSecurityContainerController.reinflateViewFlipper(onViewInflatedCallback); verify(mKeyguardSecurityViewFlipperController).clearViews(); verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView( any(SecurityMode.class), - any(KeyguardSecurityCallback.class), eq(onViewInflatedListener)); + any(KeyguardSecurityCallback.class), eq(onViewInflatedCallback)); } @Test @@ -713,14 +714,17 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { return mSwipeListenerArgumentCaptor.getValue(); } - private void attachView() { - mKeyguardSecurityContainerController.onViewAttached(); - verify(mKeyguardUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallback.capture()); + private void setupGetSecurityView(SecurityMode securityMode) { + mKeyguardSecurityContainerController.showSecurityScreen(securityMode); + getViewControllerImmediately(); } - private void setupGetSecurityView() { - when(mKeyguardSecurityViewFlipperController.getSecurityView( - any(), any(KeyguardSecurityCallback.class))) - .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewControllerMock); + private void getViewControllerImmediately() { + verify(mKeyguardSecurityViewFlipperController, atLeastOnce()).getSecurityView( + any(SecurityMode.class), any(), + mOnViewInflatedCallbackArgumentCaptor.capture()); + mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated( + (KeyguardInputViewController) mKeyguardPasswordViewControllerMock); + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index eaf7b1ec2100..cd187540ba74 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -78,8 +78,6 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { private KeyguardSecurityCallback mKeyguardSecurityCallback; @Mock private FeatureFlags mFeatureFlags; - @Mock - private ViewMediatorCallback mViewMediatorCallback; private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController; @@ -96,7 +94,7 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView, mLayoutInflater, mAsyncLayoutInflater, mKeyguardSecurityViewControllerFactory, - mEmergencyButtonControllerFactory, mFeatureFlags, mViewMediatorCallback); + mEmergencyButtonControllerFactory, mFeatureFlags); } @Test @@ -108,17 +106,29 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { reset(mLayoutInflater); when(mLayoutInflater.inflate(anyInt(), eq(mView), eq(false))) .thenReturn(mInputView); - mKeyguardSecurityViewFlipperController.getSecurityView(mode, mKeyguardSecurityCallback); - if (mode == SecurityMode.Invalid || mode == SecurityMode.None) { - verify(mLayoutInflater, never()).inflate( - anyInt(), any(ViewGroup.class), anyBoolean()); - } else { - verify(mLayoutInflater).inflate(anyInt(), eq(mView), eq(false)); - } + mKeyguardSecurityViewFlipperController.getSecurityView(mode, mKeyguardSecurityCallback, + controller -> { + if (mode == SecurityMode.Invalid || mode == SecurityMode.None) { + verify(mLayoutInflater, never()).inflate( + anyInt(), any(ViewGroup.class), anyBoolean()); + } else { + verify(mLayoutInflater).inflate(anyInt(), eq(mView), eq(false)); + } + }); } } @Test + public void getSecurityView_NotInflated() { + mKeyguardSecurityViewFlipperController.clearViews(); + mKeyguardSecurityViewFlipperController.getSecurityView(SecurityMode.PIN, + mKeyguardSecurityCallback, + controller -> {}); + verify(mAsyncLayoutInflater).inflate(anyInt(), eq(mView), any( + AsyncLayoutInflater.OnInflateFinishedListener.class)); + } + + @Test public void asynchronouslyInflateView() { mKeyguardSecurityViewFlipperController.asynchronouslyInflateView(SecurityMode.PIN, mKeyguardSecurityCallback, null); @@ -136,7 +146,6 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { argumentCaptor.getValue().onInflateFinished( LayoutInflater.from(getContext()).inflate(R.layout.keyguard_password_view, null), R.layout.keyguard_password_view, mView); - verify(mViewMediatorCallback).setNeedsInput(anyBoolean()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index 48f7d924667e..2c1d2adb11ee 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -16,7 +16,6 @@ package com.android.keyguard; -import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -24,9 +23,13 @@ import static org.mockito.Mockito.when; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; +import com.android.internal.jank.InteractionJankMonitor; import com.android.keyguard.logging.KeyguardLogger; import com.android.systemui.SysuiTestCase; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.plugins.ClockConfig; import com.android.systemui.plugins.ClockController; +import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -45,26 +48,21 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) public class KeyguardStatusViewControllerTest extends SysuiTestCase { - @Mock - private KeyguardStatusView mKeyguardStatusView; - @Mock - private KeyguardSliceViewController mKeyguardSliceViewController; - @Mock - private KeyguardClockSwitchController mKeyguardClockSwitchController; - @Mock - private KeyguardStateController mKeyguardStateController; - @Mock - private KeyguardUpdateMonitor mKeyguardUpdateMonitor; - @Mock - ConfigurationController mConfigurationController; - @Mock - DozeParameters mDozeParameters; - @Mock - ScreenOffAnimationController mScreenOffAnimationController; + @Mock private KeyguardStatusView mKeyguardStatusView; + @Mock private KeyguardSliceViewController mKeyguardSliceViewController; + @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; + @Mock private KeyguardStateController mKeyguardStateController; + @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock private ConfigurationController mConfigurationController; + @Mock private DozeParameters mDozeParameters; + @Mock private ScreenOffAnimationController mScreenOffAnimationController; + @Mock private KeyguardLogger mKeyguardLogger; + @Mock private KeyguardStatusViewController mControllerMock; + @Mock private FeatureFlags mFeatureFlags; + @Mock private InteractionJankMonitor mInteractionJankMonitor; + @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor; - @Mock - KeyguardLogger mKeyguardLogger; private KeyguardStatusViewController mController; @@ -81,7 +79,18 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase { mConfigurationController, mDozeParameters, mScreenOffAnimationController, - mKeyguardLogger); + mKeyguardLogger, + mFeatureFlags, + mInteractionJankMonitor) { + @Override + void setProperty( + AnimatableProperty property, + float value, + boolean animate) { + // Route into the mock version for verification + mControllerMock.setProperty(property, value, animate); + } + }; } @Test @@ -118,10 +127,32 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase { } @Test - public void getClock_forwardsToClockSwitch() { + public void updatePosition_primaryClockAnimation() { ClockController mockClock = mock(ClockController.class); when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock); + when(mockClock.getConfig()).thenReturn(new ClockConfig(false, false, true)); + + mController.updatePosition(10, 15, 20f, true); + + verify(mControllerMock).setProperty(AnimatableProperty.Y, 15f, true); + verify(mKeyguardClockSwitchController).updatePosition( + 10, 20f, KeyguardStatusViewController.CLOCK_ANIMATION_PROPERTIES, true); + verify(mControllerMock).setProperty(AnimatableProperty.SCALE_X, 1f, true); + verify(mControllerMock).setProperty(AnimatableProperty.SCALE_Y, 1f, true); + } + + @Test + public void updatePosition_alternateClockAnimation() { + ClockController mockClock = mock(ClockController.class); + when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock); + when(mockClock.getConfig()).thenReturn(new ClockConfig(false, true, true)); + + mController.updatePosition(10, 15, 20f, true); - assertEquals(mockClock, mController.getClockController()); + verify(mControllerMock).setProperty(AnimatableProperty.Y, 15f, true); + verify(mKeyguardClockSwitchController).updatePosition( + 10, 1f, KeyguardStatusViewController.CLOCK_ANIMATION_PROPERTIES, true); + verify(mControllerMock).setProperty(AnimatableProperty.SCALE_X, 20f, true); + verify(mControllerMock).setProperty(AnimatableProperty.SCALE_Y, 20f, true); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 08813a7fb48a..3eb9590c0b95 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -20,9 +20,12 @@ import static android.app.StatusBarManager.SESSION_KEYGUARD; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT; +import static android.hardware.biometrics.SensorProperties.STRENGTH_CONVENIENCE; +import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; import static android.hardware.face.FaceAuthenticateOptions.AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN; import static android.hardware.face.FaceAuthenticateOptions.AUTHENTICATE_REASON_STARTED_WAKING_UP; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON; +import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; @@ -41,6 +44,8 @@ import static com.android.systemui.statusbar.policy.DevicePostureController.DEVI import static com.google.common.truth.Truth.assertThat; +import static junit.framework.Assert.assertEquals; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -79,7 +84,6 @@ import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; -import android.hardware.biometrics.SensorProperties; import android.hardware.face.FaceAuthenticateOptions; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorProperties; @@ -283,33 +287,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @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); - mFingerprintSensorProperties = List.of( - new FingerprintSensorPropertiesInternal(1 /* sensorId */, - FingerprintSensorProperties.STRENGTH_STRONG, - 1 /* maxEnrollmentsPerUser */, - List.of(new ComponentInfoInternal("fingerprintSensor" /* componentId */, - "vendor/model/revision" /* hardwareVersion */, - "1.01" /* firmwareVersion */, - "00000001" /* serialNumber */, "" /* softwareVersion */)), - FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, - false /* resetLockoutRequiresHAT */)); - when(mFingerprintManager.isHardwareDetected()).thenReturn(true); - when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); - when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn( - mFingerprintSensorProperties); when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true); when(mUserManager.isPrimaryUser()).thenReturn(true); when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class)); when(mStrongAuthTracker - .isUnlockingWithBiometricAllowed(anyBoolean() /* isStrongBiometric */)) + .isUnlockingWithBiometricAllowed(anyBoolean() /* isClass3Biometric */)) .thenReturn(true); when(mTelephonyManager.getServiceStateForSubscriber(anyInt())) .thenReturn(new ServiceState()); @@ -346,20 +330,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { anyInt()); 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); + captureAuthenticatorsRegisteredCallbacks(); + setupFaceAuth(/* isClass3 */ false); + setupFingerprintAuth(/* isClass3 */ true); verify(mBiometricManager) .registerEnabledOnKeyguardCallback(mBiometricEnabledCallbackArgCaptor.capture()); @@ -381,8 +354,64 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mAuthController.areAllFingerprintAuthenticatorsRegistered()).thenReturn(true); } + private void captureAuthenticatorsRegisteredCallbacks() throws RemoteException { + 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); + } + + private void setupFaceAuth(boolean isClass3) throws RemoteException { + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mAuthController.isFaceAuthEnrolled(anyInt())).thenReturn(true); + mFaceSensorProperties = + List.of(createFaceSensorProperties(/* supportsFaceDetection = */ false, isClass3)); + when(mFaceManager.getSensorPropertiesInternal()).thenReturn(mFaceSensorProperties); + mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties); + assertEquals(isClass3, mKeyguardUpdateMonitor.isFaceClass3()); + } + + private void setupFingerprintAuth(boolean isClass3) throws RemoteException { + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + mFingerprintSensorProperties = List.of( + createFingerprintSensorPropertiesInternal(TYPE_UDFPS_OPTICAL, isClass3)); + when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn( + mFingerprintSensorProperties); + mFingerprintAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered( + mFingerprintSensorProperties); + assertEquals(isClass3, mKeyguardUpdateMonitor.isFingerprintClass3()); + } + + private FingerprintSensorPropertiesInternal createFingerprintSensorPropertiesInternal( + @FingerprintSensorProperties.SensorType int sensorType, + boolean isClass3) { + final List<ComponentInfoInternal> componentInfo = + List.of(new ComponentInfoInternal("fingerprintSensor" /* componentId */, + "vendor/model/revision" /* hardwareVersion */, + "1.01" /* firmwareVersion */, + "00000001" /* serialNumber */, "" /* softwareVersion */)); + return new FingerprintSensorPropertiesInternal( + FINGERPRINT_SENSOR_ID, + isClass3 ? STRENGTH_STRONG : STRENGTH_CONVENIENCE, + 1 /* maxEnrollmentsPerUser */, + componentInfo, + sensorType, + true /* resetLockoutRequiresHardwareAuthToken */); + } + @NonNull - private FaceSensorPropertiesInternal createFaceSensorProperties(boolean supportsFaceDetection) { + private FaceSensorPropertiesInternal createFaceSensorProperties( + boolean supportsFaceDetection, boolean isClass3) { final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, @@ -391,10 +420,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */, "vendor/version/revision" /* softwareVersion */)); - return new FaceSensorPropertiesInternal( - 0 /* id */, - FaceSensorProperties.STRENGTH_STRONG, + FACE_SENSOR_ID /* id */, + isClass3 ? STRENGTH_STRONG : STRENGTH_CONVENIENCE, 1 /* maxTemplatesAllowed */, componentInfo, FaceSensorProperties.TYPE_UNKNOWN, @@ -686,7 +714,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testUnlockingWithFaceAllowed_strongAuthTrackerUnlockingWithBiometricAllowed() { // GIVEN unlocking with biometric is allowed - strongAuthNotRequired(); + primaryAuthNotRequiredByStrongAuthTracker(); // THEN unlocking with face and fp is allowed Assert.assertTrue(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( @@ -706,12 +734,31 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void testUnlockingWithFaceAllowed_fingerprintLockout() { - // GIVEN unlocking with biometric is allowed - strongAuthNotRequired(); + public void class3FingerprintLockOut_lockOutClass1Face() throws RemoteException { + setupFaceAuth(/* isClass3 */ false); + setupFingerprintAuth(/* isClass3 */ true); + + // GIVEN primary auth is not required by StrongAuthTracker + primaryAuthNotRequiredByStrongAuthTracker(); + + // WHEN fingerprint (class 3) is lock out + fingerprintErrorTemporaryLockOut(); + + // THEN unlocking with face is not allowed + Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + BiometricSourceType.FACE)); + } + + @Test + public void class3FingerprintLockOut_lockOutClass3Face() throws RemoteException { + setupFaceAuth(/* isClass3 */ true); + setupFingerprintAuth(/* isClass3 */ true); - // WHEN fingerprint is locked out - fingerprintErrorTemporaryLockedOut(); + // GIVEN primary auth is not required by StrongAuthTracker + primaryAuthNotRequiredByStrongAuthTracker(); + + // WHEN fingerprint (class 3) is lock out + fingerprintErrorTemporaryLockOut(); // THEN unlocking with face is not allowed Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( @@ -719,6 +766,38 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void class3FaceLockOut_lockOutClass3Fingerprint() throws RemoteException { + setupFaceAuth(/* isClass3 */ true); + setupFingerprintAuth(/* isClass3 */ true); + + // GIVEN primary auth is not required by StrongAuthTracker + primaryAuthNotRequiredByStrongAuthTracker(); + + // WHEN face (class 3) is lock out + faceAuthLockOut(); + + // THEN unlocking with fingerprint is not allowed + Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + BiometricSourceType.FINGERPRINT)); + } + + @Test + public void class1FaceLockOut_doesNotLockOutClass3Fingerprint() throws RemoteException { + setupFaceAuth(/* isClass3 */ false); + setupFingerprintAuth(/* isClass3 */ true); + + // GIVEN primary auth is not required by StrongAuthTracker + primaryAuthNotRequiredByStrongAuthTracker(); + + // WHEN face (class 1) is lock out + faceAuthLockOut(); + + // THEN unlocking with fingerprint is still allowed + Assert.assertTrue(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + BiometricSourceType.FINGERPRINT)); + } + + @Test public void testUnlockingWithFpAllowed_strongAuthTrackerUnlockingWithBiometricNotAllowed() { // GIVEN unlocking with biometric is not allowed when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); @@ -731,10 +810,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testUnlockingWithFpAllowed_fingerprintLockout() { // GIVEN unlocking with biometric is allowed - strongAuthNotRequired(); + primaryAuthNotRequiredByStrongAuthTracker(); - // WHEN fingerprint is locked out - fingerprintErrorTemporaryLockedOut(); + // WHEN fingerprint is lock out + fingerprintErrorTemporaryLockOut(); // THEN unlocking with fingerprint is not allowed Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( @@ -757,8 +836,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.onTrustChanged(true, true, getCurrentUser(), 0, null); Assert.assertTrue(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser())); - // WHEN fingerprint is locked out - fingerprintErrorTemporaryLockedOut(); + // WHEN fingerprint is lock out + fingerprintErrorTemporaryLockOut(); // THEN user is NOT considered as "having trust" and bouncer cannot be skipped Assert.assertFalse(mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser())); @@ -826,7 +905,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // GIVEN udfps is supported and strong auth required for weak biometrics (face) only givenUdfpsSupported(); - strongAuthRequiredForWeakBiometricOnly(); // this allows fingerprint to run but not face + primaryAuthRequiredForWeakBiometricOnly(); // allows class3 fp to run but not class1 face // WHEN the device wakes up mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); @@ -863,7 +942,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void noFaceDetect_whenStrongAuthRequiredAndBypass_faceDetectionUnsupported() { // GIVEN bypass is enabled, face detection is NOT supported and strong auth is required lockscreenBypassIsAllowed(); - strongAuthRequiredEncrypted(); + primaryAuthRequiredEncrypted(); keyguardIsVisible(); // WHEN the device wakes up @@ -931,6 +1010,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse(); verifyFingerprintAuthenticateNeverCalled(); // WHEN alternate bouncer is shown + mKeyguardUpdateMonitor.setKeyguardShowing(true, true); mKeyguardUpdateMonitor.setAlternateBouncerShowing(true); // THEN make sure FP listening begins @@ -1011,10 +1091,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testOnFaceAuthenticated_skipsFaceWhenAuthenticated() { - // test whether face will be skipped if authenticated, so the value of isStrongBiometric + // test whether face will be skipped if authenticated, so the value of isClass3Biometric // doesn't matter here mKeyguardUpdateMonitor.onFaceAuthenticated(KeyguardUpdateMonitor.getCurrentUser(), - true /* isStrongBiometric */); + true /* isClass3Biometric */); setKeyguardBouncerVisibility(true); mTestableLooper.processAllMessages(); @@ -1027,7 +1107,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); keyguardIsVisible(); - faceAuthLockedOut(); + faceAuthLockOut(); verify(mLockPatternUtils, never()).requireStrongAuth(anyInt(), anyInt()); } @@ -1050,7 +1130,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTestableLooper.processAllMessages(); keyguardIsVisible(); - faceAuthLockedOut(); + faceAuthLockOut(); mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, ""); @@ -1060,32 +1140,32 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testGetUserCanSkipBouncer_whenFace() { int user = KeyguardUpdateMonitor.getCurrentUser(); - mKeyguardUpdateMonitor.onFaceAuthenticated(user, true /* isStrongBiometric */); + mKeyguardUpdateMonitor.onFaceAuthenticated(user, true /* isClass3Biometric */); assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue(); } @Test public void testGetUserCanSkipBouncer_whenFace_nonStrongAndDisallowed() { - when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */)) + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isClass3Biometric */)) .thenReturn(false); int user = KeyguardUpdateMonitor.getCurrentUser(); - mKeyguardUpdateMonitor.onFaceAuthenticated(user, false /* isStrongBiometric */); + mKeyguardUpdateMonitor.onFaceAuthenticated(user, false /* isClass3Biometric */); assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isFalse(); } @Test public void testGetUserCanSkipBouncer_whenFingerprint() { int user = KeyguardUpdateMonitor.getCurrentUser(); - mKeyguardUpdateMonitor.onFingerprintAuthenticated(user, true /* isStrongBiometric */); + mKeyguardUpdateMonitor.onFingerprintAuthenticated(user, true /* isClass3Biometric */); assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue(); } @Test public void testGetUserCanSkipBouncer_whenFingerprint_nonStrongAndDisallowed() { - when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */)) + when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isClass3Biometric */)) .thenReturn(false); int user = KeyguardUpdateMonitor.getCurrentUser(); - mKeyguardUpdateMonitor.onFingerprintAuthenticated(user, false /* isStrongBiometric */); + mKeyguardUpdateMonitor.onFingerprintAuthenticated(user, false /* isClass3Biometric */); assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isFalse(); } @@ -1126,9 +1206,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @BiometricConstants.LockoutMode int fingerprintLockoutMode, @BiometricConstants.LockoutMode int faceLockoutMode) { final int newUser = 12; - final boolean faceLocked = + final boolean faceLockOut = faceLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE; - final boolean fpLocked = + final boolean fpLockOut = fingerprintLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE; mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); @@ -1161,8 +1241,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { eq(false), eq(BiometricSourceType.FINGERPRINT)); // THEN locked out states are updated - assertThat(mKeyguardUpdateMonitor.isFingerprintLockedOut()).isEqualTo(fpLocked); - assertThat(mKeyguardUpdateMonitor.isFaceLockedOut()).isEqualTo(faceLocked); + assertThat(mKeyguardUpdateMonitor.isFingerprintLockedOut()).isEqualTo(fpLockOut); + assertThat(mKeyguardUpdateMonitor.isFaceLockedOut()).isEqualTo(faceLockOut); // Fingerprint should be cancelled on lockout if going to lockout state, else // restarted if it's not @@ -1443,7 +1523,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { // GIVEN SFPS supported and enrolled final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); - props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON)); + props.add(createFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON, + /* isClass3 */ true)); when(mAuthController.getSfpsProps()).thenReturn(props); when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true); @@ -1466,17 +1547,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue(); } - private FingerprintSensorPropertiesInternal newFingerprintSensorPropertiesInternal( - @FingerprintSensorProperties.SensorType int sensorType) { - return new FingerprintSensorPropertiesInternal( - 0 /* sensorId */, - SensorProperties.STRENGTH_STRONG, - 1 /* maxEnrollmentsPerUser */, - new ArrayList<ComponentInfoInternal>(), - sensorType, - true /* resetLockoutRequiresHardwareAuthToken */); - } - @Test public void testShouldNotListenForUdfps_whenTrustEnabled() { // GIVEN a "we should listen for udfps" state @@ -1613,7 +1683,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { keyguardNotGoingAway(); occludingAppRequestsFaceAuth(); currentUserIsPrimary(); - strongAuthNotRequired(); + primaryAuthNotRequiredByStrongAuthTracker(); biometricsEnabledForCurrentUser(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); @@ -1622,7 +1692,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue(); // Fingerprint is locked out. - fingerprintErrorTemporaryLockedOut(); + fingerprintErrorTemporaryLockOut(); assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse(); } @@ -1634,7 +1704,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { bouncerFullyVisibleAndNotGoingToSleep(); keyguardNotGoingAway(); currentUserIsPrimary(); - strongAuthNotRequired(); + primaryAuthNotRequiredByStrongAuthTracker(); biometricsEnabledForCurrentUser(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); @@ -1657,7 +1727,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { bouncerFullyVisibleAndNotGoingToSleep(); keyguardNotGoingAway(); currentUserIsPrimary(); - strongAuthNotRequired(); + primaryAuthNotRequiredByStrongAuthTracker(); biometricsEnabledForCurrentUser(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); @@ -1684,7 +1754,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Face auth should run when the following is true. keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - strongAuthNotRequired(); + primaryAuthNotRequiredByStrongAuthTracker(); biometricsEnabledForCurrentUser(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); @@ -1940,7 +2010,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue(); // Face is locked out. - faceAuthLockedOut(); + faceAuthLockOut(); mTestableLooper.processAllMessages(); // This is needed beccause we want to show face locked out error message whenever face auth @@ -2578,7 +2648,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { verify(mFingerprintManager).addLockoutResetCallback(fpLockoutResetCallbackCaptor.capture()); // GIVEN device is locked out - fingerprintErrorTemporaryLockedOut(); + fingerprintErrorTemporaryLockOut(); // GIVEN FP detection is running givenDetectFingerprintWithClearingFingerprintManagerInvocations(); @@ -2662,6 +2732,21 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { KeyguardUpdateMonitor.getCurrentUser())).isTrue(); } + @Test + public void testFingerprintListeningStateWhenOccluded() { + when(mAuthController.isUdfpsSupported()).thenReturn(true); + + mKeyguardUpdateMonitor.setKeyguardShowing(false, false); + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_BIOMETRIC); + mKeyguardUpdateMonitor.setKeyguardShowing(false, true); + + verifyFingerprintAuthenticateNeverCalled(); + + mKeyguardUpdateMonitor.setKeyguardShowing(true, true); + mKeyguardUpdateMonitor.setAlternateBouncerShowing(true); + + verifyFingerprintAuthenticateCall(); + } private void verifyFingerprintAuthenticateNeverCalled() { verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any()); @@ -2705,8 +2790,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } private void supportsFaceDetection() throws RemoteException { + final boolean isClass3 = !mFaceSensorProperties.isEmpty() + && mFaceSensorProperties.get(0).sensorStrength == STRENGTH_STRONG; mFaceSensorProperties = - List.of(createFaceSensorProperties(/* supportsFaceDetection = */ true)); + List.of(createFaceSensorProperties(/* supportsFaceDetection = */ true, isClass3)); mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties); } @@ -2734,7 +2821,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } } - private void faceAuthLockedOut() { + private void faceAuthLockOut() { mKeyguardUpdateMonitor.mFaceAuthenticationCallback .onAuthenticationError(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, ""); } @@ -2767,7 +2854,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.setSwitchingUser(true); } - private void fingerprintErrorTemporaryLockedOut() { + private void fingerprintErrorTemporaryLockOut() { mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out"); } @@ -2821,18 +2908,18 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { ); } - private void strongAuthRequiredEncrypted() { + private void primaryAuthRequiredEncrypted() { when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT); when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); } - private void strongAuthRequiredForWeakBiometricOnly() { + private void primaryAuthRequiredForWeakBiometricOnly() { when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(eq(true))).thenReturn(true); when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(eq(false))).thenReturn(false); } - private void strongAuthNotRequired() { + private void primaryAuthNotRequiredByStrongAuthTracker() { when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) .thenReturn(0); when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); @@ -2917,10 +3004,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } private void givenDetectFace() throws RemoteException { - // GIVEN bypass is enabled, face detection is supported and strong auth is required + // GIVEN bypass is enabled, face detection is supported and primary auth is required lockscreenBypassIsAllowed(); supportsFaceDetection(); - strongAuthRequiredEncrypted(); + primaryAuthRequiredEncrypted(); keyguardIsVisible(); // fingerprint is NOT running, UDFPS is NOT supported diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/SplitShadeTransitionAdapterTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt index 64fec5bfd4ed..dea2082a2c22 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/SplitShadeTransitionAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.shade +package com.android.keyguard import android.animation.Animator import android.testing.AndroidTestingRunner import android.transition.TransitionValues import androidx.test.filters.SmallTest -import com.android.keyguard.KeyguardStatusViewController +import com.android.keyguard.KeyguardStatusViewController.SplitShadeTransitionAdapter import com.android.systemui.SysuiTestCase -import com.android.systemui.shade.NotificationPanelViewController.SplitShadeTransitionAdapter import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -33,14 +32,14 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) class SplitShadeTransitionAdapterTest : SysuiTestCase() { - @Mock private lateinit var keyguardStatusViewController: KeyguardStatusViewController + @Mock private lateinit var KeyguardClockSwitchController: KeyguardClockSwitchController private lateinit var adapter: SplitShadeTransitionAdapter @Before fun setUp() { MockitoAnnotations.initMocks(this) - adapter = SplitShadeTransitionAdapter(keyguardStatusViewController) + adapter = SplitShadeTransitionAdapter(KeyguardClockSwitchController) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/ChooserPinMigrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ChooserPinMigrationTest.kt deleted file mode 100644 index 44da5f42aafd..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/ChooserPinMigrationTest.kt +++ /dev/null @@ -1,255 +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.systemui - -import android.content.Context -import android.content.Intent -import android.content.SharedPreferences -import android.content.res.Resources -import android.testing.AndroidTestingRunner -import androidx.test.filters.SmallTest -import com.android.systemui.broadcast.BroadcastSender -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags -import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.kotlinArgumentCaptor -import com.android.systemui.util.mockito.whenever -import com.google.common.truth.Truth.assertThat -import java.io.File -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.anyInt -import org.mockito.Mock -import org.mockito.Mockito.never -import org.mockito.Mockito.verify -import org.mockito.Mockito.verifyZeroInteractions -import org.mockito.MockitoAnnotations - -@RunWith(AndroidTestingRunner::class) -@SmallTest -class ChooserPinMigrationTest : SysuiTestCase() { - - private val fakeFeatureFlags = FakeFeatureFlags() - private val fakePreferences = - mutableMapOf( - "TestPinnedPackage/TestPinnedClass" to true, - "TestUnpinnedPackage/TestUnpinnedClass" to false, - ) - private val intent = kotlinArgumentCaptor<Intent>() - private val permission = kotlinArgumentCaptor<String>() - - private lateinit var chooserPinMigration: ChooserPinMigration - - @Mock private lateinit var mockContext: Context - @Mock private lateinit var mockResources: Resources - @Mock - private lateinit var mockLegacyPinPrefsFileSupplier: - ChooserPinMigration.Companion.LegacyPinPrefsFileSupplier - @Mock private lateinit var mockFile: File - @Mock private lateinit var mockSharedPreferences: SharedPreferences - @Mock private lateinit var mockSharedPreferencesEditor: SharedPreferences.Editor - @Mock private lateinit var mockBroadcastSender: BroadcastSender - - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - - whenever(mockContext.resources).thenReturn(mockResources) - whenever(mockContext.getSharedPreferences(any<File>(), anyInt())) - .thenReturn(mockSharedPreferences) - whenever(mockResources.getString(anyInt())).thenReturn("TestPackage/TestClass") - whenever(mockSharedPreferences.all).thenReturn(fakePreferences) - whenever(mockSharedPreferences.edit()).thenReturn(mockSharedPreferencesEditor) - whenever(mockSharedPreferencesEditor.commit()).thenReturn(true) - whenever(mockLegacyPinPrefsFileSupplier.get()).thenReturn(mockFile) - whenever(mockFile.exists()).thenReturn(true) - whenever(mockFile.delete()).thenReturn(true) - fakeFeatureFlags.set(Flags.CHOOSER_MIGRATION_ENABLED, true) - } - - @Test - fun start_performsMigration() { - // Arrange - chooserPinMigration = - ChooserPinMigration( - mockContext, - fakeFeatureFlags, - mockBroadcastSender, - mockLegacyPinPrefsFileSupplier, - ) - - // Act - chooserPinMigration.start() - - // Assert - verify(mockBroadcastSender).sendBroadcast(intent.capture(), permission.capture()) - assertThat(intent.value.action).isEqualTo("android.intent.action.CHOOSER_PIN_MIGRATION") - assertThat(intent.value.`package`).isEqualTo("TestPackage") - assertThat(intent.value.extras?.keySet()).hasSize(2) - assertThat(intent.value.hasExtra("TestPinnedPackage/TestPinnedClass")).isTrue() - assertThat(intent.value.getBooleanExtra("TestPinnedPackage/TestPinnedClass", false)) - .isTrue() - assertThat(intent.value.hasExtra("TestUnpinnedPackage/TestUnpinnedClass")).isTrue() - assertThat(intent.value.getBooleanExtra("TestUnpinnedPackage/TestUnpinnedClass", true)) - .isFalse() - assertThat(permission.value).isEqualTo("android.permission.RECEIVE_CHOOSER_PIN_MIGRATION") - - // Assert - verify(mockSharedPreferencesEditor).clear() - verify(mockSharedPreferencesEditor).commit() - - // Assert - verify(mockFile).delete() - } - - @Test - fun start_doesNotDeleteLegacyPreferencesFile_whenClearingItFails() { - // Arrange - whenever(mockSharedPreferencesEditor.commit()).thenReturn(false) - chooserPinMigration = - ChooserPinMigration( - mockContext, - fakeFeatureFlags, - mockBroadcastSender, - mockLegacyPinPrefsFileSupplier, - ) - - // Act - chooserPinMigration.start() - - // Assert - verify(mockBroadcastSender).sendBroadcast(intent.capture(), permission.capture()) - assertThat(intent.value.action).isEqualTo("android.intent.action.CHOOSER_PIN_MIGRATION") - assertThat(intent.value.`package`).isEqualTo("TestPackage") - assertThat(intent.value.extras?.keySet()).hasSize(2) - assertThat(intent.value.hasExtra("TestPinnedPackage/TestPinnedClass")).isTrue() - assertThat(intent.value.getBooleanExtra("TestPinnedPackage/TestPinnedClass", false)) - .isTrue() - assertThat(intent.value.hasExtra("TestUnpinnedPackage/TestUnpinnedClass")).isTrue() - assertThat(intent.value.getBooleanExtra("TestUnpinnedPackage/TestUnpinnedClass", true)) - .isFalse() - assertThat(permission.value).isEqualTo("android.permission.RECEIVE_CHOOSER_PIN_MIGRATION") - - // Assert - verify(mockSharedPreferencesEditor).clear() - verify(mockSharedPreferencesEditor).commit() - - // Assert - verify(mockFile, never()).delete() - } - - @Test - fun start_OnlyDeletesLegacyPreferencesFile_whenEmpty() { - // Arrange - whenever(mockSharedPreferences.all).thenReturn(emptyMap()) - chooserPinMigration = - ChooserPinMigration( - mockContext, - fakeFeatureFlags, - mockBroadcastSender, - mockLegacyPinPrefsFileSupplier, - ) - - // Act - chooserPinMigration.start() - - // Assert - verifyZeroInteractions(mockBroadcastSender) - - // Assert - verifyZeroInteractions(mockSharedPreferencesEditor) - - // Assert - verify(mockFile).delete() - } - - @Test - fun start_DoesNotDoMigration_whenFlagIsDisabled() { - // Arrange - fakeFeatureFlags.set(Flags.CHOOSER_MIGRATION_ENABLED, false) - chooserPinMigration = - ChooserPinMigration( - mockContext, - fakeFeatureFlags, - mockBroadcastSender, - mockLegacyPinPrefsFileSupplier, - ) - - // Act - chooserPinMigration.start() - - // Assert - verifyZeroInteractions(mockBroadcastSender) - - // Assert - verifyZeroInteractions(mockSharedPreferencesEditor) - - // Assert - verify(mockFile, never()).delete() - } - - @Test - fun start_DoesNotDoMigration_whenLegacyPreferenceFileNotPresent() { - // Arrange - whenever(mockFile.exists()).thenReturn(false) - chooserPinMigration = - ChooserPinMigration( - mockContext, - fakeFeatureFlags, - mockBroadcastSender, - mockLegacyPinPrefsFileSupplier, - ) - - // Act - chooserPinMigration.start() - - // Assert - verifyZeroInteractions(mockBroadcastSender) - - // Assert - verifyZeroInteractions(mockSharedPreferencesEditor) - - // Assert - verify(mockFile, never()).delete() - } - - @Test - fun start_DoesNotDoMigration_whenConfiguredChooserComponentIsInvalid() { - // Arrange - whenever(mockResources.getString(anyInt())).thenReturn("InvalidComponent") - chooserPinMigration = - ChooserPinMigration( - mockContext, - fakeFeatureFlags, - mockBroadcastSender, - mockLegacyPinPrefsFileSupplier, - ) - - // Act - chooserPinMigration.start() - - // Assert - verifyZeroInteractions(mockBroadcastSender) - - // Assert - verifyZeroInteractions(mockSharedPreferencesEditor) - - // Assert - verify(mockFile, never()).delete() - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt new file mode 100644 index 000000000000..01d3a3931052 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt @@ -0,0 +1,119 @@ +/* + * 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 + +import android.graphics.Point +import android.hardware.display.DisplayManagerGlobal +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.Display +import android.view.DisplayAdjustments +import android.view.DisplayInfo +import androidx.test.filters.SmallTest +import com.android.internal.R +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.biometrics.AuthController +import com.android.systemui.decor.FaceScanningProviderFactory +import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.ScreenDecorationsLogger +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import java.util.concurrent.Executor +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.MockitoAnnotations + +@RunWithLooper +@RunWith(AndroidTestingRunner::class) +@SmallTest +class FaceScanningProviderFactoryTest : SysuiTestCase() { + + private lateinit var underTest: FaceScanningProviderFactory + + @Mock private lateinit var authController: AuthController + + @Mock private lateinit var statusBarStateController: StatusBarStateController + + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + + @Mock private lateinit var display: Display + + private val displayId = 2 + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + val displayInfo = DisplayInfo() + val dmGlobal = mock(DisplayManagerGlobal::class.java) + val display = + Display( + dmGlobal, + displayId, + displayInfo, + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS + ) + whenever(dmGlobal.getDisplayInfo(eq(displayId))).thenReturn(displayInfo) + val displayContext = context.createDisplayContext(display) as SysuiTestableContext + displayContext.orCreateTestableResources.addOverride( + R.array.config_displayUniqueIdArray, + arrayOf(displayId) + ) + displayContext.orCreateTestableResources.addOverride( + R.bool.config_fillMainBuiltInDisplayCutout, + true + ) + underTest = + FaceScanningProviderFactory( + authController, + displayContext, + statusBarStateController, + keyguardUpdateMonitor, + mock(Executor::class.java), + ScreenDecorationsLogger(logcatLogBuffer("FaceScanningProviderFactoryTest")) + ) + + whenever(authController.faceSensorLocation).thenReturn(Point(10, 10)) + } + + @Test + fun shouldNotShowFaceScanningAnimationIfFaceIsNotEnrolled() { + whenever(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false) + whenever(authController.isShowing).thenReturn(true) + + assertThat(underTest.shouldShowFaceScanningAnim()).isFalse() + } + + @Test + fun shouldShowFaceScanningAnimationIfBiometricPromptIsShowing() { + whenever(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(true) + whenever(authController.isShowing).thenReturn(true) + + assertThat(underTest.shouldShowFaceScanningAnim()).isTrue() + } + + @Test + fun shouldShowFaceScanningAnimationIfKeyguardFaceDetectionIsShowing() { + whenever(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(true) + whenever(keyguardUpdateMonitor.isFaceDetectionRunning).thenReturn(true) + + assertThat(underTest.shouldShowFaceScanningAnim()).isTrue() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index 0978c824cb15..9c36af3a35e4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -18,6 +18,7 @@ package com.android.systemui.accessibility; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.view.Choreographer.FrameCallback; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; @@ -172,6 +173,12 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { returnsSecondArg()); mResources = getContext().getOrCreateTestableResources().getResources(); + // prevent the config orientation from undefined, which may cause config.diff method + // neglecting the orientation update. + if (mResources.getConfiguration().orientation == ORIENTATION_UNDEFINED) { + mResources.getConfiguration().orientation = ORIENTATION_PORTRAIT; + } + mWindowMagnificationAnimationController = new WindowMagnificationAnimationController( mContext, mValueAnimator); mWindowMagnificationController = @@ -688,7 +695,11 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { @Test public void enableWindowMagnification_rotationIsChanged_updateRotationValue() { - final Configuration config = mContext.getResources().getConfiguration(); + // the config orientation should not be undefined, since it would cause config.diff + // returning 0 and thus the orientation changed would not be detected + assertNotEquals(ORIENTATION_UNDEFINED, mResources.getConfiguration().orientation); + + final Configuration config = mResources.getConfiguration(); config.orientation = config.orientation == ORIENTATION_LANDSCAPE ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; final int newRotation = simulateRotateTheDevice(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt index 921f9a8fc7d6..2b95973363ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt @@ -37,7 +37,13 @@ class OnBackAnimationCallbackExtensionTest : SysuiTestCase() { @Test fun onBackProgressed_shouldInvoke_onBackProgress() { - val backEvent = BackEvent(0f, 0f, 0f, BackEvent.EDGE_LEFT) + val backEvent = + BackEvent( + /* touchX = */ 0f, + /* touchY = */ 0f, + /* progress = */ 0f, + /* swipeEdge = */ BackEvent.EDGE_LEFT + ) onBackAnimationCallback.onBackStarted(backEvent) onBackAnimationCallback.onBackProgressed(backEvent) @@ -47,7 +53,13 @@ class OnBackAnimationCallbackExtensionTest : SysuiTestCase() { @Test fun onBackStarted_shouldInvoke_onBackStart() { - val backEvent = BackEvent(0f, 0f, 0f, BackEvent.EDGE_LEFT) + val backEvent = + BackEvent( + /* touchX = */ 0f, + /* touchY = */ 0f, + /* progress = */ 0f, + /* swipeEdge = */ BackEvent.EDGE_LEFT + ) onBackAnimationCallback.onBackStarted(backEvent) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt index 58d906907488..dd87f6e7f64b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt @@ -18,10 +18,10 @@ package com.android.systemui.biometrics import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT -import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import android.view.View +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase @@ -36,7 +36,8 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit -@RunWith(AndroidTestingRunner::class) + +@RunWith(AndroidJUnit4::class) @RunWithLooper(setAsMainLooper = true) @SmallTest class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt index bce98cf116d4..9f789e4cbd18 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt @@ -17,7 +17,7 @@ package com.android.systemui.biometrics import android.hardware.biometrics.BiometricAuthenticator import android.os.Bundle -import android.testing.AndroidTestingRunner +import androidx.test.ext.junit.runners.AndroidJUnit4 import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import android.view.View @@ -37,7 +37,7 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) @RunWithLooper(setAsMainLooper = true) @SmallTest class AuthBiometricFingerprintViewTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index b4696e49e9aa..6d4c467aca7d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -25,7 +25,6 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.os.Handler import android.os.IBinder import android.os.UserManager -import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import android.testing.ViewUtils @@ -34,6 +33,7 @@ import android.view.View import android.view.WindowInsets import android.view.WindowManager import android.widget.ScrollView +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.jank.InteractionJankMonitor import com.android.internal.widget.LockPatternUtils @@ -62,7 +62,7 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) @RunWithLooper(setAsMainLooper = true) @SmallTest class AuthContainerViewTest : SysuiTestCase() { @@ -170,24 +170,16 @@ class AuthContainerViewTest : SysuiTestCase() { } @Test - fun testFocusLossAfterRotating() { + fun testActionCancel_panelInteractionDetectorDisable() { val container = initializeFingerprintContainer() - waitForIdleSync() - - val requestID = authContainer?.requestId ?: 0L - - verify(callback).onDialogAnimatedIn(requestID) - container.onOrientationChanged() - container.onWindowFocusChanged(false) - waitForIdleSync() - - verify(callback, never()).onDismissed( - eq(AuthDialogCallback.DISMISSED_USER_CANCELED), - eq<ByteArray?>(null), /* credentialAttestation */ - eq(requestID) + container.mBiometricCallback.onAction( + AuthBiometricView.Callback.ACTION_USER_CANCELED ) + waitForIdleSync() + verify(panelInteractionDetector).disable() } + @Test fun testActionAuthenticated_sendsDismissedAuthenticated() { val container = initializeFingerprintContainer() @@ -489,7 +481,7 @@ class AuthContainerViewTest : SysuiTestCase() { private fun AuthContainerView.addToView() { ViewUtils.attachView(this) waitForIdleSync() - assertThat(isAttachedToWindow).isTrue() + assertThat(isAttachedToWindow()).isTrue() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index c068efb1b5d4..0f20ace49a47 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -75,7 +75,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.os.UserManager; -import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; @@ -83,6 +82,7 @@ import android.view.DisplayInfo; import android.view.Surface; import android.view.WindowManager; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.R; @@ -117,7 +117,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -@RunWith(AndroidTestingRunner.class) +@RunWith(AndroidJUnit4.class) @RunWithLooper @SmallTest public class AuthControllerTest extends SysuiTestCase { @@ -265,7 +265,7 @@ public class AuthControllerTest extends SysuiTestCase { mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps); // Ensures that the operations posted on the handler get executed. - mTestableLooper.processAllMessages(); + waitForIdleSync(); } // Callback tests @@ -285,14 +285,14 @@ public class AuthControllerTest extends SysuiTestCase { mFpAuthenticatorsRegisteredCaptor.capture()); verify(mFaceManager).addAuthenticatorsRegisteredCallback( mFaceAuthenticatorsRegisteredCaptor.capture()); - mTestableLooper.processAllMessages(); + waitForIdleSync(); verify(mFingerprintManager, never()).registerBiometricStateListener(any()); verify(mFaceManager, never()).registerBiometricStateListener(any()); mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of()); mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of()); - mTestableLooper.processAllMessages(); + waitForIdleSync(); verify(mFingerprintManager).registerBiometricStateListener(any()); verify(mFaceManager).registerBiometricStateListener(any()); @@ -316,7 +316,7 @@ public class AuthControllerTest extends SysuiTestCase { // Emulates a device with no authenticators (empty list). mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of()); mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of()); - mTestableLooper.processAllMessages(); + waitForIdleSync(); verify(mFingerprintManager).registerBiometricStateListener( mBiometricStateCaptor.capture()); @@ -328,7 +328,7 @@ public class AuthControllerTest extends SysuiTestCase { listener.onEnrollmentsChanged(0 /* userId */, 0xbeef /* sensorId */, true /* hasEnrollments */); } - mTestableLooper.processAllMessages(); + waitForIdleSync(); // Nothing should crash. } @@ -692,7 +692,7 @@ public class AuthControllerTest extends SysuiTestCase { switchTask("other_package"); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); - mTestableLooper.processAllMessages(); + waitForIdleSync(); assertNull(mAuthController.mCurrentDialog); assertNull(mAuthController.mReceiver); @@ -709,7 +709,7 @@ public class AuthControllerTest extends SysuiTestCase { switchTask("other_package"); mAuthController.mTaskStackListener.onTaskStackChanged(); - mTestableLooper.processAllMessages(); + waitForIdleSync(); assertNull(mAuthController.mCurrentDialog); assertNull(mAuthController.mReceiver); @@ -742,7 +742,7 @@ public class AuthControllerTest extends SysuiTestCase { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); mAuthController.mBroadcastReceiver.onReceive(mContext, intent); - mTestableLooper.processAllMessages(); + waitForIdleSync(); assertNull(mAuthController.mCurrentDialog); assertNull(mAuthController.mReceiver); @@ -1021,4 +1021,9 @@ public class AuthControllerTest extends SysuiTestCase { return dialog; } } + + @Override + protected void waitForIdleSync() { + mTestableLooper.processAllMessages(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt index b41053cdea50..ef750be90b4b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt @@ -51,32 +51,37 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() { @Test fun testEnableDetector_expandWithTrack_shouldPostRunnable() { detector.enable(action) - // simulate notification expand - shadeExpansionStateManager.onPanelExpansionChanged(5566f, true, true, 5566f) + shadeExpansionStateManager.onPanelExpansionChanged(1.0f, true, true, 0f) verify(action).run() } @Test fun testEnableDetector_trackOnly_shouldPostRunnable() { detector.enable(action) - // simulate notification expand - shadeExpansionStateManager.onPanelExpansionChanged(5566f, false, true, 5566f) + shadeExpansionStateManager.onPanelExpansionChanged(1.0f, false, true, 0f) verify(action).run() } @Test fun testEnableDetector_expandOnly_shouldPostRunnable() { detector.enable(action) - // simulate notification expand - shadeExpansionStateManager.onPanelExpansionChanged(5566f, true, false, 5566f) + shadeExpansionStateManager.onPanelExpansionChanged(1.0f, true, false, 0f) verify(action).run() } @Test + fun testEnableDetector_expandWithoutFraction_shouldPostRunnable() { + detector.enable(action) + // simulate headsup notification + shadeExpansionStateManager.onPanelExpansionChanged(0.0f, true, false, 0f) + verifyZeroInteractions(action) + } + + @Test fun testEnableDetector_shouldNotPostRunnable() { detector.enable(action) detector.disable() - shadeExpansionStateManager.onPanelExpansionChanged(5566f, true, true, 5566f) + shadeExpansionStateManager.onPanelExpansionChanged(1.0f, true, true, 0f) verifyZeroInteractions(action) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java index 69c7f364d235..24a13a57dae7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java @@ -32,17 +32,20 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.hardware.display.DisplayManager; import android.os.Handler; -import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.Display; import android.view.Surface; import android.view.Surface.Rotation; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -51,11 +54,8 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import kotlin.Unit; -import kotlin.jvm.functions.Function0; - @SmallTest -@RunWith(AndroidTestingRunner.class) +@RunWith(AndroidJUnit4.class) @RunWithLooper(setAsMainLooper = true) public class BiometricDisplayListenerTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt index c9ccdb36da89..88b6c39531e2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt @@ -16,7 +16,7 @@ package com.android.systemui.biometrics -import android.testing.AndroidTestingRunner +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.logging.BiometricMessageDeferralLogger import com.android.systemui.SysuiTestCase @@ -33,7 +33,7 @@ import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) class FaceHelpMessageDeferralTest : SysuiTestCase() { val threshold = .75f @Mock lateinit var logger: BiometricMessageDeferralLogger 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 33345b5b9f75..c554af630106 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt @@ -34,7 +34,6 @@ import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.hardware.fingerprint.ISidefpsController import android.os.Handler -import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.Display import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS @@ -49,6 +48,7 @@ import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG import android.view.WindowMetrics +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.airbnb.lottie.LottieAnimationView import com.android.systemui.R @@ -90,7 +90,7 @@ private const val DISPLAY_ID = 2 private const val SENSOR_ID = 1 @SmallTest -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper class SideFpsControllerTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index b2c2ae7458ae..1faad8084535 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -25,7 +25,7 @@ import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROL import android.hardware.biometrics.BiometricOverlayConstants.ShowReason import android.hardware.fingerprint.FingerprintManager import android.hardware.fingerprint.IUdfpsOverlayControllerCallback -import android.testing.AndroidTestingRunner +import androidx.test.ext.junit.runners.AndroidJUnit4 import android.testing.TestableLooper.RunWithLooper import android.view.LayoutInflater import android.view.MotionEvent @@ -80,7 +80,7 @@ private const val SENSOR_WIDTH = 30 private const val SENSOR_HEIGHT = 60 @SmallTest -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) @RunWithLooper(setAsMainLooper = true) class UdfpsControllerOverlayTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index edee3f1b9f02..8d8b19050e4b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -58,7 +58,6 @@ import android.os.Handler; import android.os.PowerManager; import android.os.RemoteException; import android.os.VibrationAttributes; -import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -68,6 +67,7 @@ import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.logging.InstanceIdSequence; @@ -87,6 +87,7 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.FalsingManager; @@ -124,7 +125,7 @@ import java.util.Optional; import javax.inject.Provider; @SmallTest -@RunWith(AndroidTestingRunner.class) +@RunWith(AndroidJUnit4.class) @RunWithLooper(setAsMainLooper = true) public class UdfpsControllerTest extends SysuiTestCase { @@ -311,7 +312,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mUnlockedScreenOffAnimationController, mSystemUIDialogManager, mLatencyTracker, mActivityLaunchAnimator, alternateTouchProvider, mBiometricExecutor, mPrimaryBouncerInteractor, mSinglePointerTouchProcessor, mSessionTracker, - mAlternateBouncerInteractor, mSecureSettings, mInputManager, mUdfpsUtils); + mAlternateBouncerInteractor, mSecureSettings, mInputManager, mUdfpsUtils, + mock(KeyguardFaceAuthInteractor.class)); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture()); @@ -1017,7 +1019,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // THEN the display should be unconfigured once. If the timeout action is not // cancelled, the display would be unconfigured twice which would cause two // FP attempts. - verify(mUdfpsView, times(1)).unconfigureDisplay(); + verify(mUdfpsView).unconfigureDisplay(); } else { verify(mUdfpsView, never()).unconfigureDisplay(); } @@ -1301,8 +1303,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mBiometricExecutor.runAllReady(); downEvent.recycle(); - // THEN the touch is pilfered, expected twice (valid overlap and touch on sensor) - verify(mInputManager, times(2)).pilferPointers(any()); + // THEN the touch is pilfered + verify(mInputManager).pilferPointers(any()); } @Test @@ -1340,7 +1342,7 @@ public class UdfpsControllerTest extends SysuiTestCase { downEvent.recycle(); // THEN the touch is NOT pilfered - verify(mInputManager, times(0)).pilferPointers(any()); + verify(mInputManager, never()).pilferPointers(any()); } @Test @@ -1380,7 +1382,51 @@ public class UdfpsControllerTest extends SysuiTestCase { downEvent.recycle(); // THEN the touch is pilfered - verify(mInputManager, times(1)).pilferPointers(any()); + verify(mInputManager).pilferPointers(any()); + } + + @Test + public void onTouch_withNewTouchDetection_doNotPilferWhenPullingUpBouncer() + throws RemoteException { + final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L, + 0L); + final TouchProcessorResult processorResultMove = + new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN, + 1 /* pointerId */, touchData); + + // Enable new touch detection. + when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true); + + // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider. + initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */); + + // Configure UdfpsView to accept the ACTION_MOVE event + when(mUdfpsView.isDisplayConfigured()).thenReturn(false); + when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true); + + // GIVEN that the alternate bouncer is not showing and a11y touch exploration NOT enabled + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); + when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false); + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, + BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + + verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); + + // GIVEN a swipe up to bring up primary bouncer is in progress or swipe down for QS + when(mPrimaryBouncerInteractor.isInTransit()).thenReturn(true); + when(mLockscreenShadeTransitionController.getFractionToShade()).thenReturn(1f); + + // WHEN ACTION_MOVE is received and touch is within sensor + when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn( + processorResultMove); + MotionEvent moveEvent = MotionEvent.obtain(0, 0, ACTION_MOVE, 0, 0, 0); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent); + mBiometricExecutor.runAllReady(); + moveEvent.recycle(); + + // THEN the touch is NOT pilfered + verify(mInputManager, never()).pilferPointers(any()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java index 78fb5b00a21e..cd9189bef7f1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java @@ -23,8 +23,8 @@ import android.hardware.biometrics.SensorLocationInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; -import android.testing.AndroidTestingRunner; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; @@ -35,7 +35,7 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; -@RunWith(AndroidTestingRunner.class) +@RunWith(AndroidJUnit4.class) @SmallTest public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase { @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java index 1bc237d422d6..5239966f1923 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java @@ -25,9 +25,9 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback; import android.os.RemoteException; -import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; @@ -40,7 +40,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest -@RunWith(AndroidTestingRunner.class) +@RunWith(AndroidJUnit4.class) @RunWithLooper(setAsMainLooper = true) public class UdfpsDisplayModeTest extends SysuiTestCase { private static final int DISPLAY_ID = 0; diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index 6d9acb92a5f4..af3a06b74943 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -27,10 +27,10 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.MotionEvent; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.shade.ShadeExpansionListener; @@ -40,7 +40,7 @@ import org.junit.Test; import org.junit.runner.RunWith; @SmallTest -@RunWith(AndroidTestingRunner.class) +@RunWith(AndroidJUnit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest { 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 b848413423d1..fea9d2d5a6be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt @@ -17,8 +17,8 @@ package com.android.systemui.biometrics import android.os.Handler -import android.testing.AndroidTestingRunner import android.testing.TestableLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityModel import com.android.systemui.classifier.FalsingCollector @@ -39,10 +39,9 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.SystemClock -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.test.TestCoroutineScope -import kotlinx.coroutines.yield +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before @@ -54,22 +53,27 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) @SmallTest @TestableLooper.RunWithLooper +@kotlinx.coroutines.ExperimentalCoroutinesApi class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControllerBaseTest() { lateinit var keyguardBouncerRepository: KeyguardBouncerRepository @Mock private lateinit var bouncerLogger: TableLogBuffer + private lateinit var testScope: TestScope + @Before override fun setUp() { + testScope = TestScope() + allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread MockitoAnnotations.initMocks(this) keyguardBouncerRepository = KeyguardBouncerRepositoryImpl( mock(com.android.keyguard.ViewMediatorCallback::class.java), FakeSystemClock(), - TestCoroutineScope(), + testScope.backgroundScope, bouncerLogger, ) super.setUp() @@ -107,7 +111,7 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle @Test fun shadeLocked_showAlternateBouncer_unpauseAuth() = - runBlocking(IMMEDIATE) { + testScope.runTest { // GIVEN view is attached + on the SHADE_LOCKED (udfps view not showing) mController.onViewAttached() captureStatusBarStateListeners() @@ -116,7 +120,7 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle // WHEN alternate bouncer is requested val job = mController.listenForAlternateBouncerVisibility(this) keyguardBouncerRepository.setAlternateVisible(true) - yield() + runCurrent() // THEN udfps view will animate in & pause auth is updated to NOT pause verify(mView).animateInUdfpsBouncer(any()) @@ -128,7 +132,7 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle /** After migration to MODERN_BOUNCER, replaces UdfpsKeyguardViewControllerTest version */ @Test fun shouldPauseAuthBouncerShowing() = - runBlocking(IMMEDIATE) { + testScope.runTest { // GIVEN view attached and we're on the keyguard mController.onViewAttached() captureStatusBarStateListeners() @@ -138,15 +142,11 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle val job = mController.listenForBouncerExpansion(this) keyguardBouncerRepository.setPrimaryShow(true) keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE) - yield() + runCurrent() // THEN UDFPS shouldPauseAuth == true assertTrue(mController.shouldPauseAuth()) job.cancel() } - - companion object { - private val IMMEDIATE = Dispatchers.Main.immediate - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt index c2a129be66a4..8b374ae54127 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt @@ -17,9 +17,9 @@ package com.android.systemui.biometrics import android.graphics.Rect -import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.MotionEvent +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.UdfpsController.UdfpsOverlayController @@ -39,7 +39,7 @@ import org.mockito.Mockito.`when` as whenEver import org.mockito.junit.MockitoJUnit @SmallTest -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper class UdfpsShellTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt index 07b4a649a604..f0759670a21b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt @@ -19,7 +19,7 @@ package com.android.systemui.biometrics import android.graphics.PointF import android.graphics.RectF import android.hardware.biometrics.SensorLocationInternal -import android.testing.AndroidTestingRunner +import androidx.test.ext.junit.runners.AndroidJUnit4 import android.testing.TestableLooper import android.testing.ViewUtils import android.view.LayoutInflater @@ -49,7 +49,7 @@ private const val SENSOR_Y = 250 private const val SENSOR_RADIUS = 10 @SmallTest -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper class UdfpsViewTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java index 8cb91304808d..4cb99a23a531 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java @@ -120,7 +120,6 @@ public class BrightLineClassifierTest extends SysuiTestCase { gestureCompleteListenerCaptor.capture()); mGestureFinalizedListener = gestureCompleteListenerCaptor.getValue(); - mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, true); mFakeFeatureFlags.set(Flags.MEDIA_FALSING_PENALTY, true); mFakeFeatureFlags.set(Flags.FALSING_OFF_FOR_UNFOLDED, true); } @@ -260,13 +259,6 @@ public class BrightLineClassifierTest extends SysuiTestCase { } @Test - public void testIsFalseLongTap_FalseLongTap_NotFlagged() { - mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, false); - when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mFalsedResult); - assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isFalse(); - } - - @Test public void testIsFalseLongTap_FalseLongTap() { when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mFalsedResult); assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isTrue(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java index 315774aad71a..292fdff0027d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java @@ -94,7 +94,6 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { mMetricsLogger, mClassifiers, mSingleTapClassifier, mLongTapClassifier, mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController, mAccessibilityManager, false, mFakeFeatureFlags); - mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, true); mFakeFeatureFlags.set(Flags.FALSING_OFF_FOR_UNFOLDED, true); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java index fd6e31ba3bee..18515825967f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java @@ -16,8 +16,6 @@ package com.android.systemui.clipboardoverlay; -import static com.android.systemui.flags.Flags.CLIPBOARD_MINIMIZED_LAYOUT; - import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE; import static org.junit.Assert.assertEquals; @@ -40,7 +38,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; -import com.android.systemui.flags.FakeFeatureFlags; import org.junit.Before; import org.junit.Test; @@ -65,7 +62,6 @@ public class ClipboardListenerTest extends SysuiTestCase { private ClipboardOverlayController mOverlayController; @Mock private ClipboardToast mClipboardToast; - private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); @Mock private UiEventLogger mUiEventLogger; @@ -99,10 +95,8 @@ public class ClipboardListenerTest extends SysuiTestCase { when(mClipboardManager.getPrimaryClip()).thenReturn(mSampleClipData); when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource); - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, true); - mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider, - mClipboardToast, mClipboardManager, mFeatureFlags, mUiEventLogger); + mClipboardToast, mClipboardManager, mUiEventLogger); } @@ -222,34 +216,4 @@ public class ClipboardListenerTest extends SysuiTestCase { verify(mClipboardToast, times(1)).showCopiedToast(); verifyZeroInteractions(mOverlayControllerProvider); } - - @Test - public void test_minimizedLayoutFlagOff_usesLegacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - - mClipboardListener.start(); - mClipboardListener.onPrimaryClipChanged(); - - verify(mOverlayControllerProvider).get(); - - verify(mOverlayController).setClipDataLegacy( - mClipDataCaptor.capture(), mStringCaptor.capture()); - - assertEquals(mSampleClipData, mClipDataCaptor.getValue()); - assertEquals(mSampleSource, mStringCaptor.getValue()); - } - - @Test - public void test_minimizedLayoutFlagOn_usesNew() { - mClipboardListener.start(); - mClipboardListener.onPrimaryClipChanged(); - - verify(mOverlayControllerProvider).get(); - - verify(mOverlayController).setClipData( - mClipDataCaptor.capture(), mStringCaptor.capture()); - - assertEquals(mSampleClipData, mClipDataCaptor.getValue()); - assertEquals(mSampleSource, mStringCaptor.getValue()); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java index 299869c04d34..8600b7c48d33 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java @@ -25,7 +25,6 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_EXPANDED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_MINIMIZED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED; -import static com.android.systemui.flags.Flags.CLIPBOARD_MINIMIZED_LAYOUT; import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR; import static org.mockito.ArgumentMatchers.any; @@ -123,7 +122,6 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { new ClipData.Item("Test Item")); mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, false); - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, true); // turned off for legacy tests mOverlayController = new ClipboardOverlayController( mContext, @@ -146,178 +144,6 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { } @Test - public void test_setClipData_invalidImageData_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - ClipData clipData = new ClipData("", new String[]{"image/png"}, - new ClipData.Item(Uri.parse(""))); - - mOverlayController.setClipDataLegacy(clipData, ""); - - verify(mClipboardOverlayView, times(1)).showDefaultTextPreview(); - verify(mClipboardOverlayView, times(1)).showShareChip(); - verify(mClipboardOverlayView, times(1)).getEnterAnimation(); - } - - @Test - public void test_setClipData_nonImageUri_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - ClipData clipData = new ClipData("", new String[]{"resource/png"}, - new ClipData.Item(Uri.parse(""))); - - mOverlayController.setClipDataLegacy(clipData, ""); - - verify(mClipboardOverlayView, times(1)).showDefaultTextPreview(); - verify(mClipboardOverlayView, times(1)).showShareChip(); - verify(mClipboardOverlayView, times(1)).getEnterAnimation(); - } - - @Test - public void test_setClipData_textData_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - - mOverlayController.setClipDataLegacy(mSampleClipData, ""); - - verify(mClipboardOverlayView, times(1)).showTextPreview("Test Item", false); - verify(mClipboardOverlayView, times(1)).showShareChip(); - verify(mClipboardOverlayView, times(1)).getEnterAnimation(); - } - - @Test - public void test_setClipData_sensitiveTextData_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - - ClipDescription description = mSampleClipData.getDescription(); - PersistableBundle b = new PersistableBundle(); - b.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true); - description.setExtras(b); - ClipData data = new ClipData(description, mSampleClipData.getItemAt(0)); - mOverlayController.setClipDataLegacy(data, ""); - - verify(mClipboardOverlayView, times(1)).showTextPreview("••••••", true); - verify(mClipboardOverlayView, times(1)).showShareChip(); - verify(mClipboardOverlayView, times(1)).getEnterAnimation(); - } - - @Test - public void test_setClipData_repeatedCalls_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - when(mAnimator.isRunning()).thenReturn(true); - - mOverlayController.setClipDataLegacy(mSampleClipData, ""); - mOverlayController.setClipDataLegacy(mSampleClipData, ""); - - verify(mClipboardOverlayView, times(1)).getEnterAnimation(); - } - - @Test - public void test_viewCallbacks_onShareTapped_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - mOverlayController.setClipDataLegacy(mSampleClipData, ""); - - mCallbacks.onShareButtonTapped(); - - verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, ""); - verify(mClipboardOverlayView, times(1)).getExitAnimation(); - } - - @Test - public void test_viewCallbacks_onDismissTapped_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - mOverlayController.setClipDataLegacy(mSampleClipData, ""); - - mCallbacks.onDismissButtonTapped(); - - verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, ""); - verify(mClipboardOverlayView, times(1)).getExitAnimation(); - } - - @Test - public void test_multipleDismissals_dismissesOnce_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - - mCallbacks.onSwipeDismissInitiated(mAnimator); - mCallbacks.onDismissButtonTapped(); - mCallbacks.onSwipeDismissInitiated(mAnimator); - mCallbacks.onDismissButtonTapped(); - - verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SWIPE_DISMISSED, 0, null); - verify(mUiEventLogger, never()).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED); - } - - @Test - public void test_remoteCopy_withFlagOn_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true); - when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true); - - mOverlayController.setClipDataLegacy(mSampleClipData, ""); - - verify(mTimeoutHandler, never()).resetTimeout(); - } - - @Test - public void test_remoteCopy_withFlagOff_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true); - - mOverlayController.setClipDataLegacy(mSampleClipData, ""); - - verify(mTimeoutHandler).resetTimeout(); - } - - @Test - public void test_nonRemoteCopy_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true); - when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(false); - - mOverlayController.setClipDataLegacy(mSampleClipData, ""); - - verify(mTimeoutHandler).resetTimeout(); - } - - @Test - public void test_logsUseLastClipSource_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - - mOverlayController.setClipDataLegacy(mSampleClipData, "first.package"); - mCallbacks.onDismissButtonTapped(); - mOverlayController.setClipDataLegacy(mSampleClipData, "second.package"); - mCallbacks.onDismissButtonTapped(); - - verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, "first.package"); - verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, "second.package"); - verifyNoMoreInteractions(mUiEventLogger); - } - - @Test - public void test_logOnClipboardActionsShown_legacy() { - mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false); - ClipData.Item item = mSampleClipData.getItemAt(0); - item.setTextLinks(Mockito.mock(TextLinks.class)); - mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true); - when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString())) - .thenReturn(true); - when(mClipboardUtils.getAction(any(ClipData.Item.class), anyString())) - .thenReturn(Optional.of(Mockito.mock(RemoteAction.class))); - when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - ((Runnable) invocation.getArgument(0)).run(); - return null; - } - }); - - mOverlayController.setClipDataLegacy( - new ClipData(mSampleClipData.getDescription(), item), "actionShownSource"); - mExecutor.runAllReady(); - - verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_ACTION_SHOWN, 0, "actionShownSource"); - verifyNoMoreInteractions(mUiEventLogger); - } - - // start of refactored setClipData tests - @Test public void test_setClipData_invalidImageData() { ClipData clipData = new ClipData("", new String[]{"image/png"}, new ClipData.Item(Uri.parse(""))); diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java index 3d8f04e08825..673b5eb5dc3c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java @@ -142,81 +142,6 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { assertEquals(actionB, result); } - // TODO(b/267162944): Next four tests (marked "legacy") are obsolete once - // CLIPBOARD_MINIMIZED_LAYOUT flag is released and removed - @Test - public void test_getAction_noLinks_returnsEmptyOptional_legacy() { - ClipData.Item item = new ClipData.Item("no text links"); - item.setTextLinks(Mockito.mock(TextLinks.class)); - - Optional<RemoteAction> action = mClipboardUtils.getAction(item, ""); - - assertTrue(action.isEmpty()); - } - - @Test - public void test_getAction_returnsFirstLink_legacy() { - when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build()); - when(mClipDataItem.getText()).thenReturn(""); - RemoteAction actionA = constructRemoteAction("abc"); - RemoteAction actionB = constructRemoteAction("def"); - TextClassification classificationA = Mockito.mock(TextClassification.class); - when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); - TextClassification classificationB = Mockito.mock(TextClassification.class); - when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); - when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn( - classificationA, classificationB); - - RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null); - - assertEquals(actionA, result); - } - - @Test - public void test_getAction_skipsMatchingComponent_legacy() { - when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build()); - when(mClipDataItem.getText()).thenReturn(""); - RemoteAction actionA = constructRemoteAction("abc"); - RemoteAction actionB = constructRemoteAction("def"); - TextClassification classificationA = Mockito.mock(TextClassification.class); - when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); - TextClassification classificationB = Mockito.mock(TextClassification.class); - when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); - when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn( - classificationA, classificationB); - - RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "abc").orElse(null); - - assertEquals(actionB, result); - } - - @Test - public void test_getAction_skipsShortEntity_legacy() { - TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22"); - final Map<String, Float> scores = new ArrayMap<>(); - scores.put(TextClassifier.TYPE_EMAIL, 1f); - textLinks.addLink(20, 22, scores); - textLinks.addLink(0, 22, scores); - - when(mClipDataItem.getTextLinks()).thenReturn(textLinks.build()); - when(mClipDataItem.getText()).thenReturn(textLinks.build().getText()); - - RemoteAction actionA = constructRemoteAction("abc"); - RemoteAction actionB = constructRemoteAction("def"); - TextClassification classificationA = Mockito.mock(TextClassification.class); - when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); - TextClassification classificationB = Mockito.mock(TextClassification.class); - when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); - when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn( - classificationA); - when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn( - classificationB); - - RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null); - - assertEquals(actionB, result); - } - @Test public void test_extra_withPackage_returnsTrue() { PersistableBundle b = new PersistableBundle(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java new file mode 100644 index 000000000000..ca6282c66a17 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java @@ -0,0 +1,115 @@ +/* + * 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.complication; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.lifecycle.Observer; +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; + +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; +import org.mockito.MockitoAnnotations; + +import java.util.Collection; +import java.util.HashSet; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class ComplicationCollectionLiveDataTest extends SysuiTestCase { + + private FakeExecutor mExecutor; + private DreamOverlayStateController mStateController; + private ComplicationCollectionLiveData mLiveData; + private FakeFeatureFlags mFeatureFlags; + @Mock + private Observer mObserver; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mFeatureFlags = new FakeFeatureFlags(); + mExecutor = new FakeExecutor(new FakeSystemClock()); + mFeatureFlags.set(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS, true); + mStateController = new DreamOverlayStateController( + mExecutor, + /* overlayEnabled= */ true, + mFeatureFlags); + mLiveData = new ComplicationCollectionLiveData(mStateController); + } + + @Test + /** + * Ensures registration and callback lifecycles are respected. + */ + public void testLifecycle() { + final HashSet<Complication> complications = new HashSet<>(); + mLiveData.observeForever(mObserver); + mExecutor.runAllReady(); + // Verify observer called with empty complications + assertObserverCalledWith(complications); + + addComplication(mock(Complication.class), complications); + assertObserverCalledWith(complications); + + addComplication(mock(Complication.class), complications); + assertObserverCalledWith(complications); + + mStateController.setAvailableComplicationTypes(0); + mExecutor.runAllReady(); + assertObserverCalledWith(complications); + mLiveData.removeObserver(mObserver); + } + + private void assertObserverCalledWith(Collection<Complication> targetCollection) { + ArgumentCaptor<Collection<Complication>> collectionCaptor = + ArgumentCaptor.forClass(Collection.class); + + verify(mObserver).onChanged(collectionCaptor.capture()); + + final Collection<Complication> collection = collectionCaptor.getValue(); + + assertThat(collection.containsAll(targetCollection) + && targetCollection.containsAll(collection)).isTrue(); + Mockito.clearInvocations(mObserver); + } + + private void addComplication(Complication complication, + Collection<Complication> complications) { + complications.add(complication); + mStateController.addComplication(complication); + mExecutor.runAllReady(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationHostViewControllerTest.java index 95c689737417..c43df17f498c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationHostViewControllerTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java index 06a944e7a6d3..a1d4fb4dd583 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import static com.google.common.truth.Truth.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java index e414942afb56..286972db57a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import static com.google.common.truth.Truth.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationTypesUpdaterTest.java index 0e16b4771e0f..8cd23b27e4eb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationTypesUpdaterTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.never; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationUtilsTest.java index ea16cb567028..235c56bcc14d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationUtilsTest.java @@ -14,18 +14,18 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; - -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_AIR_QUALITY; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_CAST_INFO; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_DATE; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_HOME_CONTROLS; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_MEDIA_ENTRY; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_SMARTSPACE; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_TIME; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_WEATHER; -import static com.android.systemui.dreams.complication.ComplicationUtils.convertComplicationType; -import static com.android.systemui.dreams.complication.ComplicationUtils.convertComplicationTypes; +package com.android.systemui.complication; + +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_AIR_QUALITY; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_CAST_INFO; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_DATE; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_HOME_CONTROLS; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_MEDIA_ENTRY; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_SMARTSPACE; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_TIME; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_WEATHER; +import static com.android.systemui.complication.ComplicationUtils.convertComplicationType; +import static com.android.systemui.complication.ComplicationUtils.convertComplicationTypes; import static com.google.common.truth.Truth.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationViewModelTransformerTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java index 2bc427d1cd97..206babf9ec44 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationViewModelTransformerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -26,7 +26,7 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.dreams.complication.dagger.ComplicationViewModelComponent; +import com.android.systemui.complication.dagger.ComplicationViewModelComponent; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java index f6662d05c817..57d3a01a4f47 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import static com.google.common.truth.Truth.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java index aad49f9b8069..3cbb24905222 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_HOME_CONTROLS; import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_HOME_CONTROLS; import static com.google.common.truth.Truth.assertThat; @@ -37,6 +37,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.view.LaunchableImageView; +import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.controls.ControlsServiceInfo; import com.android.systemui.controls.controller.ControlsController; @@ -44,7 +45,6 @@ import com.android.systemui.controls.controller.StructureInfo; import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.controls.management.ControlsListingController; import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.shared.condition.Monitor; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamMediaEntryComplicationTest.java index 0295030da510..2bf9ab264bcf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamMediaEntryComplicationTest.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; -import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_MEDIA_ENTRY; +import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_MEDIA_ENTRY; import static com.android.systemui.flags.Flags.DREAM_MEDIA_TAP_TO_OPEN; import static com.google.common.truth.Truth.assertThat; @@ -34,8 +34,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.ActivityIntentHelper; import com.android.systemui.SysuiTestCase; +import com.android.systemui.complication.dagger.DreamMediaEntryComplicationComponent; import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.controls.ui.MediaCarouselController; import com.android.systemui.media.dream.MediaDreamComplication; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/SmartSpaceComplicationTest.java index 175da0b7a5c2..87de8657f593 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/SmartSpaceComplicationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.dreams.complication; +package com.android.systemui.complication; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt index 86e2bd3e0890..df6fa11ff72c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt @@ -22,6 +22,7 @@ import android.graphics.drawable.ShapeDrawable import android.testing.AndroidTestingRunner import android.util.DisplayMetrics import android.view.View +import android.view.ViewGroup import android.widget.PopupWindow.OnDismissListener import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.filters.SmallTest @@ -29,13 +30,17 @@ import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.activity.EmptyTestActivity import com.android.systemui.util.mockito.whenever +import com.android.systemui.widget.FakeListAdapter +import com.android.systemui.widget.FakeListAdapter.FakeListAdapterItem 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.mock import org.mockito.Mockito.spy import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) @@ -52,10 +57,16 @@ open class ControlsPopupMenuTest : SysuiTestCase() { @Rule @JvmField val activityScenarioRule = ActivityScenarioRule(EmptyTestActivity::class.java) - private val testDisplayMetrics: DisplayMetrics = DisplayMetrics() + private val testDisplayMetrics = DisplayMetrics() + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + } @Test - fun testDismissListenerWorks() = testPopup { popupMenu -> + fun testDismissListenerWorks() = testPopup { activity, popupMenu -> + popupMenu.setAdapter(FakeListAdapter()) val listener = mock(OnDismissListener::class.java) popupMenu.setOnDismissListener(listener) popupMenu.show() @@ -66,7 +77,9 @@ open class ControlsPopupMenuTest : SysuiTestCase() { } @Test - fun testPopupDoesntExceedMaxWidth() = testPopup { popupMenu -> + fun testPopupDoesntExceedMaxWidth() = testPopup { activity, popupMenu -> + popupMenu.setAdapter(FakeListAdapter()) + popupMenu.width = ViewGroup.LayoutParams.MATCH_PARENT testDisplayMetrics.widthPixels = DISPLAY_WIDTH_WIDE popupMenu.show() @@ -75,7 +88,28 @@ open class ControlsPopupMenuTest : SysuiTestCase() { } @Test - fun testPopupMarginsWidthLessMax() = testPopup { popupMenu -> + fun testPopupMarginsWidthLessMax() = testPopup { activity, popupMenu -> + popupMenu.setAdapter(FakeListAdapter()) + popupMenu.width = ViewGroup.LayoutParams.MATCH_PARENT + testDisplayMetrics.widthPixels = DISPLAY_WIDTH_NARROW + + popupMenu.show() + + assertThat(popupMenu.width).isEqualTo(DISPLAY_WIDTH_NARROW - 2 * HORIZONTAL_MARGIN) + } + + @Test + fun testWrapContentDoesntExceedMax() = testPopup { activity, popupMenu -> + popupMenu.setAdapter( + FakeListAdapter( + listOf( + FakeListAdapterItem({ _, _, _ -> + View(activity).apply { minimumWidth = MAX_WIDTH + 1 } + }) + ) + ) + ) + popupMenu.width = ViewGroup.LayoutParams.WRAP_CONTENT testDisplayMetrics.widthPixels = DISPLAY_WIDTH_NARROW popupMenu.show() @@ -83,10 +117,13 @@ open class ControlsPopupMenuTest : SysuiTestCase() { assertThat(popupMenu.width).isEqualTo(DISPLAY_WIDTH_NARROW - 2 * HORIZONTAL_MARGIN) } - private fun testPopup(test: (popup: ControlsPopupMenu) -> Unit) { + private fun testPopup(test: (activity: Activity, popup: ControlsPopupMenu) -> Unit) { activityScenarioRule.scenario.onActivity { activity -> val testActivity = setupActivity(activity) - test(ControlsPopupMenu(testActivity).apply { anchorView = View(testActivity) }) + test( + testActivity, + ControlsPopupMenu(testActivity).apply { anchorView = View(testActivity) } + ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt index 0a9470617a5f..b7c62463899f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt @@ -7,7 +7,7 @@ import android.testing.AndroidTestingRunner import android.view.View import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.dreams.complication.ComplicationHostViewController +import com.android.systemui.complication.ComplicationHostViewController import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel import com.android.systemui.statusbar.BlurUtils import com.android.systemui.statusbar.policy.ConfigurationController 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 18abfa546ea6..47b7d49ac7af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java @@ -39,7 +39,7 @@ import androidx.test.filters.SmallTest; import com.android.dream.lowlight.LowLightTransitionCoordinator; import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.systemui.SysuiTestCase; -import com.android.systemui.dreams.complication.ComplicationHostViewController; +import com.android.systemui.complication.ComplicationHostViewController; import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController; import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor; import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index ed737972e286..cfd51e3901bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -49,10 +49,10 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; -import com.android.systemui.dreams.complication.ComplicationLayoutEngine; +import com.android.systemui.complication.ComplicationLayoutEngine; +import com.android.systemui.dreams.complication.HideComplicationTouchHandler; import com.android.systemui.dreams.complication.dagger.ComplicationComponent; import com.android.systemui.dreams.dagger.DreamOverlayComponent; -import com.android.systemui.dreams.dreamcomplication.HideComplicationTouchHandler; import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor; import com.android.systemui.touch.TouchInsetManager; import com.android.systemui.util.concurrency.FakeExecutor; @@ -98,21 +98,20 @@ public class DreamOverlayServiceTest extends SysuiTestCase { WindowManagerImpl mWindowManager; @Mock - ComplicationComponent.Factory mComplicationComponentFactory; + com.android.systemui.complication.dagger.ComplicationComponent.Factory + mComplicationComponentFactory; @Mock - ComplicationComponent mComplicationComponent; + com.android.systemui.complication.dagger.ComplicationComponent mComplicationComponent; @Mock ComplicationLayoutEngine mComplicationVisibilityController; @Mock - com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent.Factory - mDreamComplicationComponentFactory; + ComplicationComponent.Factory mDreamComplicationComponentFactory; @Mock - com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent - mDreamComplicationComponent; + ComplicationComponent mDreamComplicationComponent; @Mock HideComplicationTouchHandler mHideComplicationTouchHandler; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java index b88dbe6be856..f143c46701c7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java @@ -31,7 +31,7 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.dreams.complication.Complication; +import com.android.systemui.complication.Complication; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.util.concurrency.FakeExecutor; @@ -235,6 +235,23 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase { } @Test + public void testComplicationsNotShownForLowLight() { + final Complication complication = Mockito.mock(Complication.class); + final DreamOverlayStateController stateController = getDreamOverlayStateController(true); + + // Add a complication and verify it's returned in getComplications. + stateController.addComplication(complication); + mExecutor.runAllReady(); + assertThat(stateController.getComplications().contains(complication)) + .isTrue(); + + stateController.setLowLightActive(true); + mExecutor.runAllReady(); + + assertThat(stateController.getComplications()).isEmpty(); + } + + @Test public void testNotifyLowLightChanged() { final DreamOverlayStateController stateController = getDreamOverlayStateController(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationCollectionLiveDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationCollectionLiveDataTest.java deleted file mode 100644 index 5fcf414f0251..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationCollectionLiveDataTest.java +++ /dev/null @@ -1,97 +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.dreams.complication; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import androidx.lifecycle.Observer; -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.dreams.DreamOverlayStateController; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -import java.util.Collection; -import java.util.HashSet; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class ComplicationCollectionLiveDataTest extends SysuiTestCase { - @Before - public void setUp() throws Exception { - allowTestableLooperAsMainThread(); - } - - @Test - /** - * Ensures registration and callback lifecycles are respected. - */ - public void testLifecycle() { - getContext().getMainExecutor().execute(() -> { - final DreamOverlayStateController stateController = - Mockito.mock(DreamOverlayStateController.class); - final ComplicationCollectionLiveData liveData = - new ComplicationCollectionLiveData(stateController); - final HashSet<Complication> complications = new HashSet<>(); - final Observer<Collection<Complication>> observer = Mockito.mock(Observer.class); - complications.add(Mockito.mock(Complication.class)); - - when(stateController.getComplications()).thenReturn(complications); - - liveData.observeForever(observer); - ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor = - ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class); - - verify(stateController).addCallback(callbackCaptor.capture()); - verifyUpdate(observer, complications); - - complications.add(Mockito.mock(Complication.class)); - callbackCaptor.getValue().onComplicationsChanged(); - - verifyUpdate(observer, complications); - - callbackCaptor.getValue().onAvailableComplicationTypesChanged(); - - verifyUpdate(observer, complications); - }); - } - - void verifyUpdate(Observer<Collection<Complication>> observer, - Collection<Complication> targetCollection) { - ArgumentCaptor<Collection<Complication>> collectionCaptor = - ArgumentCaptor.forClass(Collection.class); - - verify(observer).onChanged(collectionCaptor.capture()); - - final Collection collection = collectionCaptor.getValue(); - assertThat(collection.containsAll(targetCollection) - && targetCollection.containsAll(collection)).isTrue(); - Mockito.clearInvocations(observer); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java index d68f03246bf6..eed4dbcb7773 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/dreamcomplication/HideComplicationTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.dreams.dreamcomplication; +package com.android.systemui.dreams.complication; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -31,8 +31,8 @@ import androidx.concurrent.futures.CallbackToFutureAdapter; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.complication.Complication; import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.dreams.complication.Complication; import com.android.systemui.dreams.touch.DreamTouchHandler; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java index 08427dab978b..21397d97b578 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java @@ -269,6 +269,30 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase { } @Test + public void testInputEventPropagationAfterRemoval() { + final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); + + final Environment environment = new Environment(Stream.of(touchHandler) + .collect(Collectors.toCollection(HashSet::new))); + + final InputEvent initialEvent = Mockito.mock(InputEvent.class); + environment.publishInputEvent(initialEvent); + + // Ensure session started + final DreamTouchHandler.TouchSession session = captureSession(touchHandler); + final InputChannelCompat.InputEventListener eventListener = + registerInputEventListener(session); + + session.pop(); + environment.executeAll(); + + final InputEvent event = Mockito.mock(InputEvent.class); + environment.publishInputEvent(event); + + verify(eventListener, never()).onInputEvent(eq(event)); + } + + @Test public void testInputGesturePropagation() { final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index c93e677071cd..0de9608b906f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -66,6 +66,8 @@ import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.NotificationShadeWindowControllerImpl; @@ -142,6 +144,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock CentralSurfaces mCentralSurfaces; + private FakeFeatureFlags mFeatureFlags; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -160,6 +164,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mColorExtractor, mDumpManager, mKeyguardStateController, mScreenOffAnimationController, mAuthController, mShadeExpansionStateManager, mShadeWindowLogger); + mFeatureFlags = new FakeFeatureFlags(); + DejankUtils.setImmediate(true); @@ -515,6 +521,28 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { verify(mStatusBarKeyguardViewManager, never()).reset(anyBoolean()); } + @Test + @TestableLooper.RunWithLooper(setAsMainLooper = true) + public void testNotStartingKeyguardWhenFlagIsDisabled() { + mViewMediator.setShowingLocked(false); + when(mKeyguardStateController.isShowing()).thenReturn(false); + + mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, false); + mViewMediator.onDreamingStarted(); + assertFalse(mViewMediator.isShowingAndNotOccluded()); + } + + @Test + @TestableLooper.RunWithLooper(setAsMainLooper = true) + public void testStartingKeyguardWhenFlagIsEnabled() { + mViewMediator.setShowingLocked(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); + + mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, true); + mViewMediator.onDreamingStarted(); + assertTrue(mViewMediator.isShowingAndNotOccluded()); + } + private void createAndStartViewMediator() { mViewMediator = new KeyguardViewMediator( mContext, @@ -545,7 +573,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { () -> mShadeController, () -> mNotificationShadeWindowController, () -> mActivityLaunchAnimator, - () -> mScrimController); + () -> mScrimController, + mFeatureFlags); mViewMediator.start(); mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index 6e002f5a9a9a..fc75d47c01b7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -44,22 +44,28 @@ import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.AuthenticationStatus import com.android.systemui.keyguard.shared.model.DetectionStatus import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.shared.model.WakeSleepReason import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.log.SessionTracker +import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.phone.FakeKeyguardStateController import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.mockito.KotlinArgumentCaptor +import com.android.systemui.util.mockito.captureMany import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.SystemClock import com.google.common.truth.Truth.assertThat import java.io.PrintWriter @@ -81,6 +87,7 @@ import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.isNull import org.mockito.Mockito.mock @@ -115,11 +122,13 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { private lateinit var faceLockoutResetCallback: ArgumentCaptor<FaceManager.LockoutResetCallback> private lateinit var testDispatcher: TestDispatcher + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository private lateinit var testScope: TestScope private lateinit var fakeUserRepository: FakeUserRepository private lateinit var authStatus: FlowValue<AuthenticationStatus?> private lateinit var detectStatus: FlowValue<DetectionStatus?> private lateinit var authRunning: FlowValue<Boolean?> + private lateinit var bypassEnabled: FlowValue<Boolean?> private lateinit var lockedOut: FlowValue<Boolean?> private lateinit var canFaceAuthRun: FlowValue<Boolean?> private lateinit var authenticated: FlowValue<Boolean?> @@ -180,8 +189,14 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { private fun createDeviceEntryFaceAuthRepositoryImpl( fmOverride: FaceManager? = faceManager, bypassControllerOverride: KeyguardBypassController? = bypassController - ) = - DeviceEntryFaceAuthRepositoryImpl( + ): DeviceEntryFaceAuthRepositoryImpl { + val systemClock = FakeSystemClock() + val faceAuthBuffer = TableLogBuffer(10, "face auth", systemClock) + val faceDetectBuffer = TableLogBuffer(10, "face detect", systemClock) + keyguardTransitionRepository = FakeKeyguardTransitionRepository() + val keyguardTransitionInteractor = + KeyguardTransitionInteractor(keyguardTransitionRepository) + return DeviceEntryFaceAuthRepositoryImpl( mContext, fmOverride, fakeUserRepository, @@ -197,8 +212,12 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { keyguardRepository, keyguardInteractor, alternateBouncerInteractor, + faceDetectBuffer, + faceAuthBuffer, + keyguardTransitionInteractor, dumpManager, ) + } @Test fun faceAuthRunsAndProvidesAuthStatusUpdates() = @@ -726,6 +745,23 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test + fun isBypassEnabledReflectsBypassControllerState() = + testScope.runTest { + initCollectors() + runCurrent() + val listeners = captureMany { + verify(bypassController, atLeastOnce()) + .registerOnBypassStateChangedListener(capture()) + } + + listeners.forEach { it.onBypassStateChanged(true) } + assertThat(bypassEnabled()).isTrue() + + listeners.forEach { it.onBypassStateChanged(false) } + assertThat(bypassEnabled()).isFalse() + } + + @Test fun detectDoesNotRunWhenNonStrongBiometricIsAllowed() = testScope.runTest { testGatingCheckForDetect { @@ -744,6 +780,50 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } } + @Test + fun schedulesFaceManagerWatchdogWhenKeyguardIsGoneFromDozing() = + testScope.runTest { + keyguardTransitionRepository.sendTransitionStep( + TransitionStep(from = KeyguardState.DOZING, to = KeyguardState.GONE) + ) + + runCurrent() + verify(faceManager).scheduleWatchdog() + } + + @Test + fun schedulesFaceManagerWatchdogWhenKeyguardIsGoneFromAod() = + testScope.runTest { + keyguardTransitionRepository.sendTransitionStep( + TransitionStep(from = KeyguardState.AOD, to = KeyguardState.GONE) + ) + + runCurrent() + verify(faceManager).scheduleWatchdog() + } + + @Test + fun schedulesFaceManagerWatchdogWhenKeyguardIsGoneFromLockscreen() = + testScope.runTest { + keyguardTransitionRepository.sendTransitionStep( + TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE) + ) + + runCurrent() + verify(faceManager).scheduleWatchdog() + } + + @Test + fun schedulesFaceManagerWatchdogWhenKeyguardIsGoneFromBouncer() = + testScope.runTest { + keyguardTransitionRepository.sendTransitionStep( + TransitionStep(from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE) + ) + + runCurrent() + verify(faceManager).scheduleWatchdog() + } + private suspend fun TestScope.testGatingCheckForFaceAuth(gatingCheckModifier: () -> Unit) { initCollectors() allPreconditionsToRunFaceAuthAreTrue() @@ -844,6 +924,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { lockedOut = collectLastValue(underTest.isLockedOut) canFaceAuthRun = collectLastValue(underTest.canRunFaceAuth) authenticated = collectLastValue(underTest.isAuthenticated) + bypassEnabled = collectLastValue(underTest.isBypassEnabled) fakeUserRepository.setSelectedUserInfo(primaryUser) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt index 86e8c9accc45..a668af340e7b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt @@ -41,6 +41,7 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat +import java.util.Locale import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope @@ -67,6 +68,7 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { @Before fun setUp() { + context.resources.configuration.setLayoutDirection(Locale.US) config1 = FakeKeyguardQuickAffordanceConfig(FakeCustomizationProviderClient.AFFORDANCE_1) config2 = FakeKeyguardQuickAffordanceConfig(FakeCustomizationProviderClient.AFFORDANCE_2) val testDispatcher = StandardTestDispatcher() @@ -222,6 +224,40 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { } @Test + fun getSlotPickerRepresentations_rightToLeft_slotsReversed() { + context.resources.configuration.setLayoutDirection(Locale("he", "IL")) + val slot1 = "slot1" + val slot2 = "slot2" + val slot3 = "slot3" + context.orCreateTestableResources.addOverride( + R.array.config_keyguardQuickAffordanceSlots, + arrayOf( + "$slot1:2", + "$slot2:4", + "$slot3:5", + ), + ) + + assertThat(underTest.getSlotPickerRepresentations()) + .isEqualTo( + listOf( + KeyguardSlotPickerRepresentation( + id = slot3, + maxSelectedAffordances = 5, + ), + KeyguardSlotPickerRepresentation( + id = slot2, + maxSelectedAffordances = 4, + ), + KeyguardSlotPickerRepresentation( + id = slot1, + maxSelectedAffordances = 2, + ), + ) + ) + } + + @Test fun `selections for secondary user`() = testScope.runTest { userTracker.set( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt new file mode 100644 index 000000000000..3d1d2f46a65e --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt @@ -0,0 +1,292 @@ +/* + * 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.keyguard.domain.interactor + +import android.os.Handler +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.keyguard.FaceAuthUiEvent +import com.android.keyguard.KeyguardSecurityModel +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.DismissCallbackRegistry +import com.android.systemui.keyguard.data.BouncerView +import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository +import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository +import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.log.FaceAuthenticationLogger +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestCoroutineScheduler +import kotlinx.coroutines.test.TestScope +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.mock +import org.mockito.MockitoAnnotations + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class KeyguardFaceAuthInteractorTest : SysuiTestCase() { + + private lateinit var underTest: SystemUIKeyguardFaceAuthInteractor + private lateinit var testScope: TestScope + private lateinit var bouncerRepository: FakeKeyguardBouncerRepository + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor + private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository + + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + val scheduler = TestCoroutineScheduler() + val dispatcher = StandardTestDispatcher(scheduler) + testScope = TestScope(dispatcher) + val featureFlags = FakeFeatureFlags() + featureFlags.set(Flags.FACE_AUTH_REFACTOR, true) + bouncerRepository = FakeKeyguardBouncerRepository() + faceAuthRepository = FakeDeviceEntryFaceAuthRepository() + keyguardTransitionRepository = FakeKeyguardTransitionRepository() + keyguardTransitionInteractor = KeyguardTransitionInteractor(keyguardTransitionRepository) + + underTest = + SystemUIKeyguardFaceAuthInteractor( + testScope.backgroundScope, + dispatcher, + faceAuthRepository, + PrimaryBouncerInteractor( + bouncerRepository, + mock(BouncerView::class.java), + mock(Handler::class.java), + mock(KeyguardStateController::class.java), + mock(KeyguardSecurityModel::class.java), + mock(PrimaryBouncerCallbackInteractor::class.java), + mock(FalsingCollector::class.java), + mock(DismissCallbackRegistry::class.java), + context, + keyguardUpdateMonitor, + mock(KeyguardBypassController::class.java), + ), + AlternateBouncerInteractor( + mock(StatusBarStateController::class.java), + mock(KeyguardStateController::class.java), + bouncerRepository, + mock(BiometricSettingsRepository::class.java), + FakeDeviceEntryFingerprintAuthRepository(), + FakeSystemClock(), + ), + keyguardTransitionInteractor, + featureFlags, + FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")), + keyguardUpdateMonitor, + ) + } + + @Test + fun faceAuthIsRequestedWhenLockscreenBecomesVisibleFromOffState() = + testScope.runTest { + underTest.start() + + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + KeyguardState.OFF, + KeyguardState.LOCKSCREEN, + transitionState = TransitionState.STARTED + ) + ) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo( + Pair(FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED, true) + ) + } + + @Test + fun faceAuthIsRequestedWhenLockscreenBecomesVisibleFromAodState() = + testScope.runTest { + underTest.start() + + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + KeyguardState.AOD, + KeyguardState.LOCKSCREEN, + transitionState = TransitionState.STARTED + ) + ) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo( + Pair(FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED, true) + ) + } + + @Test + fun faceAuthIsRequestedWhenLockscreenBecomesVisibleFromDozingState() = + testScope.runTest { + underTest.start() + + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + KeyguardState.DOZING, + KeyguardState.LOCKSCREEN, + transitionState = TransitionState.STARTED + ) + ) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo( + Pair(FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED, true) + ) + } + + @Test + fun faceAuthIsRequestedWhenPrimaryBouncerIsVisible() = + testScope.runTest { + underTest.start() + + bouncerRepository.setPrimaryShow(false) + runCurrent() + + bouncerRepository.setPrimaryShow(true) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN, true)) + } + + @Test + fun faceAuthIsRequestedWhenAlternateBouncerIsVisible() = + testScope.runTest { + underTest.start() + + bouncerRepository.setAlternateVisible(false) + runCurrent() + + bouncerRepository.setAlternateVisible(true) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo( + Pair( + FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN, + false + ) + ) + } + + @Test + fun faceAuthIsRequestedWhenUdfpsSensorTouched() = + testScope.runTest { + underTest.start() + + underTest.onUdfpsSensorTouched() + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_UDFPS_POINTER_DOWN, false)) + } + + @Test + fun faceAuthIsRequestedWhenOnAssistantTriggeredOnLockScreen() = + testScope.runTest { + underTest.start() + + underTest.onAssistantTriggeredOnLockScreen() + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo( + Pair(FaceAuthUiEvent.FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED, true) + ) + } + + @Test + fun faceAuthIsRequestedWhenDeviceLifted() = + testScope.runTest { + underTest.start() + + underTest.onDeviceLifted() + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo( + Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_PICK_UP_GESTURE_TRIGGERED, true) + ) + } + + @Test + fun faceAuthIsRequestedWhenQsExpansionStared() = + testScope.runTest { + underTest.start() + + underTest.onQsExpansionStared() + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED, true)) + } + + @Test + fun faceAuthIsRequestedWhenNotificationPanelClicked() = + testScope.runTest { + underTest.start() + + underTest.onNotificationPanelClicked() + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo( + Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED, true) + ) + } + + @Test + fun faceAuthIsRequestedWhenSwipeUpOnBouncer() = + testScope.runTest { + underTest.start() + + underTest.onSwipeUpOnBouncer() + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER, false)) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt index 51988ef1ab78..77bb12c2cbda 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt @@ -29,20 +29,20 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.util.mockito.any +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper +import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.runBlocking 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.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock -import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -51,8 +51,8 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class KeyguardLongPressInteractorTest : SysuiTestCase() { - @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var logger: UiEventLogger + @Mock private lateinit var accessibilityManager: AccessibilityManagerWrapper private lateinit var underTest: KeyguardLongPressInteractor @@ -63,6 +63,14 @@ class KeyguardLongPressInteractorTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) + whenever(accessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenAnswer { + it.arguments[0] + } + + testScope = TestScope() + keyguardRepository = FakeKeyguardRepository() + keyguardTransitionRepository = FakeKeyguardTransitionRepository() + runBlocking { createUnderTest() } } @@ -98,60 +106,117 @@ class KeyguardLongPressInteractorTest : SysuiTestCase() { } @Test - fun `long-pressed - pop-up clicked - starts activity`() = + fun longPressed_menuClicked_showsSettings() = testScope.runTest { - val menu = collectLastValue(underTest.menu) + val isMenuVisible by collectLastValue(underTest.isMenuVisible) + val shouldOpenSettings by collectLastValue(underTest.shouldOpenSettings) runCurrent() - val x = 100 - val y = 123 - underTest.onLongPress(x, y) - assertThat(menu()).isNotNull() - assertThat(menu()?.position?.x).isEqualTo(x) - assertThat(menu()?.position?.y).isEqualTo(y) + underTest.onLongPress() + assertThat(isMenuVisible).isTrue() + + underTest.onMenuTouchGestureEnded(/* isClick= */ true) + + assertThat(isMenuVisible).isFalse() + assertThat(shouldOpenSettings).isTrue() + } + + @Test + fun onSettingsShown_consumesSettingsShowEvent() = + testScope.runTest { + val shouldOpenSettings by collectLastValue(underTest.shouldOpenSettings) + runCurrent() - menu()?.onClicked?.invoke() + underTest.onLongPress() + underTest.onMenuTouchGestureEnded(/* isClick= */ true) + assertThat(shouldOpenSettings).isTrue() - assertThat(menu()).isNull() - verify(activityStarter).dismissKeyguardThenExecute(any(), any(), anyBoolean()) + underTest.onSettingsShown() + assertThat(shouldOpenSettings).isFalse() } @Test - fun `long-pressed - pop-up dismissed - never starts activity`() = + fun onTouchedOutside_neverShowsSettings() = testScope.runTest { - val menu = collectLastValue(underTest.menu) + val isMenuVisible by collectLastValue(underTest.isMenuVisible) + val shouldOpenSettings by collectLastValue(underTest.shouldOpenSettings) runCurrent() - menu()?.onDismissed?.invoke() + underTest.onTouchedOutside() - assertThat(menu()).isNull() - verify(activityStarter, never()).dismissKeyguardThenExecute(any(), any(), anyBoolean()) + assertThat(isMenuVisible).isFalse() + assertThat(shouldOpenSettings).isFalse() + } + + @Test + fun longPressed_openWppDirectlyEnabled_doesNotShowMenu_opensSettings() = + testScope.runTest { + createUnderTest(isOpenWppDirectlyEnabled = true) + val isMenuVisible by collectLastValue(underTest.isMenuVisible) + val shouldOpenSettings by collectLastValue(underTest.shouldOpenSettings) + runCurrent() + + underTest.onLongPress() + + assertThat(isMenuVisible).isFalse() + assertThat(shouldOpenSettings).isTrue() } - @Suppress("DEPRECATION") // We're okay using ACTION_CLOSE_SYSTEM_DIALOGS on system UI. @Test fun `long pressed - close dialogs broadcast received - popup dismissed`() = testScope.runTest { - val menu = collectLastValue(underTest.menu) + val isMenuVisible by collectLastValue(underTest.isMenuVisible) runCurrent() - underTest.onLongPress(123, 456) - assertThat(menu()).isNotNull() + underTest.onLongPress() + assertThat(isMenuVisible).isTrue() fakeBroadcastDispatcher.registeredReceivers.forEach { broadcastReceiver -> broadcastReceiver.onReceive(context, Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) } - assertThat(menu()).isNull() + assertThat(isMenuVisible).isFalse() + } + + @Test + fun closesDialogAfterTimeout() = + testScope.runTest { + val isMenuVisible by collectLastValue(underTest.isMenuVisible) + runCurrent() + + underTest.onLongPress() + assertThat(isMenuVisible).isTrue() + + advanceTimeBy(KeyguardLongPressInteractor.DEFAULT_POPUP_AUTO_HIDE_TIMEOUT_MS) + + assertThat(isMenuVisible).isFalse() + } + + @Test + fun closesDialogAfterTimeout_onlyAfterTouchGestureEnded() = + testScope.runTest { + val isMenuVisible by collectLastValue(underTest.isMenuVisible) + runCurrent() + + underTest.onLongPress() + assertThat(isMenuVisible).isTrue() + underTest.onMenuTouchGestureStarted() + + advanceTimeBy(KeyguardLongPressInteractor.DEFAULT_POPUP_AUTO_HIDE_TIMEOUT_MS) + assertThat(isMenuVisible).isTrue() + + underTest.onMenuTouchGestureEnded(/* isClick= */ false) + advanceTimeBy(KeyguardLongPressInteractor.DEFAULT_POPUP_AUTO_HIDE_TIMEOUT_MS) + assertThat(isMenuVisible).isFalse() } @Test fun `logs when menu is shown`() = testScope.runTest { - collectLastValue(underTest.menu) + collectLastValue(underTest.isMenuVisible) runCurrent() - underTest.onLongPress(100, 123) + underTest.onLongPress() verify(logger) .log(KeyguardLongPressInteractor.LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_SHOWN) @@ -160,41 +225,61 @@ class KeyguardLongPressInteractorTest : SysuiTestCase() { @Test fun `logs when menu is clicked`() = testScope.runTest { - val menu = collectLastValue(underTest.menu) + collectLastValue(underTest.isMenuVisible) runCurrent() - underTest.onLongPress(100, 123) - menu()?.onClicked?.invoke() + underTest.onLongPress() + underTest.onMenuTouchGestureEnded(/* isClick= */ true) verify(logger) .log(KeyguardLongPressInteractor.LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_CLICKED) } + @Test + fun showMenu_leaveLockscreen_returnToLockscreen_menuNotVisible() = + testScope.runTest { + val isMenuVisible by collectLastValue(underTest.isMenuVisible) + runCurrent() + underTest.onLongPress() + assertThat(isMenuVisible).isTrue() + + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + to = KeyguardState.GONE, + ), + ) + assertThat(isMenuVisible).isFalse() + + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + to = KeyguardState.LOCKSCREEN, + ), + ) + assertThat(isMenuVisible).isFalse() + } + private suspend fun createUnderTest( isLongPressFeatureEnabled: Boolean = true, isRevampedWppFeatureEnabled: Boolean = true, + isOpenWppDirectlyEnabled: Boolean = false, ) { - testScope = TestScope() - keyguardRepository = FakeKeyguardRepository() - keyguardTransitionRepository = FakeKeyguardTransitionRepository() - underTest = KeyguardLongPressInteractor( - unsafeContext = context, scope = testScope.backgroundScope, transitionInteractor = KeyguardTransitionInteractor( repository = keyguardTransitionRepository, ), repository = keyguardRepository, - activityStarter = activityStarter, logger = logger, featureFlags = FakeFeatureFlags().apply { set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, isLongPressFeatureEnabled) set(Flags.REVAMPED_WALLPAPER_UI, isRevampedWppFeatureEnabled) + set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, isOpenWppDirectlyEnabled) }, broadcastDispatcher = fakeBroadcastDispatcher, + accessibilityManager = accessibilityManager ) setUpState() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index bfc09d7c0379..224eec1bf3ac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt @@ -20,10 +20,12 @@ import android.app.admin.DevicePolicyManager import android.content.Intent import android.os.UserHandle import androidx.test.filters.SmallTest +import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.animation.Expandable +import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.shared.model.Icon import com.android.systemui.coroutines.collectLastValue import com.android.systemui.doze.util.BurnInHelperWrapper @@ -38,10 +40,13 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardLongPressInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition @@ -51,6 +56,7 @@ import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.any @@ -91,6 +97,8 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { @Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger + @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock private lateinit var accessibilityManager: AccessibilityManagerWrapper private lateinit var underTest: KeyguardBottomAreaViewModel @@ -134,6 +142,8 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { FakeFeatureFlags().apply { set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false) set(Flags.FACE_AUTH_REFACTOR, true) + set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false) + set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, false) } val keyguardInteractor = @@ -196,6 +206,19 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { dumpManager = mock(), userHandle = UserHandle.SYSTEM, ) + val keyguardLongPressInteractor = + KeyguardLongPressInteractor( + scope = testScope.backgroundScope, + transitionInteractor = + KeyguardTransitionInteractor( + repository = FakeKeyguardTransitionRepository(), + ), + repository = repository, + logger = UiEventLoggerFake(), + featureFlags = featureFlags, + broadcastDispatcher = broadcastDispatcher, + accessibilityManager = accessibilityManager, + ) underTest = KeyguardBottomAreaViewModel( keyguardInteractor = keyguardInteractor, @@ -216,6 +239,14 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { ), bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository), burnInHelperWrapper = burnInHelperWrapper, + longPressViewModel = + KeyguardLongPressViewModel( + interactor = keyguardLongPressInteractor, + ), + settingsMenuViewModel = + KeyguardSettingsMenuViewModel( + interactor = keyguardLongPressInteractor, + ), ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt index d428db7b9dda..0a1db60e075c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt @@ -40,6 +40,7 @@ import android.testing.TestableLooper.RunWithLooper import androidx.media.utils.MediaConstants import androidx.test.filters.SmallTest import com.android.internal.logging.InstanceId +import com.android.internal.statusbar.IStatusBarService import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.InstanceIdSequenceFake import com.android.systemui.R @@ -130,6 +131,7 @@ class MediaDataManagerTest : SysuiTestCase() { @Mock lateinit var activityStarter: ActivityStarter @Mock lateinit var smartspaceManager: SmartspaceManager @Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + @Mock lateinit var statusBarService: IStatusBarService lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider @Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget @Mock private lateinit var mediaRecommendationItem: SmartspaceAction @@ -192,7 +194,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaFlags = mediaFlags, logger = logger, smartspaceManager = smartspaceManager, - keyguardUpdateMonitor = keyguardUpdateMonitor + keyguardUpdateMonitor = keyguardUpdateMonitor, + statusBarService = statusBarService, ) verify(tunerService) .addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION)) @@ -517,19 +520,136 @@ class MediaDataManagerTest : SysuiTestCase() { } @Test - fun testOnNotificationRemoved_emptyTitle_notConverted() { - // GIVEN that the manager has a notification with a resume action and empty title. + fun testOnNotificationAdded_emptyTitle_notLoaded() { + // GIVEN that the manager has a notification with an empty title. whenever(controller.metadata) .thenReturn( metadataBuilder .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE) .build() ) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + verify(statusBarService) + .onNotificationError( + eq(PACKAGE_NAME), + eq(mediaNotification.tag), + eq(mediaNotification.id), + eq(mediaNotification.uid), + eq(mediaNotification.initialPid), + eq(MEDIA_TITLE_ERROR_MESSAGE), + eq(mediaNotification.user.identifier) + ) + verify(listener, never()) + .onMediaDataLoaded( + eq(KEY), + eq(null), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + verify(logger, never()).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), any()) + verify(logger, never()).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), any()) + } + + @Test + fun testOnNotificationAdded_blankTitle_notLoaded() { + // GIVEN that the manager has a notification with a blank title. + whenever(controller.metadata) + .thenReturn( + metadataBuilder + .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE) + .build() + ) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + verify(statusBarService) + .onNotificationError( + eq(PACKAGE_NAME), + eq(mediaNotification.tag), + eq(mediaNotification.id), + eq(mediaNotification.uid), + eq(mediaNotification.initialPid), + eq(MEDIA_TITLE_ERROR_MESSAGE), + eq(mediaNotification.user.identifier) + ) + verify(listener, never()) + .onMediaDataLoaded( + eq(KEY), + eq(null), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + verify(logger, never()).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), any()) + verify(logger, never()).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), any()) + } + + @Test + fun testOnNotificationUpdated_invalidTitle_logMediaRemoved() { + addNotificationAndLoad() + val data = mediaDataCaptor.value + + verify(listener) + .onMediaDataLoaded( + eq(KEY), + eq(null), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + + reset(listener) + whenever(controller.metadata) + .thenReturn( + metadataBuilder + .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE) + .build() + ) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + verify(statusBarService) + .onNotificationError( + eq(PACKAGE_NAME), + eq(mediaNotification.tag), + eq(mediaNotification.id), + eq(mediaNotification.uid), + eq(mediaNotification.initialPid), + eq(MEDIA_TITLE_ERROR_MESSAGE), + eq(mediaNotification.user.identifier) + ) + verify(listener, never()) + .onMediaDataLoaded( + eq(KEY), + eq(null), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) + } + + @Test + fun testOnNotificationRemoved_emptyTitle_notConverted() { + // GIVEN that the manager has a notification with a resume action and empty title. addNotificationAndLoad() val data = mediaDataCaptor.value val instanceId = data.instanceId assertThat(data.resumption).isFalse() - mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) + mediaDataManager.onMediaDataLoaded( + KEY, + null, + data.copy(song = SESSION_EMPTY_TITLE, resumeAction = Runnable {}) + ) // WHEN the notification is removed reset(listener) @@ -554,17 +674,15 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testOnNotificationRemoved_blankTitle_notConverted() { // GIVEN that the manager has a notification with a resume action and blank title. - whenever(controller.metadata) - .thenReturn( - metadataBuilder - .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE) - .build() - ) addNotificationAndLoad() val data = mediaDataCaptor.value val instanceId = data.instanceId assertThat(data.resumption).isFalse() - mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) + mediaDataManager.onMediaDataLoaded( + KEY, + null, + data.copy(song = SESSION_BLANK_TITLE, resumeAction = Runnable {}) + ) // WHEN the notification is removed reset(listener) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt index 543875dc31cf..1e465c791795 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt @@ -24,6 +24,7 @@ import android.content.Context import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.PackageManager +import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color @@ -42,6 +43,7 @@ import android.os.Bundle import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS import android.testing.AndroidTestingRunner import android.testing.TestableLooper +import android.util.TypedValue import android.view.View import android.view.ViewGroup import android.view.animation.Interpolator @@ -2199,7 +2201,7 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test - fun bindRecommendation_carouselNotFitThreeRecs() { + fun bindRecommendation_carouselNotFitThreeRecs_OrientationPortrait() { useRealConstraintSets() setupUpdatedRecommendationViewHolder() val albumArt = getColorIcon(Color.RED) @@ -2227,16 +2229,84 @@ public class MediaControlPanelTest : SysuiTestCase() { // set the screen width less than the width of media controls. player.context.resources.configuration.screenWidthDp = 350 + player.context.resources.configuration.orientation = Configuration.ORIENTATION_PORTRAIT player.attachRecommendation(recommendationViewHolder) player.bindRecommendation(data) - assertThat(player.numberOfFittedRecommendations).isEqualTo(2) - assertThat(expandedSet.getVisibility(coverContainer1.id)).isEqualTo(ConstraintSet.VISIBLE) - assertThat(collapsedSet.getVisibility(coverContainer1.id)).isEqualTo(ConstraintSet.VISIBLE) - assertThat(expandedSet.getVisibility(coverContainer2.id)).isEqualTo(ConstraintSet.VISIBLE) - assertThat(collapsedSet.getVisibility(coverContainer2.id)).isEqualTo(ConstraintSet.VISIBLE) - assertThat(expandedSet.getVisibility(coverContainer3.id)).isEqualTo(ConstraintSet.GONE) - assertThat(collapsedSet.getVisibility(coverContainer3.id)).isEqualTo(ConstraintSet.GONE) + val res = player.context.resources + val displayAvailableWidth = + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 350f, res.displayMetrics).toInt() + val recCoverWidth: Int = + (res.getDimensionPixelSize(R.dimen.qs_media_rec_album_width) + + res.getDimensionPixelSize(R.dimen.qs_media_info_spacing) * 2) + val numOfRecs = displayAvailableWidth / recCoverWidth + + assertThat(player.numberOfFittedRecommendations).isEqualTo(numOfRecs) + recommendationViewHolder.mediaCoverContainers.forEachIndexed { index, container -> + if (index < numOfRecs) { + assertThat(expandedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.VISIBLE) + assertThat(collapsedSet.getVisibility(container.id)) + .isEqualTo(ConstraintSet.VISIBLE) + } else { + assertThat(expandedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.GONE) + assertThat(collapsedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.GONE) + } + } + } + + @Test + fun bindRecommendation_carouselNotFitThreeRecs_OrientationLandscape() { + useRealConstraintSets() + setupUpdatedRecommendationViewHolder() + val albumArt = getColorIcon(Color.RED) + val data = + smartspaceData.copy( + recommendations = + listOf( + SmartspaceAction.Builder("id1", "title1") + .setSubtitle("subtitle1") + .setIcon(albumArt) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id2", "title2") + .setSubtitle("subtitle1") + .setIcon(albumArt) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id3", "title3") + .setSubtitle("subtitle1") + .setIcon(albumArt) + .setExtras(Bundle.EMPTY) + .build() + ) + ) + + // set the screen width less than the width of media controls. + // We should have dp width less than 378 to test. In landscape we should have 2x. + player.context.resources.configuration.screenWidthDp = 700 + player.context.resources.configuration.orientation = Configuration.ORIENTATION_LANDSCAPE + player.attachRecommendation(recommendationViewHolder) + player.bindRecommendation(data) + + val res = player.context.resources + val displayAvailableWidth = + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 350f, res.displayMetrics).toInt() + val recCoverWidth: Int = + (res.getDimensionPixelSize(R.dimen.qs_media_rec_album_width) + + res.getDimensionPixelSize(R.dimen.qs_media_info_spacing) * 2) + val numOfRecs = displayAvailableWidth / recCoverWidth + + assertThat(player.numberOfFittedRecommendations).isEqualTo(numOfRecs) + recommendationViewHolder.mediaCoverContainers.forEachIndexed { index, container -> + if (index < numOfRecs) { + assertThat(expandedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.VISIBLE) + assertThat(collapsedSet.getVisibility(container.id)) + .isEqualTo(ConstraintSet.VISIBLE) + } else { + assertThat(expandedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.GONE) + assertThat(collapsedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.GONE) + } + } } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt new file mode 100644 index 000000000000..86f3062bca35 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt @@ -0,0 +1,75 @@ +/* + * 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.controls.util + +import android.testing.AndroidTestingRunner +import android.util.Pair as APair +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 MediaDataUtilsTest : SysuiTestCase() { + + @Test + fun testScaleFactor_zeroInput_returnsZero() { + val input = APair(0, 0) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(0f) + } + + @Test + fun testScaleFactor_tooWide_scaleDown() { + val input = APair(400, 200) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(0.5f) + } + + @Test + fun testScaleFactor_tooTall_scaleDown() { + val input = APair(200, 400) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(0.5f) + } + + @Test + fun testScaleFactor_lessWide_scaleUp() { + val input = APair(50, 100) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(2f) + } + + @Test + fun testScaleFactor_lessTall_scaleUp() { + val input = APair(100, 50) + val target = APair(100, 100) + + val scale = MediaDataUtils.getScaleFactor(input, target) + assertThat(scale).isEqualTo(2f) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java index 9a0bd9e4b0df..f206409a071e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java @@ -255,10 +255,10 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { mLocalBluetoothLeBroadcast); mIsBroadcasting = true; - mMediaOutputBaseDialogImpl.onStart(); + mMediaOutputBaseDialogImpl.start(); verify(mLocalBluetoothLeBroadcast).registerServiceCallBack(any(), any()); - mMediaOutputBaseDialogImpl.onStop(); + mMediaOutputBaseDialogImpl.stop(); verify(mLocalBluetoothLeBroadcast).unregisterServiceCallBack(any()); } @@ -269,8 +269,8 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { mLocalBluetoothLeBroadcast); mIsBroadcasting = false; - mMediaOutputBaseDialogImpl.onStart(); - mMediaOutputBaseDialogImpl.onStop(); + mMediaOutputBaseDialogImpl.start(); + mMediaOutputBaseDialogImpl.stop(); verify(mLocalBluetoothLeBroadcast, never()).registerServiceCallBack(any(), any()); verify(mLocalBluetoothLeBroadcast, never()).unregisterServiceCallBack(any()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java index ed928a35a20e..8a316642a3b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java @@ -30,8 +30,8 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.complication.DreamMediaEntryComplication; import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.dreams.complication.DreamMediaEntryComplication; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.controls.models.player.MediaData; import com.android.systemui.media.controls.pipeline.MediaDataManager; 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 ba29ca57cefb..22a5b21f71ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt @@ -63,8 +63,10 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock +import org.mockito.Mockito.doNothing import org.mockito.Mockito.isNull import org.mockito.Mockito.never +import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.verifyZeroInteractions import org.mockito.MockitoAnnotations @@ -75,7 +77,9 @@ import org.mockito.MockitoAnnotations internal class NoteTaskControllerTest : SysuiTestCase() { @Mock private lateinit var context: Context + @Mock private lateinit var workProfileContext: Context @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var workProfilePackageManager: PackageManager @Mock private lateinit var resolver: NoteTaskInfoResolver @Mock private lateinit var bubbles: Bubbles @Mock private lateinit var keyguardManager: KeyguardManager @@ -107,6 +111,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { .thenReturn(listOf(NOTE_TASK_PACKAGE_NAME)) whenever(activityManager.getRunningTasks(anyInt())).thenReturn(emptyList()) whenever(userManager.isManagedProfile(workUserInfo.id)).thenReturn(true) + whenever(context.resources).thenReturn(getContext().resources) } private fun createNoteTaskController( @@ -337,14 +342,14 @@ internal class NoteTaskControllerTest : SysuiTestCase() { } @Test - fun showNoteTask_intentResolverReturnsNull_shouldDoNothing() { + fun showNoteTask_intentResolverReturnsNull_shouldShowToast() { whenever(resolver.resolveInfo(any(), any())).thenReturn(null) + val noteTaskController = spy(createNoteTaskController()) + doNothing().whenever(noteTaskController).showNoDefaultNotesAppToast() - createNoteTaskController() - .showNoteTask( - entryPoint = NoteTaskEntryPoint.TAIL_BUTTON, - ) + noteTaskController.showNoteTask(entryPoint = NoteTaskEntryPoint.TAIL_BUTTON) + verify(noteTaskController).showNoDefaultNotesAppToast() verifyZeroInteractions(context, bubbles, eventLogger) } @@ -373,17 +378,17 @@ internal class NoteTaskControllerTest : SysuiTestCase() { @Test fun showNoteTask_keyboardShortcut_shouldStartActivity() { val expectedInfo = - NOTE_TASK_INFO.copy( - entryPoint = NoteTaskEntryPoint.KEYBOARD_SHORTCUT, - isKeyguardLocked = true, - ) + NOTE_TASK_INFO.copy( + entryPoint = NoteTaskEntryPoint.KEYBOARD_SHORTCUT, + isKeyguardLocked = true, + ) whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked) whenever(resolver.resolveInfo(any(), any())).thenReturn(expectedInfo) createNoteTaskController() - .showNoteTask( - entryPoint = expectedInfo.entryPoint!!, - ) + .showNoteTask( + entryPoint = expectedInfo.entryPoint!!, + ) val intentCaptor = argumentCaptor<Intent>() val userCaptor = argumentCaptor<UserHandle>() @@ -393,9 +398,9 @@ internal class NoteTaskControllerTest : SysuiTestCase() { assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME) assertThat(intent.flags and FLAG_ACTIVITY_NEW_TASK).isEqualTo(FLAG_ACTIVITY_NEW_TASK) assertThat(intent.flags and FLAG_ACTIVITY_MULTIPLE_TASK) - .isEqualTo(FLAG_ACTIVITY_MULTIPLE_TASK) + .isEqualTo(FLAG_ACTIVITY_MULTIPLE_TASK) assertThat(intent.flags and FLAG_ACTIVITY_NEW_DOCUMENT) - .isEqualTo(FLAG_ACTIVITY_NEW_DOCUMENT) + .isEqualTo(FLAG_ACTIVITY_NEW_DOCUMENT) assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, true)).isFalse() } assertThat(userCaptor.value).isEqualTo(userTracker.userHandle) @@ -407,7 +412,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { // region setNoteTaskShortcutEnabled @Test fun setNoteTaskShortcutEnabled_setTrue() { - createNoteTaskController().setNoteTaskShortcutEnabled(value = true) + createNoteTaskController().setNoteTaskShortcutEnabled(value = true, userTracker.userHandle) val argument = argumentCaptor<ComponentName>() verify(context.packageManager) @@ -422,7 +427,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { @Test fun setNoteTaskShortcutEnabled_setFalse() { - createNoteTaskController().setNoteTaskShortcutEnabled(value = false) + createNoteTaskController().setNoteTaskShortcutEnabled(value = false, userTracker.userHandle) val argument = argumentCaptor<ComponentName>() verify(context.packageManager) @@ -434,6 +439,47 @@ internal class NoteTaskControllerTest : SysuiTestCase() { assertThat(argument.value.className) .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) } + + @Test + fun setNoteTaskShortcutEnabled_workProfileUser_setTrue() { + whenever(context.createContextAsUser(eq(workUserInfo.userHandle), any())) + .thenReturn(workProfileContext) + whenever(workProfileContext.packageManager).thenReturn(workProfilePackageManager) + userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo)) + + createNoteTaskController().setNoteTaskShortcutEnabled(value = true, workUserInfo.userHandle) + + val argument = argumentCaptor<ComponentName>() + verify(workProfilePackageManager) + .setComponentEnabledSetting( + argument.capture(), + eq(COMPONENT_ENABLED_STATE_ENABLED), + eq(PackageManager.DONT_KILL_APP), + ) + assertThat(argument.value.className) + .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + } + + @Test + fun setNoteTaskShortcutEnabled_workProfileUser_setFalse() { + whenever(context.createContextAsUser(eq(workUserInfo.userHandle), any())) + .thenReturn(workProfileContext) + whenever(workProfileContext.packageManager).thenReturn(workProfilePackageManager) + userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo)) + + createNoteTaskController() + .setNoteTaskShortcutEnabled(value = false, workUserInfo.userHandle) + + val argument = argumentCaptor<ComponentName>() + verify(workProfilePackageManager) + .setComponentEnabledSetting( + argument.capture(), + eq(COMPONENT_ENABLED_STATE_DISABLED), + eq(PackageManager.DONT_KILL_APP), + ) + assertThat(argument.value.className) + .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name) + } // endregion // region keyguard policy diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt index ec4daee72cf8..28ed9d22a41b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt @@ -20,9 +20,11 @@ import android.test.suitebuilder.annotation.SmallTest import android.view.KeyEvent import androidx.test.runner.AndroidJUnit4 import com.android.systemui.SysuiTestCase +import com.android.systemui.settings.FakeUserTracker import com.android.systemui.statusbar.CommandQueue import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.android.wm.shell.bubbles.Bubbles import java.util.Optional @@ -46,6 +48,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { @Mock lateinit var roleManager: RoleManager private val clock = FakeSystemClock() private val executor = FakeExecutor(clock) + private val userTracker = FakeUserTracker() @Before fun setUp() { @@ -63,6 +66,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { isEnabled = isEnabled, roleManager = roleManager, backgroundExecutor = executor, + userTracker = userTracker, ) } @@ -71,7 +75,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { fun initialize() { createNoteTaskInitializer().initialize() - verify(controller).setNoteTaskShortcutEnabled(true) + verify(controller).setNoteTaskShortcutEnabled(eq(true), eq(userTracker.userHandle)) verify(commandQueue).addCallback(any()) verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any()) } @@ -80,7 +84,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { fun initialize_flagDisabled() { createNoteTaskInitializer(isEnabled = false).initialize() - verify(controller, never()).setNoteTaskShortcutEnabled(any()) + verify(controller, never()).setNoteTaskShortcutEnabled(any(), any()) verify(commandQueue, never()).addCallback(any()) verify(roleManager, never()).addOnRoleHoldersChangedListenerAsUser(any(), any(), any()) } @@ -89,7 +93,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { fun initialize_bubblesNotPresent() { createNoteTaskInitializer(bubbles = null).initialize() - verify(controller, never()).setNoteTaskShortcutEnabled(any()) + verify(controller, never()).setNoteTaskShortcutEnabled(any(), any()) verify(commandQueue, never()).addCallback(any()) verify(roleManager, never()).addOnRoleHoldersChangedListenerAsUser(any(), any(), any()) } @@ -98,24 +102,36 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { // region handleSystemKey @Test fun handleSystemKey_receiveValidSystemKey_shouldShowNoteTask() { - createNoteTaskInitializer().callbacks.handleSystemKey(KeyEvent(KeyEvent.ACTION_DOWN, - KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL)) + createNoteTaskInitializer() + .callbacks + .handleSystemKey(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL)) verify(controller).showNoteTask(entryPoint = NoteTaskEntryPoint.TAIL_BUTTON) } @Test fun handleSystemKey_receiveKeyboardShortcut_shouldShowNoteTask() { - createNoteTaskInitializer().callbacks.handleSystemKey(KeyEvent(0, 0, KeyEvent.ACTION_DOWN, - KeyEvent.KEYCODE_N, 0, KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)) + createNoteTaskInitializer() + .callbacks + .handleSystemKey( + KeyEvent( + 0, + 0, + KeyEvent.ACTION_DOWN, + KeyEvent.KEYCODE_N, + 0, + KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON + ) + ) verify(controller).showNoteTask(entryPoint = NoteTaskEntryPoint.KEYBOARD_SHORTCUT) } - + @Test fun handleSystemKey_receiveInvalidSystemKey_shouldDoNothing() { - createNoteTaskInitializer().callbacks.handleSystemKey(KeyEvent(KeyEvent.ACTION_DOWN, - KeyEvent.KEYCODE_UNKNOWN)) + createNoteTaskInitializer() + .callbacks + .handleSystemKey(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_UNKNOWN)) verifyZeroInteractions(controller) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt index c96853d1a406..a0c376ff1a1c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.notetask.NoteTaskController import com.android.systemui.notetask.NoteTaskEntryPoint import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.whenever import org.junit.After @@ -38,6 +39,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.never import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -86,15 +88,28 @@ class LaunchNoteTaskActivityTest : SysuiTestCase() { @Test fun startActivityOnWorkProfileUser_shouldLaunchProxyActivity() { + val mainUserHandle: UserHandle = mainUser.userHandle userTracker.set(listOf(mainUser, workProfileUser), selectedUserIndex = 1) whenever(userManager.isManagedProfile).thenReturn(true) + whenever(userManager.mainUser).thenReturn(mainUserHandle) activityRule.launchActivity(/* startIntent= */ null) - val mainUserHandle: UserHandle = mainUser.userHandle verify(noteTaskController).startNoteTaskProxyActivityForUser(eq(mainUserHandle)) } + @Test + fun startActivityOnWorkProfileUser_noMainUser_shouldNotLaunch() { + userTracker.set(listOf(mainUser, workProfileUser), selectedUserIndex = 1) + whenever(userManager.isManagedProfile).thenReturn(true) + whenever(userManager.mainUser).thenReturn(null) + + activityRule.launchActivity(/* startIntent= */ null) + + verify(noteTaskController, never()).showNoteTask(any()) + verify(noteTaskController, never()).startNoteTaskProxyActivityForUser(any()) + } + private companion object { val mainUser = UserInfo(/* id= */ 0, /* name= */ "primary", /* flags= */ UserInfo.FLAG_MAIN) val workProfileUser = diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 34d2b14d46a9..e4d8b2598fe3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -46,13 +46,14 @@ import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; import com.android.internal.util.CollectionUtils; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; -import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.nano.SystemUIProtoDump; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.qs.QSFactory; @@ -62,7 +63,6 @@ import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.external.CustomTileStatePersister; import com.android.systemui.qs.external.TileLifecycleManager; import com.android.systemui.qs.external.TileServiceKey; -import com.android.systemui.qs.external.TileServiceRequestController; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserFileManager; @@ -110,25 +110,17 @@ public class QSTileHostTest extends SysuiTestCase { @Mock private Provider<AutoTileManager> mAutoTiles; @Mock - private DumpManager mDumpManager; - @Mock private CentralSurfaces mCentralSurfaces; @Mock private QSLogger mQSLogger; @Mock private CustomTile mCustomTile; @Mock - private UiEventLogger mUiEventLogger; - @Mock private UserTracker mUserTracker; private SecureSettings mSecureSettings; @Mock private CustomTileStatePersister mCustomTileStatePersister; @Mock - private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder; - @Mock - private TileServiceRequestController mTileServiceRequestController; - @Mock private TileLifecycleManager.Factory mTileLifecycleManagerFactory; @Mock private TileLifecycleManager mTileLifecycleManager; @@ -137,6 +129,8 @@ public class QSTileHostTest extends SysuiTestCase { private SparseArray<SharedPreferences> mSharedPreferencesByUser; + private FakeFeatureFlags mFeatureFlags; + private FakeExecutor mMainExecutor; private QSTileHost mQSTileHost; @@ -144,12 +138,13 @@ public class QSTileHostTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); + mFeatureFlags = new FakeFeatureFlags(); + + mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, false); + mMainExecutor = new FakeExecutor(new FakeSystemClock()); mSharedPreferencesByUser = new SparseArray<>(); - - when(mTileServiceRequestControllerBuilder.create(any())) - .thenReturn(mTileServiceRequestController); when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class))) .thenReturn(mTileLifecycleManager); when(mUserFileManager.getSharedPreferences(anyString(), anyInt(), anyInt())) @@ -165,10 +160,9 @@ public class QSTileHostTest extends SysuiTestCase { mSecureSettings = new FakeSettings(); saveSetting(""); mQSTileHost = new TestQSTileHost(mContext, mDefaultFactory, mMainExecutor, - mPluginManager, mTunerService, mAutoTiles, mDumpManager, mCentralSurfaces, - mQSLogger, mUiEventLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister, - mTileServiceRequestControllerBuilder, mTileLifecycleManagerFactory, - mUserFileManager); + mPluginManager, mTunerService, mAutoTiles, mCentralSurfaces, + mQSLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister, + mTileLifecycleManagerFactory, mUserFileManager, mFeatureFlags); mSecureSettings.registerContentObserverForUser(SETTING, new ContentObserver(null) { @Override @@ -686,18 +680,16 @@ public class QSTileHostTest extends SysuiTestCase { TestQSTileHost(Context context, QSFactory defaultFactory, Executor mainExecutor, PluginManager pluginManager, TunerService tunerService, - Provider<AutoTileManager> autoTiles, DumpManager dumpManager, - CentralSurfaces centralSurfaces, QSLogger qsLogger, UiEventLogger uiEventLogger, + Provider<AutoTileManager> autoTiles, + CentralSurfaces centralSurfaces, QSLogger qsLogger, UserTracker userTracker, SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, - TileServiceRequestController.Builder tileServiceRequestControllerBuilder, TileLifecycleManager.Factory tileLifecycleManagerFactory, - UserFileManager userFileManager) { + UserFileManager userFileManager, FeatureFlags featureFlags) { super(context, defaultFactory, mainExecutor, pluginManager, - tunerService, autoTiles, dumpManager, Optional.of(centralSurfaces), qsLogger, - uiEventLogger, userTracker, secureSettings, customTileStatePersister, - tileServiceRequestControllerBuilder, tileLifecycleManagerFactory, - userFileManager); + tunerService, autoTiles, Optional.of(centralSurfaces), qsLogger, + userTracker, secureSettings, customTileStatePersister, + tileLifecycleManagerFactory, userFileManager, featureFlags); } @Override @@ -715,6 +707,7 @@ public class QSTileHostTest extends SysuiTestCase { protected TestTile(QSHost host) { super( host, + mock(QsEventLogger.class), mock(Looper.class), mock(Handler.class), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QsEventLoggerFake.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QsEventLoggerFake.kt new file mode 100644 index 000000000000..40aa2607dc94 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QsEventLoggerFake.kt @@ -0,0 +1,35 @@ +/* + * 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 + +import com.android.internal.logging.InstanceId +import com.android.internal.logging.UiEventLogger +import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.systemui.InstanceIdSequenceFake + +class QsEventLoggerFake( + uiEventLogger: UiEventLoggerFake, + private val instanceIdSequence: InstanceIdSequenceFake, +) : QsEventLogger, UiEventLogger by uiEventLogger { + + val lastInstanceId: Int + get() = instanceIdSequence.lastInstanceId + + override fun getNewInstanceId(): InstanceId { + return instanceIdSequence.newInstanceId() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt index ac106ef9bf51..198ed4ac08fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt @@ -41,6 +41,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.settings.FakeDisplayTracker import com.android.systemui.util.mockito.any @@ -56,12 +57,12 @@ import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -89,6 +90,7 @@ class CustomTileTest : SysuiTestCase() { @Mock private lateinit var applicationInfo: ApplicationInfo @Mock private lateinit var serviceInfo: ServiceInfo @Mock private lateinit var customTileStatePersister: CustomTileStatePersister + @Mock private lateinit var uiEventLogger: QsEventLogger private var displayTracker = FakeDisplayTracker(mContext) private lateinit var customTile: CustomTile @@ -115,6 +117,7 @@ class CustomTileTest : SysuiTestCase() { customTileBuilder = CustomTile.Builder( { tileHost }, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt new file mode 100644 index 000000000000..77b3e69f4384 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt @@ -0,0 +1,189 @@ +/* + * 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.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.util.settings.FakeSettings +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +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 + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidTestingRunner::class) +class AutoAddSettingsRepositoryTest : SysuiTestCase() { + private val secureSettings = FakeSettings() + + private val testDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testDispatcher) + + private lateinit var underTest: AutoAddSettingRepository + + @Before + fun setUp() { + underTest = + AutoAddSettingRepository( + secureSettings, + testDispatcher, + ) + } + + @Test + fun nonExistentSetting_emptySet() = + testScope.runTest { + val specs by collectLastValue(underTest.autoAddedTiles(0)) + + assertThat(specs).isEmpty() + } + + @Test + fun settingsChange_correctValues() = + testScope.runTest { + val userId = 0 + val specs by collectLastValue(underTest.autoAddedTiles(userId)) + + val value = "a,custom(b/c)" + storeForUser(value, userId) + + assertThat(specs).isEqualTo(value.toSet()) + + val newValue = "a" + storeForUser(newValue, userId) + + assertThat(specs).isEqualTo(newValue.toSet()) + } + + @Test + fun tilesForCorrectUsers() = + testScope.runTest { + val tilesFromUser0 by collectLastValue(underTest.autoAddedTiles(0)) + val tilesFromUser1 by collectLastValue(underTest.autoAddedTiles(1)) + + val user0Tiles = "a" + val user1Tiles = "custom(b/c)" + storeForUser(user0Tiles, 0) + storeForUser(user1Tiles, 1) + + assertThat(tilesFromUser0).isEqualTo(user0Tiles.toSet()) + assertThat(tilesFromUser1).isEqualTo(user1Tiles.toSet()) + } + + @Test + fun noInvalidTileSpecs() = + testScope.runTest { + val userId = 0 + val tiles by collectLastValue(underTest.autoAddedTiles(userId)) + + val specs = "d,custom(bad)" + storeForUser(specs, userId) + + assertThat(tiles).isEqualTo("d".toSet()) + } + + @Test + fun markAdded() = + testScope.runTest { + val userId = 0 + val specs = mutableSetOf(TileSpec.create("a")) + underTest.markTileAdded(userId, TileSpec.create("a")) + + assertThat(loadForUser(userId).toSet()).containsExactlyElementsIn(specs) + + specs.add(TileSpec.create("b")) + underTest.markTileAdded(userId, TileSpec.create("b")) + + assertThat(loadForUser(userId).toSet()).containsExactlyElementsIn(specs) + } + + @Test + fun markAdded_multipleUsers() = + testScope.runTest { + underTest.markTileAdded(userId = 1, TileSpec.create("a")) + + assertThat(loadForUser(0).toSet()).isEmpty() + assertThat(loadForUser(1).toSet()) + .containsExactlyElementsIn(setOf(TileSpec.create("a"))) + } + + @Test + fun markAdded_Invalid_noop() = + testScope.runTest { + val userId = 0 + underTest.markTileAdded(userId, TileSpec.Invalid) + + assertThat(loadForUser(userId).toSet()).isEmpty() + } + + @Test + fun unmarkAdded() = + testScope.runTest { + val userId = 0 + val specs = "a,custom(b/c)" + storeForUser(specs, userId) + + underTest.unmarkTileAdded(userId, TileSpec.create("a")) + + assertThat(loadForUser(userId).toSet()) + .containsExactlyElementsIn(setOf(TileSpec.create("custom(b/c)"))) + } + + @Test + fun unmarkAdded_multipleUsers() = + testScope.runTest { + val specs = "a,b" + storeForUser(specs, 0) + storeForUser(specs, 1) + + underTest.unmarkTileAdded(1, TileSpec.create("a")) + + assertThat(loadForUser(0).toSet()).isEqualTo(specs.toSet()) + assertThat(loadForUser(1).toSet()).isEqualTo(setOf(TileSpec.create("b"))) + } + + private fun storeForUser(specs: String, userId: Int) { + secureSettings.putStringForUser(SETTING, specs, userId) + } + + private fun loadForUser(userId: Int): String { + return secureSettings.getStringForUser(SETTING, userId) ?: "" + } + + companion object { + private const val SETTING = Settings.Secure.QS_AUTO_ADDED_TILES + private const val DELIMITER = "," + + fun Set<TileSpec>.toSeparatedString() = joinToString(DELIMITER, transform = TileSpec::spec) + + fun String.toSet(): Set<TileSpec> { + return if (isNullOrBlank()) { + emptySet() + } else { + split(DELIMITER).map(TileSpec::create).toSet() + } + } + } +} 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 index c03849b35f54..50a8d2630d79 100644 --- 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 @@ -170,6 +170,21 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { } @Test + fun addTileAtPosition_tooLarge_addedAtEnd() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + val specs = "a,custom(b/c)" + storeTilesForUser(specs, 0) + + underTest.addTile(userId = 0, TileSpec.create("d"), position = 100) + + val expected = "a,custom(b/c),d" + assertThat(loadTilesForUser(0)).isEqualTo(expected) + assertThat(tiles).isEqualTo(expected.toTileSpecs()) + } + + @Test fun addTileForOtherUser_addedInThatUser() = testScope.runTest { val tilesUser0 by collectLastValue(underTest.tilesSpecs(0)) @@ -187,27 +202,27 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { } @Test - fun removeTile() = + fun removeTiles() = testScope.runTest { val tiles by collectLastValue(underTest.tilesSpecs(0)) storeTilesForUser("a,b", 0) - underTest.removeTile(userId = 0, TileSpec.create("a")) + underTest.removeTiles(userId = 0, listOf(TileSpec.create("a"))) assertThat(loadTilesForUser(0)).isEqualTo("b") assertThat(tiles).isEqualTo("b".toTileSpecs()) } @Test - fun removeTileNotThere_noop() = + fun removeTilesNotThere_noop() = testScope.runTest { val tiles by collectLastValue(underTest.tilesSpecs(0)) val specs = "a,b" storeTilesForUser(specs, 0) - underTest.removeTile(userId = 0, TileSpec.create("c")) + underTest.removeTiles(userId = 0, listOf(TileSpec.create("c"))) assertThat(loadTilesForUser(0)).isEqualTo(specs) assertThat(tiles).isEqualTo(specs.toTileSpecs()) @@ -221,7 +236,7 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { val specs = "a,b" storeTilesForUser(specs, 0) - underTest.removeTile(userId = 0, TileSpec.Invalid) + underTest.removeTiles(userId = 0, listOf(TileSpec.Invalid)) assertThat(loadTilesForUser(0)).isEqualTo(specs) assertThat(tiles).isEqualTo(specs.toTileSpecs()) @@ -237,7 +252,7 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { storeTilesForUser(specs, 0) storeTilesForUser(specs, 1) - underTest.removeTile(userId = 1, TileSpec.create("a")) + underTest.removeTiles(userId = 1, listOf(TileSpec.create("a"))) assertThat(loadTilesForUser(0)).isEqualTo(specs) assertThat(user0Tiles).isEqualTo(specs.toTileSpecs()) @@ -246,6 +261,19 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { } @Test + fun removeMultipleTiles() = + testScope.runTest { + val tiles by collectLastValue(underTest.tilesSpecs(0)) + + storeTilesForUser("a,b,c,d", 0) + + underTest.removeTiles(userId = 0, listOf(TileSpec.create("a"), TileSpec.create("c"))) + + assertThat(loadTilesForUser(0)).isEqualTo("b,d") + assertThat(tiles).isEqualTo("b,d".toTileSpecs()) + } + + @Test fun changeTiles() = testScope.runTest { val tiles by collectLastValue(underTest.tilesSpecs(0)) @@ -310,8 +338,8 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { storeTilesForUser(specs, 0) coroutineScope { - underTest.removeTile(userId = 0, TileSpec.create("c")) - underTest.removeTile(userId = 0, TileSpec.create("a")) + underTest.removeTiles(userId = 0, listOf(TileSpec.create("c"))) + underTest.removeTiles(userId = 0, listOf(TileSpec.create("a"))) } assertThat(loadTilesForUser(0)).isEqualTo("b") diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt new file mode 100644 index 000000000000..7ecb4dc9376a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt @@ -0,0 +1,674 @@ +/* + * 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.domain.interactor + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.UserInfo +import android.os.UserHandle +import android.service.quicksettings.Tile +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dump.nano.SystemUIProtoDump +import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.plugins.qs.QSTile.BooleanState +import com.android.systemui.qs.FakeQSFactory +import com.android.systemui.qs.external.CustomTile +import com.android.systemui.qs.external.CustomTileStatePersister +import com.android.systemui.qs.external.TileLifecycleManager +import com.android.systemui.qs.external.TileServiceKey +import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository +import com.android.systemui.qs.pipeline.data.repository.FakeCustomTileAddedRepository +import com.android.systemui.qs.pipeline.data.repository.FakeTileSpecRepository +import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository +import com.android.systemui.qs.pipeline.domain.model.TileModel +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import com.android.systemui.qs.toProto +import com.android.systemui.settings.UserTracker +import com.android.systemui.user.data.repository.FakeUserRepository +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import com.google.protobuf.nano.MessageNano +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +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.ArgumentMatchers.anyString +import org.mockito.Mock +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@OptIn(ExperimentalCoroutinesApi::class) +class CurrentTilesInteractorImplTest : SysuiTestCase() { + + private val tileSpecRepository: TileSpecRepository = FakeTileSpecRepository() + private val userRepository = FakeUserRepository() + private val tileFactory = FakeQSFactory(::tileCreator) + private val customTileAddedRepository: CustomTileAddedRepository = + FakeCustomTileAddedRepository() + private val featureFlags = FakeFeatureFlags() + private val tileLifecycleManagerFactory = TLMFactory() + + @Mock private lateinit var customTileStatePersister: CustomTileStatePersister + + @Mock private lateinit var userTracker: UserTracker + + @Mock private lateinit var logger: QSPipelineLogger + + private val testDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testDispatcher) + + private val unavailableTiles = mutableSetOf("e") + + private lateinit var underTest: CurrentTilesInteractorImpl + + @OptIn(ExperimentalCoroutinesApi::class) + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + featureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true) + + userRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1)) + setUserTracker(0) + + underTest = + CurrentTilesInteractorImpl( + tileSpecRepository = tileSpecRepository, + userRepository = userRepository, + customTileStatePersister = customTileStatePersister, + tileFactory = tileFactory, + customTileAddedRepository = customTileAddedRepository, + tileLifecycleManagerFactory = tileLifecycleManagerFactory, + userTracker = userTracker, + mainDispatcher = testDispatcher, + backgroundDispatcher = testDispatcher, + scope = testScope.backgroundScope, + logger = logger, + featureFlags = featureFlags, + ) + } + + @Test + fun initialState() = + testScope.runTest(USER_INFO_0) { + assertThat(underTest.currentTiles.value).isEmpty() + assertThat(underTest.currentQSTiles).isEmpty() + assertThat(underTest.currentTilesSpecs).isEmpty() + assertThat(underTest.userId.value).isEqualTo(0) + assertThat(underTest.userContext.value.userId).isEqualTo(0) + } + + @Test + fun correctTiles() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + + val specs = + listOf( + TileSpec.create("a"), + TileSpec.create("e"), + CUSTOM_TILE_SPEC, + TileSpec.create("d"), + TileSpec.create("non_existent") + ) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + + // check each tile + + // Tile a + val tile0 = tiles!![0] + assertThat(tile0.spec).isEqualTo(specs[0]) + assertThat(tile0.tile.tileSpec).isEqualTo(specs[0].spec) + assertThat(tile0.tile).isInstanceOf(FakeQSTile::class.java) + assertThat(tile0.tile.isAvailable).isTrue() + + // Tile e is not available and is not in the list + + // Custom Tile + val tile1 = tiles!![1] + assertThat(tile1.spec).isEqualTo(specs[2]) + assertThat(tile1.tile.tileSpec).isEqualTo(specs[2].spec) + assertThat(tile1.tile).isInstanceOf(CustomTile::class.java) + assertThat(tile1.tile.isAvailable).isTrue() + + // Tile d + val tile2 = tiles!![2] + assertThat(tile2.spec).isEqualTo(specs[3]) + assertThat(tile2.tile.tileSpec).isEqualTo(specs[3].spec) + assertThat(tile2.tile).isInstanceOf(FakeQSTile::class.java) + assertThat(tile2.tile.isAvailable).isTrue() + + // Tile non-existent shouldn't be created. Therefore, only 3 tiles total + assertThat(tiles?.size).isEqualTo(3) + } + + @Test + fun logTileCreated() = + testScope.runTest(USER_INFO_0) { + val specs = + listOf( + TileSpec.create("a"), + CUSTOM_TILE_SPEC, + ) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + runCurrent() + + specs.forEach { verify(logger).logTileCreated(it) } + } + + @Test + fun logTileNotFoundInFactory() = + testScope.runTest(USER_INFO_0) { + val specs = + listOf( + TileSpec.create("non_existing"), + ) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + runCurrent() + + verify(logger, never()).logTileCreated(any()) + verify(logger).logTileNotFoundInFactory(specs[0]) + } + + @Test + fun tileNotAvailableDestroyed_logged() = + testScope.runTest(USER_INFO_0) { + val specs = + listOf( + TileSpec.create("e"), + ) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + runCurrent() + + verify(logger, never()).logTileCreated(any()) + verify(logger) + .logTileDestroyed( + specs[0], + QSPipelineLogger.TileDestroyedReason.NEW_TILE_NOT_AVAILABLE + ) + } + + @Test + fun someTilesNotValid_repositorySetToDefinitiveList() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id)) + + val specs = + listOf( + TileSpec.create("a"), + TileSpec.create("e"), + ) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + + assertThat(tiles).isEqualTo(listOf(TileSpec.create("a"))) + } + + @Test + fun deduplicatedTiles() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + + val specs = listOf(TileSpec.create("a"), TileSpec.create("a")) + + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + + assertThat(tiles?.size).isEqualTo(1) + assertThat(tiles!![0].spec).isEqualTo(specs[0]) + } + + @Test + fun tilesChange_platformTileNotRecreated() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + + val specs = + listOf( + TileSpec.create("a"), + ) + + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + val originalTileA = tiles!![0].tile + + tileSpecRepository.addTile(USER_INFO_0.id, TileSpec.create("b")) + + assertThat(tiles?.size).isEqualTo(2) + assertThat(tiles!![0].tile).isSameInstanceAs(originalTileA) + } + + @Test + fun tileRemovedIsDestroyed() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + + val specs = listOf(TileSpec.create("a"), TileSpec.create("c")) + + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + val originalTileC = tiles!![1].tile + + tileSpecRepository.removeTiles(USER_INFO_0.id, listOf(TileSpec.create("c"))) + + assertThat(tiles?.size).isEqualTo(1) + assertThat(tiles!![0].spec).isEqualTo(TileSpec.create("a")) + + assertThat((originalTileC as FakeQSTile).destroyed).isTrue() + verify(logger) + .logTileDestroyed( + TileSpec.create("c"), + QSPipelineLogger.TileDestroyedReason.TILE_REMOVED + ) + } + + @Test + fun tileBecomesNotAvailable_destroyed() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + val repoTiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id)) + + val specs = listOf(TileSpec.create("a")) + + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + val originalTileA = tiles!![0].tile + + // Tile becomes unavailable + (originalTileA as FakeQSTile).available = false + unavailableTiles.add("a") + // and there is some change in the specs + tileSpecRepository.addTile(USER_INFO_0.id, TileSpec.create("b")) + runCurrent() + + assertThat(originalTileA.destroyed).isTrue() + verify(logger) + .logTileDestroyed( + TileSpec.create("a"), + QSPipelineLogger.TileDestroyedReason.EXISTING_TILE_NOT_AVAILABLE + ) + + assertThat(tiles?.size).isEqualTo(1) + assertThat(tiles!![0].spec).isEqualTo(TileSpec.create("b")) + assertThat(tiles!![0].tile).isNotSameInstanceAs(originalTileA) + + assertThat(repoTiles).isEqualTo(tiles!!.map(TileModel::spec)) + } + + @Test + fun userChange_tilesChange() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + + val specs0 = listOf(TileSpec.create("a")) + val specs1 = listOf(TileSpec.create("b")) + tileSpecRepository.setTiles(USER_INFO_0.id, specs0) + tileSpecRepository.setTiles(USER_INFO_1.id, specs1) + + switchUser(USER_INFO_1) + + assertThat(tiles!![0].spec).isEqualTo(specs1[0]) + assertThat(tiles!![0].tile.tileSpec).isEqualTo(specs1[0].spec) + } + + @Test + fun tileNotPresentInSecondaryUser_destroyedInUserChange() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + + val specs0 = listOf(TileSpec.create("a")) + val specs1 = listOf(TileSpec.create("b")) + tileSpecRepository.setTiles(USER_INFO_0.id, specs0) + tileSpecRepository.setTiles(USER_INFO_1.id, specs1) + + val originalTileA = tiles!![0].tile + + switchUser(USER_INFO_1) + runCurrent() + + assertThat((originalTileA as FakeQSTile).destroyed).isTrue() + verify(logger) + .logTileDestroyed( + specs0[0], + QSPipelineLogger.TileDestroyedReason.TILE_NOT_PRESENT_IN_NEW_USER + ) + } + + @Test + fun userChange_customTileDestroyed_lifecycleNotTerminated() { + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + + val specs = listOf(CUSTOM_TILE_SPEC) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + tileSpecRepository.setTiles(USER_INFO_1.id, specs) + + val originalCustomTile = tiles!![0].tile + + switchUser(USER_INFO_1) + runCurrent() + + verify(originalCustomTile).destroy() + assertThat(tileLifecycleManagerFactory.created).isEmpty() + } + } + + @Test + fun userChange_sameTileUserChanged() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + + val specs = listOf(TileSpec.create("a")) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + tileSpecRepository.setTiles(USER_INFO_1.id, specs) + + val originalTileA = tiles!![0].tile as FakeQSTile + assertThat(originalTileA.user).isEqualTo(USER_INFO_0.id) + + switchUser(USER_INFO_1) + runCurrent() + + assertThat(tiles!![0].tile).isSameInstanceAs(originalTileA) + assertThat(originalTileA.user).isEqualTo(USER_INFO_1.id) + verify(logger).logTileUserChanged(specs[0], USER_INFO_1.id) + } + + @Test + fun addTile() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id)) + val spec = TileSpec.create("a") + val currentSpecs = + listOf( + TileSpec.create("b"), + TileSpec.create("c"), + ) + tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs) + + underTest.addTile(spec, position = 1) + + val expectedSpecs = + listOf( + TileSpec.create("b"), + spec, + TileSpec.create("c"), + ) + assertThat(tiles).isEqualTo(expectedSpecs) + } + + @Test + fun addTile_currentUser() = + testScope.runTest(USER_INFO_1) { + val tiles0 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id)) + val tiles1 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_1.id)) + val spec = TileSpec.create("a") + val currentSpecs = + listOf( + TileSpec.create("b"), + TileSpec.create("c"), + ) + tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs) + tileSpecRepository.setTiles(USER_INFO_1.id, currentSpecs) + + switchUser(USER_INFO_1) + underTest.addTile(spec, position = 1) + + assertThat(tiles0).isEqualTo(currentSpecs) + + val expectedSpecs = + listOf( + TileSpec.create("b"), + spec, + TileSpec.create("c"), + ) + assertThat(tiles1).isEqualTo(expectedSpecs) + } + + @Test + fun removeTile_platform() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id)) + + val specs = listOf(TileSpec.create("a"), TileSpec.create("b")) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + runCurrent() + + underTest.removeTiles(specs.subList(0, 1)) + + assertThat(tiles).isEqualTo(specs.subList(1, 2)) + } + + @Test + fun removeTile_customTile_lifecycleEnded() { + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id)) + + val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + runCurrent() + assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id)) + .isTrue() + + underTest.removeTiles(listOf(CUSTOM_TILE_SPEC)) + + assertThat(tiles).isEqualTo(specs.subList(0, 1)) + + val tileLifecycleManager = + tileLifecycleManagerFactory.created[USER_INFO_0.id to TEST_COMPONENT] + assertThat(tileLifecycleManager).isNotNull() + + with(inOrder(tileLifecycleManager!!)) { + verify(tileLifecycleManager).onStopListening() + verify(tileLifecycleManager).onTileRemoved() + verify(tileLifecycleManager).flushMessagesAndUnbind() + } + assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id)) + .isFalse() + verify(customTileStatePersister) + .removeState(TileServiceKey(TEST_COMPONENT, USER_INFO_0.id)) + } + } + + @Test + fun removeTiles_currentUser() = + testScope.runTest { + val tiles0 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id)) + val tiles1 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_1.id)) + val currentSpecs = + listOf( + TileSpec.create("a"), + TileSpec.create("b"), + TileSpec.create("c"), + ) + tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs) + tileSpecRepository.setTiles(USER_INFO_1.id, currentSpecs) + + switchUser(USER_INFO_1) + runCurrent() + + underTest.removeTiles(currentSpecs.subList(0, 2)) + + assertThat(tiles0).isEqualTo(currentSpecs) + assertThat(tiles1).isEqualTo(currentSpecs.subList(2, 3)) + } + + @Test + fun setTiles() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id)) + + val currentSpecs = listOf(TileSpec.create("a"), TileSpec.create("b")) + tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs) + runCurrent() + + val newSpecs = listOf(TileSpec.create("b"), TileSpec.create("c"), TileSpec.create("a")) + underTest.setTiles(newSpecs) + runCurrent() + + assertThat(tiles).isEqualTo(newSpecs) + } + + @Test + fun setTiles_customTiles_lifecycleEndedIfGone() = + testScope.runTest(USER_INFO_0) { + val otherCustomTileSpec = TileSpec.create("custom(b/c)") + + val currentSpecs = listOf(CUSTOM_TILE_SPEC, TileSpec.create("a"), otherCustomTileSpec) + tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs) + runCurrent() + + val newSpecs = + listOf( + otherCustomTileSpec, + TileSpec.create("a"), + ) + + underTest.setTiles(newSpecs) + runCurrent() + + val tileLifecycleManager = + tileLifecycleManagerFactory.created[USER_INFO_0.id to TEST_COMPONENT]!! + + with(inOrder(tileLifecycleManager)) { + verify(tileLifecycleManager).onStopListening() + verify(tileLifecycleManager).onTileRemoved() + verify(tileLifecycleManager).flushMessagesAndUnbind() + } + assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id)) + .isFalse() + verify(customTileStatePersister) + .removeState(TileServiceKey(TEST_COMPONENT, USER_INFO_0.id)) + } + + @Test + fun protoDump() = + testScope.runTest(USER_INFO_0) { + val tiles by collectLastValue(underTest.currentTiles) + val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC) + + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + + val stateA = tiles!![0].tile.state + stateA.fillIn(Tile.STATE_INACTIVE, "A", "AA") + val stateCustom = QSTile.BooleanState() + stateCustom.fillIn(Tile.STATE_ACTIVE, "B", "BB") + stateCustom.spec = CUSTOM_TILE_SPEC.spec + whenever(tiles!![1].tile.state).thenReturn(stateCustom) + + val proto = SystemUIProtoDump() + underTest.dumpProto(proto, emptyArray()) + + assertThat(MessageNano.messageNanoEquals(proto.tiles[0], stateA.toProto())).isTrue() + assertThat(MessageNano.messageNanoEquals(proto.tiles[1], stateCustom.toProto())) + .isTrue() + } + + private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) { + this.state = state + this.label = label + this.secondaryLabel = secondaryLabel + if (this is BooleanState) { + value = state == Tile.STATE_ACTIVE + } + } + + private fun tileCreator(spec: String): QSTile? { + val currentUser = userTracker.userId + return when (spec) { + CUSTOM_TILE_SPEC.spec -> + mock<CustomTile> { + var tileSpecReference: String? = null + whenever(user).thenReturn(currentUser) + whenever(component).thenReturn(CUSTOM_TILE_SPEC.componentName) + whenever(isAvailable).thenReturn(true) + whenever(setTileSpec(anyString())).thenAnswer { + tileSpecReference = it.arguments[0] as? String + Unit + } + whenever(tileSpec).thenAnswer { tileSpecReference } + // Also, add it to the set of added tiles (as this happens as part of the tile + // creation). + customTileAddedRepository.setTileAdded( + CUSTOM_TILE_SPEC.componentName, + currentUser, + true + ) + } + in VALID_TILES -> FakeQSTile(currentUser, available = spec !in unavailableTiles) + else -> null + } + } + + private fun TestScope.runTest(user: UserInfo, body: suspend TestScope.() -> Unit) { + return runTest { + switchUser(user) + body() + } + } + + private suspend fun switchUser(user: UserInfo) { + setUserTracker(user.id) + userRepository.setSelectedUserInfo(user) + } + + private fun setUserTracker(user: Int) { + val mockContext = mockUserContext(user) + whenever(userTracker.userContext).thenReturn(mockContext) + whenever(userTracker.userId).thenReturn(user) + } + + private class TLMFactory : TileLifecycleManager.Factory { + + val created = mutableMapOf<Pair<Int, ComponentName>, TileLifecycleManager>() + + override fun create(intent: Intent, userHandle: UserHandle): TileLifecycleManager { + val componentName = intent.component!! + val user = userHandle.identifier + val manager: TileLifecycleManager = mock() + created[user to componentName] = manager + return manager + } + } + + private fun mockUserContext(user: Int): Context { + return mock { + whenever(this.userId).thenReturn(user) + whenever(this.user).thenReturn(UserHandle.of(user)) + } + } + + companion object { + private val USER_INFO_0 = UserInfo().apply { id = 0 } + private val USER_INFO_1 = UserInfo().apply { id = 1 } + + private val VALID_TILES = setOf("a", "b", "c", "d", "e") + private val TEST_COMPONENT = ComponentName("pkg", "cls") + private val CUSTOM_TILE_SPEC = TileSpec.Companion.create(TEST_COMPONENT) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/FakeQSTile.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/FakeQSTile.kt new file mode 100644 index 000000000000..e50969641a71 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/FakeQSTile.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.systemui.qs.pipeline.domain.interactor + +import android.content.Context +import android.view.View +import com.android.internal.logging.InstanceId +import com.android.systemui.plugins.qs.QSIconView +import com.android.systemui.plugins.qs.QSTile + +class FakeQSTile( + var user: Int, + var available: Boolean = true, +) : QSTile { + private var tileSpec: String? = null + var destroyed = false + private val state = QSTile.State() + + override fun getTileSpec(): String? { + return tileSpec + } + + override fun isAvailable(): Boolean { + return available + } + + override fun setTileSpec(tileSpec: String?) { + this.tileSpec = tileSpec + state.spec = tileSpec + } + + override fun refreshState() {} + + override fun addCallback(callback: QSTile.Callback?) {} + + override fun removeCallback(callback: QSTile.Callback?) {} + + override fun removeCallbacks() {} + + override fun createTileView(context: Context?): QSIconView? { + return null + } + + override fun click(view: View?) {} + + override fun secondaryClick(view: View?) {} + + override fun longClick(view: View?) {} + + override fun userSwitch(currentUser: Int) { + user = currentUser + } + + override fun getMetricsCategory(): Int { + return 0 + } + + override fun setListening(client: Any?, listening: Boolean) {} + + override fun setDetailListening(show: Boolean) {} + + override fun destroy() { + destroyed = true + } + + override fun getTileLabel(): CharSequence { + return "" + } + + override fun getState(): QSTile.State { + return state + } + + override fun getInstanceId(): InstanceId { + return InstanceId.fakeInstanceId(0) + } + + override fun isListening(): Boolean { + return false + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java index 36549fb826ec..962b53737274 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java @@ -61,6 +61,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import com.android.systemui.InstanceIdSequenceFake; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; @@ -69,6 +70,8 @@ import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSEvent; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; +import com.android.systemui.qs.QsEventLoggerFake; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.StatusBarState; @@ -106,7 +109,8 @@ public class QSTileImplTest extends SysuiTestCase { private ActivityStarter mActivityStarter; private UiEventLoggerFake mUiEventLoggerFake; - private InstanceId mInstanceId = InstanceId.fakeInstanceId(5); + private QsEventLoggerFake mQsEventLoggerFake; + private InstanceId mInstanceId; @Captor private ArgumentCaptor<LogMaker> mLogCaptor; @@ -115,18 +119,29 @@ public class QSTileImplTest extends SysuiTestCase { public void setup() throws Exception { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); + mUiEventLoggerFake = new UiEventLoggerFake(); + mQsEventLoggerFake = + new QsEventLoggerFake(mUiEventLoggerFake, new InstanceIdSequenceFake(10)); when(mHost.indexOf(SPEC)).thenReturn(POSITION); when(mHost.getContext()).thenReturn(mContext); - when(mHost.getUiEventLogger()).thenReturn(mUiEventLoggerFake); - when(mHost.getNewInstanceId()).thenReturn(mInstanceId); Handler mainHandler = new Handler(mTestableLooper.getLooper()); - mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler, mFalsingManager, - mMetricsLogger, mStatusBarStateController, mActivityStarter, mQsLogger); + mTile = new TileImpl( + mHost, + mQsEventLoggerFake, + mTestableLooper.getLooper(), + mainHandler, + mFalsingManager, + mMetricsLogger, + mStatusBarStateController, + mActivityStarter, + mQsLogger + ); mTile.initialize(); mTestableLooper.processAllMessages(); + mInstanceId = InstanceId.fakeInstanceId(mQsEventLoggerFake.getLastInstanceId()); mTile.setTileSpec(SPEC); } @@ -507,6 +522,7 @@ public class QSTileImplTest extends SysuiTestCase { protected TileImpl( QSHost host, + QsEventLogger uiEventLogger, Looper backgroundLooper, Handler mainHandler, FalsingManager falsingManager, @@ -515,7 +531,7 @@ public class QSTileImplTest extends SysuiTestCase { ActivityStarter activityStarter, QSLogger qsLogger ) { - super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); getState().state = Tile.STATE_ACTIVE; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt index 5e0190b65a12..c60cecb29d75 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt @@ -22,8 +22,6 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.UiEventLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher @@ -32,6 +30,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.settings.UserTracker @@ -68,20 +67,21 @@ class AirplaneModeTileTest : SysuiTestCase() { private lateinit var mGlobalSettings: GlobalSettings @Mock private lateinit var mUserTracker: UserTracker + @Mock + private lateinit var mUiEventLogger: QsEventLogger private lateinit var mTestableLooper: TestableLooper private lateinit var mTile: AirplaneModeTile - private val mUiEventLogger: UiEventLogger = UiEventLoggerFake() - @Before fun setUp() { MockitoAnnotations.initMocks(this) mTestableLooper = TestableLooper.get(this) Mockito.`when`(mHost.context).thenReturn(mContext) - Mockito.`when`(mHost.uiEventLogger).thenReturn(mUiEventLogger) Mockito.`when`(mHost.userContext).thenReturn(mContext) - mTile = AirplaneModeTile(mHost, + mTile = AirplaneModeTile( + mHost, + mUiEventLogger, mTestableLooper.looper, Handler(mTestableLooper.looper), FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt index f1e3e8a71398..52b84559f396 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt @@ -9,12 +9,12 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.NextAlarmController @@ -28,8 +28,8 @@ 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.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -52,7 +52,7 @@ class AlarmTileTest : SysuiTestCase() { @Mock private lateinit var nextAlarmController: NextAlarmController @Mock - private lateinit var uiEventLogger: UiEventLogger + private lateinit var uiEventLogger: QsEventLogger @Mock private lateinit var pendingIntent: PendingIntent @Captor @@ -67,10 +67,10 @@ class AlarmTileTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) `when`(qsHost.context).thenReturn(mContext) - `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) tile = AlarmTile( qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt index a5c0004afe02..ff6814c06001 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.BatteryController @@ -43,10 +44,10 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -63,6 +64,8 @@ class BatterySaverTileTest : SysuiTestCase() { @Mock private lateinit var qsHost: QSHost @Mock + private lateinit var uiEventLogger: QsEventLogger + @Mock private lateinit var metricsLogger: MetricsLogger @Mock private lateinit var statusBarStateController: StatusBarStateController @@ -90,6 +93,7 @@ class BatterySaverTileTest : SysuiTestCase() { tile = BatterySaverTile( qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt index 2e77de270c65..5e7f68ccf3d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt @@ -9,7 +9,6 @@ import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.settingslib.Utils import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.systemui.R @@ -20,6 +19,7 @@ import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.BluetoothController @@ -49,8 +49,8 @@ class BluetoothTileTest : SysuiTestCase() { @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var bluetoothController: BluetoothController + @Mock private lateinit var uiEventLogger: QsEventLogger - private val uiEventLogger = UiEventLoggerFake() private lateinit var testableLooper: TestableLooper private lateinit var tile: FakeBluetoothTile @@ -60,11 +60,11 @@ class BluetoothTileTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) whenever(qsHost.context).thenReturn(mContext) - whenever(qsHost.uiEventLogger).thenReturn(uiEventLogger) tile = FakeBluetoothTile( qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), falsingManager, @@ -211,6 +211,7 @@ class BluetoothTileTest : SysuiTestCase() { private class FakeBluetoothTile( qsHost: QSHost, + uiEventLogger: QsEventLogger, backgroundLooper: Looper, mainHandler: Handler, falsingManager: FalsingManager, @@ -222,6 +223,7 @@ class BluetoothTileTest : SysuiTestCase() { ) : BluetoothTile( qsHost, + uiEventLogger, backgroundLooper, mainHandler, falsingManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt index 41938541124a..70d82fdb6e5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt @@ -21,8 +21,6 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.UiEventLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake @@ -30,6 +28,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLoggerFake import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController @@ -67,19 +66,21 @@ class CameraToggleTileTest : SysuiTestCase() { private lateinit var privacyController: IndividualSensorPrivacyController @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock + private lateinit var uiEventLogger: QsEventLoggerFake private lateinit var testableLooper: TestableLooper private lateinit var tile: CameraToggleTile - private val uiEventLogger: UiEventLogger = UiEventLoggerFake() @Before fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) whenever(host.context).thenReturn(mContext) - whenever(host.uiEventLogger).thenReturn(uiEventLogger) - tile = CameraToggleTile(host, + tile = CameraToggleTile( + host, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), metricsLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java index 64fd09d5f5d9..93ed99423f0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java @@ -43,6 +43,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.connectivity.IconState; import com.android.systemui.statusbar.connectivity.NetworkController; @@ -94,6 +95,8 @@ public class CastTileTest extends SysuiTestCase { private QSLogger mQSLogger; @Mock private DialogLaunchAnimator mDialogLaunchAnimator; + @Mock + private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; private CastTile mCastTile; @@ -107,6 +110,7 @@ public class CastTileTest extends SysuiTestCase { mCastTile = new CastTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java index 13c30e9ea9ab..2250ef33f9b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java @@ -32,12 +32,12 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.UserTracker; import com.android.systemui.util.settings.FakeSettings; @@ -67,7 +67,7 @@ public class ColorCorrectionTileTest extends SysuiTestCase { @Mock private QSLogger mQSLogger; @Mock - private UiEventLogger mUiEventLogger; + private QsEventLogger mUiEventLogger; @Mock private UserTracker mUserTracker; @@ -83,10 +83,10 @@ public class ColorCorrectionTileTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); when(mHost.getContext()).thenReturn(mContext); - when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger); mTile = new ColorCorrectionTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java index ff27e0255aa3..2e02bbe2ebf2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java @@ -32,7 +32,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; @@ -40,6 +39,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserTracker; @@ -72,7 +72,7 @@ public class ColorInversionTileTest extends SysuiTestCase { @Mock private QSLogger mQSLogger; @Mock - private UiEventLogger mUiEventLogger; + private QsEventLogger mUiEventLogger; @Mock private UserTracker mUserTracker; @@ -88,10 +88,10 @@ public class ColorInversionTileTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); when(mHost.getContext()).thenReturn(mContext); - when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger); mTile = new ColorInversionTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt index b048643aba84..176b33fa9fc8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt @@ -21,7 +21,6 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogLaunchAnimator @@ -30,6 +29,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.DataSaverController @@ -57,8 +57,8 @@ class DataSaverTileTest : SysuiTestCase() { @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var dataSaverController: DataSaverController @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator + @Mock private lateinit var uiEventLogger: QsEventLogger - private val uiEventLogger = UiEventLoggerFake() private lateinit var testableLooper: TestableLooper private lateinit var tile: DataSaverTile @@ -68,11 +68,11 @@ class DataSaverTileTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) Mockito.`when`(mHost.context).thenReturn(mContext) - Mockito.`when`(mHost.uiEventLogger).thenReturn(uiEventLogger) tile = DataSaverTile( mHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), falsingManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt index b51c378f6b6b..1346069d3c25 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt @@ -27,7 +27,6 @@ import android.testing.TestableLooper import androidx.lifecycle.LifecycleOwner import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.UiEventLogger import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ActivityLaunchAnimator @@ -44,6 +43,7 @@ import com.android.systemui.controls.ui.SelectedItem import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.util.mockito.any @@ -52,6 +52,7 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.SecureSettings import com.google.common.truth.Truth.assertThat +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -59,15 +60,14 @@ import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.Captor import org.mockito.Mock -import org.mockito.MockitoAnnotations -import org.mockito.Mockito.`when` import org.mockito.Mockito.doNothing import org.mockito.Mockito.nullable import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.verifyZeroInteractions +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations import java.util.Optional -import org.junit.After @SmallTest @RunWith(AndroidTestingRunner::class) @@ -95,7 +95,7 @@ class DeviceControlsTileTest : SysuiTestCase() { @Mock private lateinit var serviceInfo: ControlsServiceInfo @Mock - private lateinit var uiEventLogger: UiEventLogger + private lateinit var uiEventLogger: QsEventLogger @Captor private lateinit var listingCallbackCaptor: ArgumentCaptor<ControlsListingController.ControlsListingCallback> @@ -118,7 +118,6 @@ class DeviceControlsTileTest : SysuiTestCase() { spiedContext = spy(mContext) doNothing().`when`(spiedContext).startActivity(any(Intent::class.java)) `when`(qsHost.context).thenReturn(spiedContext) - `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) `when`(controlsComponent.isEnabled()).thenReturn(true) `when`(controlsController.getPreferredSelection()) .thenReturn(SelectedItem.StructureItem( @@ -399,6 +398,7 @@ class DeviceControlsTileTest : SysuiTestCase() { private fun createTile(): DeviceControlsTile { return DeviceControlsTile( qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt index 6c0904eb9bfd..f0e4e3adda7c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt @@ -28,7 +28,6 @@ import android.testing.TestableLooper import android.view.View import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.UiEventLogger import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogLaunchAnimator @@ -37,6 +36,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.ZenModeController @@ -46,7 +46,6 @@ import com.android.systemui.util.mockito.nullable import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.SecureSettings import com.google.common.truth.Truth.assertThat -import java.io.File import org.junit.After import org.junit.Before import org.junit.Test @@ -55,8 +54,9 @@ import org.mockito.Mock import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.never import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import java.io.File +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @@ -84,7 +84,7 @@ class DndTileTest : SysuiTestCase() { private lateinit var qsLogger: QSLogger @Mock - private lateinit var uiEventLogger: UiEventLogger + private lateinit var uiEventLogger: QsEventLogger @Mock private lateinit var zenModeController: ZenModeController @@ -109,7 +109,6 @@ class DndTileTest : SysuiTestCase() { secureSettings = FakeSettings() whenever(qsHost.userId).thenReturn(DEFAULT_USER) - whenever(qsHost.uiEventLogger).thenReturn(uiEventLogger) val wrappedContext = object : ContextWrapper(context) { override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { @@ -120,6 +119,7 @@ class DndTileTest : SysuiTestCase() { tile = DndTile( qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java index 7d41aa6c3548..f231c6e56096 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java @@ -48,6 +48,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserTracker; @@ -83,6 +84,8 @@ public class DreamTileTest extends SysuiTestCase { private BroadcastDispatcher mBroadcastDispatcher; @Mock private UserTracker mUserTracker; + @Mock + private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; @@ -258,6 +261,7 @@ public class DreamTileTest extends SysuiTestCase { boolean dreamOnlyEnabledForSystemUser) { return new DreamTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt index 692a64422a7d..73aa6991c18a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt @@ -6,7 +6,6 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake @@ -14,6 +13,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.FlashlightController @@ -45,7 +45,8 @@ class FlashlightTileTest : SysuiTestCase() { @Mock private lateinit var flashlightController: FlashlightController - private val uiEventLogger = UiEventLoggerFake() + @Mock private lateinit var uiEventLogger: QsEventLogger + private val falsingManager = FalsingManagerFake() private lateinit var testableLooper: TestableLooper private lateinit var tile: FlashlightTile @@ -56,11 +57,11 @@ class FlashlightTileTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) Mockito.`when`(qsHost.context).thenReturn(mockContext) - Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) tile = FlashlightTile( qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), falsingManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt index eeebd4fb7792..1d6f225dd0a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt @@ -23,7 +23,6 @@ import android.testing.TestableLooper import android.view.View import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.classifier.FalsingManagerFake @@ -31,7 +30,8 @@ import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController -import com.android.systemui.qs.QSTileHost +import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq @@ -52,13 +52,13 @@ import org.mockito.MockitoAnnotations @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest class FontScalingTileTest : SysuiTestCase() { - @Mock private lateinit var qsHost: QSTileHost + @Mock private lateinit var qsHost: QSHost @Mock private lateinit var metricsLogger: MetricsLogger @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator - @Mock private lateinit var uiEventLogger: UiEventLogger + @Mock private lateinit var uiEventLogger: QsEventLogger private lateinit var testableLooper: TestableLooper private lateinit var fontScalingTile: FontScalingTile @@ -70,11 +70,11 @@ class FontScalingTileTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) `when`(qsHost.getContext()).thenReturn(mContext) - `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) fontScalingTile = FontScalingTile( qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java index 959e750ac5f4..73f61d0690e2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java @@ -38,6 +38,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.DataSaverController; @@ -66,6 +67,8 @@ public class HotspotTileTest extends SysuiTestCase { private HotspotController mHotspotController; @Mock private DataSaverController mDataSaverController; + @Mock + private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; private HotspotTile mTile; @@ -80,6 +83,7 @@ public class HotspotTileTest extends SysuiTestCase { mTile = new HotspotTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java index adfd7f71e8f8..7957c6a7cfb6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java @@ -35,6 +35,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.qs.tiles.dialog.InternetDialogFactory; @@ -63,6 +64,8 @@ public class InternetTileTest extends SysuiTestCase { private AccessPointController mAccessPointController; @Mock private InternetDialogFactory mInternetDialogFactory; + @Mock + private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; private InternetTile mTile; @@ -76,6 +79,7 @@ public class InternetTileTest extends SysuiTestCase { mTile = new InternetTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt index 3642e874e7ae..0bf0b38f7471 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt @@ -22,7 +22,6 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake @@ -30,6 +29,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor import com.android.systemui.qs.tileimpl.QSTileImpl @@ -43,8 +43,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -71,8 +71,9 @@ class LocationTileTest : SysuiTestCase() { private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var panelInteractor: PanelInteractor + @Mock + private lateinit var uiEventLogger: QsEventLogger - private val uiEventLogger = UiEventLoggerFake() private lateinit var testableLooper: TestableLooper private lateinit var tile: LocationTile @@ -80,10 +81,11 @@ class LocationTileTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) - `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) `when`(qsHost.context).thenReturn(mockContext) - tile = LocationTile(qsHost, + tile = LocationTile( + qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), falsingManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt index e2f64b2cc226..ceff546106f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt @@ -21,8 +21,6 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.UiEventLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake @@ -30,6 +28,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController @@ -67,19 +66,22 @@ class MicrophoneToggleTileTest : SysuiTestCase() { private lateinit var privacyController: IndividualSensorPrivacyController @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock + private lateinit var uiEventLogger: QsEventLogger private lateinit var testableLooper: TestableLooper private lateinit var tile: MicrophoneToggleTile - private val uiEventLogger: UiEventLogger = UiEventLoggerFake() + @Before fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) whenever(host.context).thenReturn(mContext) - whenever(host.uiEventLogger).thenReturn(uiEventLogger) - tile = MicrophoneToggleTile(host, + tile = MicrophoneToggleTile( + host, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), metricsLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java index c7dae83e2056..763a7e5e4e06 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java @@ -37,6 +37,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import org.junit.After; @@ -70,6 +71,8 @@ public class NfcTileTest extends SysuiTestCase { private QSLogger mQSLogger; @Mock private BroadcastDispatcher mBroadcastDispatcher; + @Mock + private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; private NfcTile mNfcTile; @@ -84,6 +87,7 @@ public class NfcTileTest extends SysuiTestCase { mNfcTile = new NfcTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt index 04af69c84cf8..6c8f76b48f03 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt @@ -23,8 +23,6 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.UiEventLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake @@ -33,6 +31,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.LocationController @@ -43,8 +42,8 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.anyInt -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -68,17 +67,18 @@ class NightDisplayTileTest : SysuiTestCase() { @Mock private lateinit var mNightDisplayListener: NightDisplayListener + @Mock private lateinit var mUiEventLogger: QsEventLogger + private lateinit var mTestableLooper: TestableLooper private lateinit var mTile: NightDisplayTile - private val mUiEventLogger: UiEventLogger = UiEventLoggerFake() + @Before fun setUp() { MockitoAnnotations.initMocks(this) mTestableLooper = TestableLooper.get(this) whenever(mHost.context).thenReturn(mContext) - whenever(mHost.uiEventLogger).thenReturn(mUiEventLogger) whenever(mHost.userContext).thenReturn(mContext) whenever(mNightDisplayListenerBuilder.setUser(anyInt())) .thenReturn(mNightDisplayListenerBuilder) @@ -87,6 +87,7 @@ class NightDisplayTileTest : SysuiTestCase() { mTile = NightDisplayTile( mHost, + mUiEventLogger, mTestableLooper.looper, Handler(mTestableLooper.looper), FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java index 652c138f6478..c391153fecc1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/OneHandedModeTileTest.java @@ -33,6 +33,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.UserTracker; import com.android.systemui.util.settings.SecureSettings; @@ -65,6 +66,8 @@ public class OneHandedModeTileTest extends SysuiTestCase { private UserTracker mUserTracker; @Mock private SecureSettings mSecureSettings; + @Mock + private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; private OneHandedModeTile mTile; @@ -78,6 +81,7 @@ public class OneHandedModeTileTest extends SysuiTestCase { mTile = spy(new OneHandedModeTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java index 3125d455acfb..6f2d904dda64 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java @@ -30,8 +30,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; -import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; @@ -40,6 +38,7 @@ import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qrcodescanner.controller.QRCodeScannerController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -64,7 +63,8 @@ public class QRCodeScannerTileTest extends SysuiTestCase { private ActivityStarter mActivityStarter; @Mock private QSLogger mQSLogger; - private UiEventLogger mUiEventLogger = new UiEventLoggerFake(); + @Mock + private QsEventLogger mUiEventLogger; @Mock private QRCodeScannerController mController; @@ -79,6 +79,7 @@ public class QRCodeScannerTileTest extends SysuiTestCase { mTile = new QRCodeScannerTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java index 596df7856ee1..b089e380304d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java @@ -58,8 +58,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; -import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; @@ -67,6 +65,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -109,7 +108,8 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { private ActivityStarter mActivityStarter; @Mock private QSLogger mQSLogger; - private UiEventLogger mUiEventLogger = new UiEventLoggerFake(); + @Mock + private QsEventLogger mUiEventLogger; @Mock private QuickAccessWalletClient mQuickAccessWalletClient; @Mock @@ -136,7 +136,6 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { doNothing().when(mSpiedContext).startActivity(any(Intent.class)); when(mHost.getContext()).thenReturn(mSpiedContext); - when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger); when(mQuickAccessWalletClient.getServiceLabel()).thenReturn(LABEL); when(mQuickAccessWalletClient.getTileIcon()).thenReturn(mTileIcon); when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true); @@ -146,6 +145,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { mTile = new QuickAccessWalletTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java index 7913628c5693..d2445944c182 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java @@ -39,6 +39,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -69,6 +70,8 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase { private UserTracker mUserTracker; @Mock private ReduceBrightColorsController mReduceBrightColorsController; + @Mock + private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; private ReduceBrightColorsTile mTile; @@ -85,6 +88,7 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase { true, mReduceBrightColorsController, mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java index 5b94cfedaedf..e106741499ab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java @@ -39,6 +39,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; @@ -87,6 +88,8 @@ public class RotationLockTileTest extends SysuiTestCase { DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController; @Mock RotationPolicyWrapper mRotationPolicyWrapper; + @Mock + QsEventLogger mUiEventLogger; private RotationLockController mController; private TestableLooper mTestableLooper; @@ -105,6 +108,7 @@ public class RotationLockTileTest extends SysuiTestCase { mLockTile = new RotationLockTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java index d9ed1a299f51..fff2b8f5f8cd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java @@ -44,6 +44,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor; import com.android.systemui.qs.tileimpl.QSTileImpl; @@ -86,6 +87,8 @@ public class ScreenRecordTileTest extends SysuiTestCase { private DialogLaunchAnimator mDialogLaunchAnimator; @Mock private PanelInteractor mPanelInteractor; + @Mock + private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; private ScreenRecordTile mTile; @@ -100,6 +103,7 @@ public class ScreenRecordTileTest extends SysuiTestCase { mTile = new ScreenRecordTile( mHost, + mUiEventLogger, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), new FalsingManagerFake(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt index b55657163382..79147e7e66b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt @@ -25,7 +25,6 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake @@ -33,6 +32,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.BatteryController @@ -63,8 +63,8 @@ class UiModeNightTileTest : SysuiTestCase() { @Mock private lateinit var configurationController: ConfigurationController @Mock private lateinit var batteryController: BatteryController @Mock private lateinit var locationController: LocationController + @Mock private lateinit var uiEventLogger: QsEventLogger - private val uiEventLogger = UiEventLoggerFake() private val falsingManager = FalsingManagerFake() private lateinit var testableLooper: TestableLooper private lateinit var tile: UiModeNightTile @@ -81,11 +81,11 @@ class UiModeNightTileTest : SysuiTestCase() { `when`(qsHost.userContext).thenReturn(mContext) `when`(mockContext.resources).thenReturn(resources) `when`(resources.configuration).thenReturn(configuration) - `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) tile = UiModeNightTile( qsHost, + uiEventLogger, testableLooper.looper, Handler(testableLooper.looper), falsingManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java index b55fe3677256..67b1099c1e0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java @@ -20,8 +20,10 @@ import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; @@ -29,6 +31,8 @@ import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; import androidx.test.runner.AndroidJUnit4; @@ -42,6 +46,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.Optional; @@ -58,6 +63,9 @@ public final class AppClipsServiceTest extends SysuiTestCase { @Mock private Optional<Bubbles> mOptionalBubbles; @Mock private Bubbles mBubbles; @Mock private DevicePolicyManager mDevicePolicyManager; + @Mock private UserManager mUserManager; + + private AppClipsService mAppClipsService; @Before public void setUp() { @@ -119,26 +127,53 @@ public final class AppClipsServiceTest extends SysuiTestCase { @Test public void allPrerequisitesSatisfy_shouldReturnTrue() throws RemoteException { + mockToSatisfyAllPrerequisites(); + + assertThat(getInterfaceWithRealContext() + .canLaunchCaptureContentActivityForNote(FAKE_TASK_ID)).isTrue(); + } + + @Test + public void isManagedProfile_shouldUseProxyConnection() throws RemoteException { + when(mUserManager.isManagedProfile()).thenReturn(true); + when(mUserManager.getMainUser()).thenReturn(UserHandle.SYSTEM); + IAppClipsService service = getInterfaceWithRealContext(); + mAppClipsService.mProxyConnectorToMainProfile = + Mockito.spy(mAppClipsService.mProxyConnectorToMainProfile); + + service.canLaunchCaptureContentActivityForNote(FAKE_TASK_ID); + + verify(mAppClipsService.mProxyConnectorToMainProfile).postForResult(any()); + } + + @Test + public void isManagedProfile_noMainUser_shouldReturnFalse() { + when(mUserManager.isManagedProfile()).thenReturn(true); + when(mUserManager.getMainUser()).thenReturn(null); + + getInterfaceWithRealContext(); + + assertThat(mAppClipsService.mProxyConnectorToMainProfile).isNull(); + } + + private void mockToSatisfyAllPrerequisites() { when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true); when(mOptionalBubbles.isEmpty()).thenReturn(false); when(mOptionalBubbles.get()).thenReturn(mBubbles); when(mBubbles.isAppBubbleTaskId(eq((FAKE_TASK_ID)))).thenReturn(true); when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(false); - - assertThat(getInterfaceWithRealContext() - .canLaunchCaptureContentActivityForNote(FAKE_TASK_ID)).isTrue(); } private IAppClipsService getInterfaceWithRealContext() { - AppClipsService appClipsService = new AppClipsService(getContext(), mFeatureFlags, - mOptionalBubbles, mDevicePolicyManager); - return getInterfaceFromService(appClipsService); + mAppClipsService = new AppClipsService(getContext(), mFeatureFlags, + mOptionalBubbles, mDevicePolicyManager, mUserManager); + return getInterfaceFromService(mAppClipsService); } private IAppClipsService getInterfaceWithMockContext() { - AppClipsService appClipsService = new AppClipsService(mMockContext, mFeatureFlags, - mOptionalBubbles, mDevicePolicyManager); - return getInterfaceFromService(appClipsService); + mAppClipsService = new AppClipsService(mMockContext, mFeatureFlags, + mOptionalBubbles, mDevicePolicyManager, mUserManager); + return getInterfaceFromService(mAppClipsService); } private static IAppClipsService getInterfaceFromService(AppClipsService appClipsService) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java index ad06dcc6f327..31a33d4ff908 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java @@ -49,6 +49,8 @@ import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.UserHandle; +import android.os.UserManager; import android.testing.AndroidTestingRunner; import androidx.test.rule.ActivityTestRule; @@ -98,6 +100,9 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase { private UserTracker mUserTracker; @Mock private UiEventLogger mUiEventLogger; + @Mock + private UserManager mUserManager; + @Main private Handler mMainHandler; @@ -109,7 +114,7 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase { protected AppClipsTrampolineActivityTestable create(Intent unUsed) { return new AppClipsTrampolineActivityTestable(mDevicePolicyManager, mFeatureFlags, mOptionalBubbles, mNoteTaskController, mPackageManager, - mUserTracker, mUiEventLogger, mMainHandler); + mUserTracker, mUiEventLogger, mUserManager, mMainHandler); } }; @@ -264,6 +269,40 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase { verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_TRIGGERED, TEST_UID, TEST_CALLING_PACKAGE); } + @Test + public void startAppClipsActivity_throughWPUser_shouldStartMainUserActivity() + throws NameNotFoundException { + when(mUserManager.isManagedProfile()).thenReturn(true); + when(mUserManager.getMainUser()).thenReturn(UserHandle.SYSTEM); + mockToSatisfyAllPrerequisites(); + + AppClipsTrampolineActivityTestable activity = mActivityRule.launchActivity(mActivityIntent); + waitForIdleSync(); + + Intent actualIntent = activity.mStartedIntent; + assertThat(actualIntent.getComponent()).isEqualTo( + new ComponentName(mContext, AppClipsTrampolineActivity.class)); + assertThat(actualIntent.getFlags()).isEqualTo(Intent.FLAG_ACTIVITY_FORWARD_RESULT); + assertThat(activity.mStartingUser).isEqualTo(UserHandle.SYSTEM); + } + + @Test + public void startAppClipsActivity_throughWPUser_noMainUser_shouldFinishWithFailed() + throws NameNotFoundException { + when(mUserManager.isManagedProfile()).thenReturn(true); + when(mUserManager.getMainUser()).thenReturn(null); + + mockToSatisfyAllPrerequisites(); + + mActivityRule.launchActivity(mActivityIntent); + waitForIdleSync(); + + ActivityResult actualResult = mActivityRule.getActivityResult(); + assertThat(actualResult.getResultCode()).isEqualTo(Activity.RESULT_OK); + assertThat(getStatusCodeExtra(actualResult.getResultData())) + .isEqualTo(CAPTURE_CONTENT_FOR_NOTE_FAILED); + } + private void mockToSatisfyAllPrerequisites() throws NameNotFoundException { when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true); when(mOptionalBubbles.isEmpty()).thenReturn(false); @@ -282,6 +321,9 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase { public static final class AppClipsTrampolineActivityTestable extends AppClipsTrampolineActivity { + Intent mStartedIntent; + UserHandle mStartingUser; + public AppClipsTrampolineActivityTestable(DevicePolicyManager devicePolicyManager, FeatureFlags flags, Optional<Bubbles> optionalBubbles, @@ -289,9 +331,10 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase { PackageManager packageManager, UserTracker userTracker, UiEventLogger uiEventLogger, + UserManager userManager, @Main Handler mainHandler) { super(devicePolicyManager, flags, optionalBubbles, noteTaskController, packageManager, - userTracker, uiEventLogger, mainHandler); + userTracker, uiEventLogger, userManager, mainHandler); } @Override @@ -303,6 +346,12 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase { public void startActivity(Intent unUsed) { // Ignore this intent to avoid App Clips screenshot editing activity from starting. } + + @Override + public void startActivityAsUser(Intent startedIntent, UserHandle startingUser) { + mStartedIntent = startedIntent; + mStartingUser = startingUser; + } } private static int getStatusCodeExtra(Intent intent) { 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 7b37ea0c9a1a..068d933652ac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -32,6 +32,7 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -66,6 +67,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardClockSwitchController; +import com.android.keyguard.KeyguardSliceViewController; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; @@ -74,6 +76,7 @@ import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; +import com.android.keyguard.logging.KeyguardLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; @@ -90,6 +93,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerReposito import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository; import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; @@ -106,6 +110,7 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.multishade.domain.interactor.MultiShadeInteractor; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.QSFragment; @@ -232,7 +237,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; @Mock protected KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent; @Mock protected KeyguardClockSwitchController mKeyguardClockSwitchController; - @Mock protected KeyguardStatusViewController mKeyguardStatusViewController; @Mock protected KeyguardStatusBarViewController mKeyguardStatusBarViewController; @Mock protected NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; @@ -292,9 +296,14 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected AlternateBouncerInteractor mAlternateBouncerInteractor; @Mock protected MotionEvent mDownMotionEvent; @Mock protected CoroutineDispatcher mMainDispatcher; + @Mock protected KeyguardSliceViewController mKeyguardSliceViewController; + @Mock protected KeyguardLogger mKeyguardLogger; + @Mock protected KeyguardStatusView mKeyguardStatusView; @Captor protected ArgumentCaptor<NotificationStackScrollLayout.OnEmptySpaceClickListener> mEmptySpaceClickListenerCaptor; + @Mock protected ActivityStarter mActivityStarter; + @Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; protected KeyguardInteractor mKeyguardInteractor; @@ -307,6 +316,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { protected List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners; protected Handler mMainHandler; protected View.OnLayoutChangeListener mLayoutChangeListener; + protected KeyguardStatusViewController mKeyguardStatusViewController; protected final FalsingManagerFake mFalsingManager = new FalsingManagerFake(); protected final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty(); @@ -333,6 +343,18 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext); keyguardStatusView.setId(R.id.keyguard_status_view); + mKeyguardStatusViewController = spy(new KeyguardStatusViewController( + mKeyguardStatusView, + mKeyguardSliceViewController, + mKeyguardClockSwitchController, + mKeyguardStateController, + mUpdateMonitor, + mConfigurationController, + mDozeParameters, + mScreenOffAnimationController, + mKeyguardLogger, + mFeatureFlags, + mInteractionJankMonitor)); when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false); when(mHeadsUpCallback.getContext()).thenReturn(mContext); @@ -364,12 +386,15 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea); when(mKeyguardBottomArea.animate()).thenReturn(mViewPropertyAnimator); when(mView.animate()).thenReturn(mViewPropertyAnimator); + when(mKeyguardStatusView.animate()).thenReturn(mViewPropertyAnimator); when(mViewPropertyAnimator.translationX(anyFloat())).thenReturn(mViewPropertyAnimator); when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator); when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator); + when(mViewPropertyAnimator.setStartDelay(anyLong())).thenReturn(mViewPropertyAnimator); when(mViewPropertyAnimator.setInterpolator(any())).thenReturn(mViewPropertyAnimator); when(mViewPropertyAnimator.setListener(any())).thenReturn(mViewPropertyAnimator); when(mViewPropertyAnimator.setUpdateListener(any())).thenReturn(mViewPropertyAnimator); + when(mViewPropertyAnimator.withEndAction(any())).thenReturn(mViewPropertyAnimator); when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame); when(mView.findViewById(R.id.keyguard_status_view)) .thenReturn(mock(KeyguardStatusView.class)); @@ -575,7 +600,9 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { () -> mMultiShadeInteractor, mDumpManager, mKeyuardLongPressViewModel, - mKeyguardInteractor); + mKeyguardInteractor, + mActivityStarter, + mKeyguardFaceAuthInteractor); mNotificationPanelViewController.initDependencies( mCentralSurfaces, null, @@ -641,15 +668,20 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mMetricsLogger, mFeatureFlags, mInteractionJankMonitor, - mShadeLog + mShadeLog, + mKeyguardFaceAuthInteractor ); } @After public void tearDown() { - mNotificationPanelViewController.mBottomAreaShadeAlphaAnimator.cancel(); - mNotificationPanelViewController.cancelHeightAnimator(); - mMainHandler.removeCallbacksAndMessages(null); + if (mNotificationPanelViewController != null) { + mNotificationPanelViewController.mBottomAreaShadeAlphaAnimator.cancel(); + mNotificationPanelViewController.cancelHeightAnimator(); + } + if (mMainHandler != null) { + mMainHandler.removeCallbacksAndMessages(null); + } } protected void setBottomPadding(int stackBottom, int lockIconPadding, int indicationPadding, 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 2db9c9788bf8..600fb5c2e1bc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -930,6 +930,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo mTouchHandler.onTouch(mock(View.class), mDownMotionEvent); mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0); + verify(mKeyguardFaceAuthInteractor).onNotificationPanelClicked(); verify(mUpdateMonitor).requestFaceAuth( FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java index d8ffe39e427d..908f7cbf4801 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java @@ -62,6 +62,7 @@ import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.media.controls.pipeline.MediaDataManager; import com.android.systemui.media.controls.ui.MediaHierarchyManager; import com.android.systemui.plugins.FalsingManager; @@ -239,7 +240,8 @@ public class QuickSettingsControllerTest extends SysuiTestCase { mMetricsLogger, mFeatureFlags, mInteractionJankMonitor, - mShadeLogger + mShadeLogger, + mock(KeyguardFaceAuthInteractor.class) ); mFragmentListener = mQsController.getQsFragmentListener(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt index d5308298202d..76f7401adbb2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt @@ -16,6 +16,8 @@ package com.android.systemui.shade import android.animation.Animator +import android.app.AlarmManager +import android.app.PendingIntent import android.app.StatusBarManager import android.content.Context import android.content.res.Resources @@ -40,18 +42,21 @@ import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.demomode.DemoMode import com.android.systemui.demomode.DemoModeController import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.ChipVisibilityListener import com.android.systemui.qs.HeaderPrivacyIconsController -import com.android.systemui.qs.carrier.QSCarrierGroup -import com.android.systemui.qs.carrier.QSCarrierGroupController +import com.android.systemui.shade.ShadeHeaderController.Companion.DEFAULT_CLOCK_INTENT import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_HEADER_CONSTRAINT import com.android.systemui.shade.ShadeHeaderController.Companion.QQS_HEADER_CONSTRAINT import com.android.systemui.shade.ShadeHeaderController.Companion.QS_HEADER_CONSTRAINT +import com.android.systemui.shade.carrier.ShadeCarrierGroup +import com.android.systemui.shade.carrier.ShadeCarrierGroupController import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.phone.StatusIconContainer import com.android.systemui.statusbar.policy.Clock import com.android.systemui.statusbar.policy.FakeConfigurationController +import com.android.systemui.statusbar.policy.NextAlarmController import com.android.systemui.statusbar.policy.VariableDateView import com.android.systemui.statusbar.policy.VariableDateViewController import com.android.systemui.util.mockito.any @@ -88,11 +93,12 @@ class ShadeHeaderControllerTest : SysuiTestCase() { @Mock private lateinit var statusBarIconController: StatusBarIconController @Mock private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory @Mock private lateinit var iconManager: StatusBarIconController.TintedIconManager - @Mock private lateinit var qsCarrierGroupController: QSCarrierGroupController - @Mock private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder + @Mock private lateinit var mShadeCarrierGroupController: ShadeCarrierGroupController + @Mock + private lateinit var mShadeCarrierGroupControllerBuilder: ShadeCarrierGroupController.Builder @Mock private lateinit var clock: Clock @Mock private lateinit var date: VariableDateView - @Mock private lateinit var carrierGroup: QSCarrierGroup + @Mock private lateinit var carrierGroup: ShadeCarrierGroup @Mock private lateinit var batteryMeterView: BatteryMeterView @Mock private lateinit var batteryMeterViewController: BatteryMeterViewController @Mock private lateinit var privacyIconsController: HeaderPrivacyIconsController @@ -113,6 +119,8 @@ class ShadeHeaderControllerTest : SysuiTestCase() { @Mock private lateinit var demoModeController: DemoModeController @Mock private lateinit var qsBatteryModeController: QsBatteryModeController + @Mock private lateinit var nextAlarmController: NextAlarmController + @Mock private lateinit var activityStarter: ActivityStarter @JvmField @Rule val mockitoRule = MockitoJUnit.rule() var viewVisibility = View.GONE @@ -131,7 +139,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { whenever<TextView>(view.findViewById(R.id.date)).thenReturn(date) whenever(date.context).thenReturn(mockedContext) - whenever<QSCarrierGroup>(view.findViewById(R.id.carrier_group)).thenReturn(carrierGroup) + whenever<ShadeCarrierGroup>(view.findViewById(R.id.carrier_group)).thenReturn(carrierGroup) whenever<BatteryMeterView>(view.findViewById(R.id.batteryRemainingIcon)) .thenReturn(batteryMeterView) @@ -142,9 +150,10 @@ class ShadeHeaderControllerTest : SysuiTestCase() { whenever(view.context).thenReturn(viewContext) whenever(view.resources).thenReturn(context.resources) whenever(statusIcons.context).thenReturn(context) - whenever(qsCarrierGroupControllerBuilder.setQSCarrierGroup(any())) - .thenReturn(qsCarrierGroupControllerBuilder) - whenever(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController) + whenever(mShadeCarrierGroupControllerBuilder.setShadeCarrierGroup(any())) + .thenReturn(mShadeCarrierGroupControllerBuilder) + whenever(mShadeCarrierGroupControllerBuilder.build()) + .thenReturn(mShadeCarrierGroupController) whenever(view.setVisibility(anyInt())).then { viewVisibility = it.arguments[0] as Int null @@ -175,10 +184,12 @@ class ShadeHeaderControllerTest : SysuiTestCase() { variableDateViewControllerFactory, batteryMeterViewController, dumpManager, - qsCarrierGroupControllerBuilder, + mShadeCarrierGroupControllerBuilder, combinedShadeHeadersConstraintManager, demoModeController, qsBatteryModeController, + nextAlarmController, + activityStarter, ) whenever(view.isAttachedToWindow).thenReturn(true) shadeHeaderController.init() @@ -189,7 +200,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { @Test fun updateListeners_registersWhenVisible() { makeShadeVisible() - verify(qsCarrierGroupController).setListening(true) + verify(mShadeCarrierGroupController).setListening(true) verify(statusBarIconController).addIconGroup(any()) } @@ -213,7 +224,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { @Test fun singleCarrier_enablesCarrierIconsInStatusIcons() { - whenever(qsCarrierGroupController.isSingleCarrier).thenReturn(true) + whenever(mShadeCarrierGroupController.isSingleCarrier).thenReturn(true) makeShadeVisible() @@ -222,7 +233,7 @@ class ShadeHeaderControllerTest : SysuiTestCase() { @Test fun dualCarrier_disablesCarrierIconsInStatusIcons() { - whenever(qsCarrierGroupController.isSingleCarrier).thenReturn(false) + whenever(mShadeCarrierGroupController.isSingleCarrier).thenReturn(false) makeShadeVisible() @@ -349,9 +360,9 @@ class ShadeHeaderControllerTest : SysuiTestCase() { verify(batteryMeterViewController).init() verify(batteryMeterViewController).ignoreTunerUpdates() - val inOrder = Mockito.inOrder(qsCarrierGroupControllerBuilder) - inOrder.verify(qsCarrierGroupControllerBuilder).setQSCarrierGroup(carrierGroup) - inOrder.verify(qsCarrierGroupControllerBuilder).build() + val inOrder = Mockito.inOrder(mShadeCarrierGroupControllerBuilder) + inOrder.verify(mShadeCarrierGroupControllerBuilder).setShadeCarrierGroup(carrierGroup) + inOrder.verify(mShadeCarrierGroupControllerBuilder).build() } @Test @@ -826,6 +837,28 @@ class ShadeHeaderControllerTest : SysuiTestCase() { verify(carrierGroup).setPaddingRelative(514, 0, 0, 0) } + @Test + fun launchClock_launchesDefaultIntentWhenNoAlarmSet() { + shadeHeaderController.launchClockActivity() + + verify(activityStarter).postStartActivityDismissingKeyguard(DEFAULT_CLOCK_INTENT, 0) + } + + @Test + fun launchClock_launchesNextAlarmWhenExists() { + val pendingIntent = mock<PendingIntent>() + val aci = AlarmManager.AlarmClockInfo(12345, pendingIntent) + val captor = + ArgumentCaptor.forClass(NextAlarmController.NextAlarmChangeCallback::class.java) + + verify(nextAlarmController).addCallback(capture(captor)) + captor.value.onNextAlarmChanged(aci) + + shadeHeaderController.launchClockActivity() + + verify(activityStarter).postStartActivityDismissingKeyguard(pendingIntent) + } + private fun View.executeLayoutChange( left: Int, top: Int, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/CellSignalStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt index 75be74b13c87..7a9ef62278a4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/CellSignalStateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt @@ -1,11 +1,11 @@ /* - * Copyright (C) 2020 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.qs.carrier +package com.android.systemui.shade.carrier import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest @@ -45,4 +45,4 @@ class CellSignalStateTest : SysuiTestCase() { assertNotSame(c, other) } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java index 1e7722ae8395..2ef3d60c7754 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2020 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.qs.carrier; +package com.android.systemui.shade.carrier; import static com.google.common.truth.Truth.assertThat; @@ -63,13 +63,13 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest -public class QSCarrierGroupControllerTest extends LeakCheckedTest { +public class ShadeCarrierGroupControllerTest extends LeakCheckedTest { - private QSCarrierGroupController mQSCarrierGroupController; + private ShadeCarrierGroupController mShadeCarrierGroupController; private SignalCallback mSignalCallback; private CarrierTextManager.CarrierTextCallback mCallback; @Mock - private QSCarrierGroup mQSCarrierGroup; + private ShadeCarrierGroup mShadeCarrierGroup; @Mock private ActivityStarter mActivityStarter; @Mock @@ -81,14 +81,14 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { @Mock private CarrierConfigTracker mCarrierConfigTracker; @Mock - private QSCarrier mQSCarrier1; + private ShadeCarrier mShadeCarrier1; @Mock - private QSCarrier mQSCarrier2; + private ShadeCarrier mShadeCarrier2; @Mock - private QSCarrier mQSCarrier3; + private ShadeCarrier mShadeCarrier3; private TestableLooper mTestableLooper; @Mock - private QSCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener; + private ShadeCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener; private FakeSlotIndexResolver mSlotIndexResolver; private ClickListenerTextView mNoCarrierTextView; @@ -116,28 +116,28 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { .setListening(any(CarrierTextManager.CarrierTextCallback.class)); mNoCarrierTextView = new ClickListenerTextView(mContext); - when(mQSCarrierGroup.getNoSimTextView()).thenReturn(mNoCarrierTextView); - when(mQSCarrierGroup.getCarrier1View()).thenReturn(mQSCarrier1); - when(mQSCarrierGroup.getCarrier2View()).thenReturn(mQSCarrier2); - when(mQSCarrierGroup.getCarrier3View()).thenReturn(mQSCarrier3); - when(mQSCarrierGroup.getCarrierDivider1()).thenReturn(new View(mContext)); - when(mQSCarrierGroup.getCarrierDivider2()).thenReturn(new View(mContext)); + when(mShadeCarrierGroup.getNoSimTextView()).thenReturn(mNoCarrierTextView); + when(mShadeCarrierGroup.getCarrier1View()).thenReturn(mShadeCarrier1); + when(mShadeCarrierGroup.getCarrier2View()).thenReturn(mShadeCarrier2); + when(mShadeCarrierGroup.getCarrier3View()).thenReturn(mShadeCarrier3); + when(mShadeCarrierGroup.getCarrierDivider1()).thenReturn(new View(mContext)); + when(mShadeCarrierGroup.getCarrierDivider2()).thenReturn(new View(mContext)); mSlotIndexResolver = new FakeSlotIndexResolver(); - mQSCarrierGroupController = new QSCarrierGroupController.Builder( + mShadeCarrierGroupController = new ShadeCarrierGroupController.Builder( mActivityStarter, handler, TestableLooper.get(this).getLooper(), mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker, mSlotIndexResolver) - .setQSCarrierGroup(mQSCarrierGroup) + .setShadeCarrierGroup(mShadeCarrierGroup) .build(); - mQSCarrierGroupController.setListening(true); + mShadeCarrierGroupController.setListening(true); } @Test public void testInitiallyMultiCarrier() { - assertFalse(mQSCarrierGroupController.isSingleCarrier()); + assertFalse(mShadeCarrierGroupController.isSingleCarrier()); } @Test // throws no Exception @@ -257,12 +257,12 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { true /* airplaneMode */); mCallback.updateCarrierInfo(info); mTestableLooper.processAllMessages(); - assertEquals(View.GONE, mQSCarrierGroup.getNoSimTextView().getVisibility()); + assertEquals(View.GONE, mShadeCarrierGroup.getNoSimTextView().getVisibility()); } @Test public void testListenerNotCalledOnRegistreation() { - mQSCarrierGroupController + mShadeCarrierGroupController .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener); verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean()); @@ -282,9 +282,9 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(info); mTestableLooper.processAllMessages(); - verify(mQSCarrier1).updateState(any(), eq(true)); - verify(mQSCarrier2).updateState(any(), eq(true)); - verify(mQSCarrier3).updateState(any(), eq(true)); + verify(mShadeCarrier1).updateState(any(), eq(true)); + verify(mShadeCarrier2).updateState(any(), eq(true)); + verify(mShadeCarrier3).updateState(any(), eq(true)); } @Test @@ -301,9 +301,9 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(info); mTestableLooper.processAllMessages(); - verify(mQSCarrier1).updateState(any(), eq(false)); - verify(mQSCarrier2).updateState(any(), eq(false)); - verify(mQSCarrier3).updateState(any(), eq(false)); + verify(mShadeCarrier1).updateState(any(), eq(false)); + verify(mShadeCarrier2).updateState(any(), eq(false)); + verify(mShadeCarrier3).updateState(any(), eq(false)); } @Test @@ -327,7 +327,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(singleCarrierInfo); mTestableLooper.processAllMessages(); - mQSCarrierGroupController + mShadeCarrierGroupController .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener); reset(mOnSingleCarrierChangedListener); @@ -353,7 +353,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(singleCarrierInfo); mTestableLooper.processAllMessages(); - mQSCarrierGroupController + mShadeCarrierGroupController .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener); mCallback.updateCarrierInfo(singleCarrierInfo); @@ -375,7 +375,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(multiCarrierInfo); mTestableLooper.processAllMessages(); - mQSCarrierGroupController + mShadeCarrierGroupController .setOnSingleCarrierChangedListener(mOnSingleCarrierChangedListener); mCallback.updateCarrierInfo(multiCarrierInfo); @@ -389,12 +389,12 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { ArgumentCaptor<View.OnClickListener> captor = ArgumentCaptor.forClass(View.OnClickListener.class); - verify(mQSCarrier1).setOnClickListener(captor.capture()); - verify(mQSCarrier2).setOnClickListener(captor.getValue()); - verify(mQSCarrier3).setOnClickListener(captor.getValue()); + verify(mShadeCarrier1).setOnClickListener(captor.capture()); + verify(mShadeCarrier2).setOnClickListener(captor.getValue()); + verify(mShadeCarrier3).setOnClickListener(captor.getValue()); assertThat(mNoCarrierTextView.getOnClickListener()).isSameInstanceAs(captor.getValue()); - verify(mQSCarrierGroup, never()).setOnClickListener(any()); + verify(mShadeCarrierGroup, never()).setOnClickListener(any()); } @Test @@ -402,10 +402,10 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { ArgumentCaptor<View.OnClickListener> captor = ArgumentCaptor.forClass(View.OnClickListener.class); - verify(mQSCarrier1).setOnClickListener(captor.capture()); - when(mQSCarrier1.isVisibleToUser()).thenReturn(false); + verify(mShadeCarrier1).setOnClickListener(captor.capture()); + when(mShadeCarrier1.isVisibleToUser()).thenReturn(false); - captor.getValue().onClick(mQSCarrier1); + captor.getValue().onClick(mShadeCarrier1); verifyZeroInteractions(mActivityStarter); } @@ -415,17 +415,17 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { ArgumentCaptor.forClass(View.OnClickListener.class); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mQSCarrier1).setOnClickListener(listenerCaptor.capture()); - when(mQSCarrier1.isVisibleToUser()).thenReturn(true); + verify(mShadeCarrier1).setOnClickListener(listenerCaptor.capture()); + when(mShadeCarrier1.isVisibleToUser()).thenReturn(true); - listenerCaptor.getValue().onClick(mQSCarrier1); + listenerCaptor.getValue().onClick(mShadeCarrier1); verify(mActivityStarter) .postStartActivityDismissingKeyguard(intentCaptor.capture(), anyInt()); assertThat(intentCaptor.getValue().getAction()) .isEqualTo(Settings.ACTION_WIRELESS_SETTINGS); } - private class FakeSlotIndexResolver implements QSCarrierGroupController.SlotIndexResolver { + private class FakeSlotIndexResolver implements ShadeCarrierGroupController.SlotIndexResolver { public boolean overrideInvalid; @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java index 9115ab3bacca..44613103a5b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2020 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. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.qs.carrier; +package com.android.systemui.shade.carrier; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -39,9 +39,9 @@ import org.junit.runner.RunWith; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest -public class QSCarrierTest extends SysuiTestCase { +public class ShadeCarrierTest extends SysuiTestCase { - private QSCarrier mQSCarrier; + private ShadeCarrier mShadeCarrier; private TestableLooper mTestableLooper; private int mSignalIconId; @@ -51,7 +51,7 @@ public class QSCarrierTest extends SysuiTestCase { LayoutInflater inflater = LayoutInflater.from(mContext); mContext.ensureTestableResources(); mTestableLooper.runWithLooper(() -> - mQSCarrier = (QSCarrier) inflater.inflate(R.layout.qs_carrier, null)); + mShadeCarrier = (ShadeCarrier) inflater.inflate(R.layout.shade_carrier, null)); // In this case, the id is an actual drawable id mSignalIconId = TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[0]; @@ -61,76 +61,76 @@ public class QSCarrierTest extends SysuiTestCase { public void testUpdateState_first() { CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false); - assertTrue(mQSCarrier.updateState(c, false)); + assertTrue(mShadeCarrier.updateState(c, false)); } @Test public void testUpdateState_same() { CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false); - assertTrue(mQSCarrier.updateState(c, false)); - assertFalse(mQSCarrier.updateState(c, false)); + assertTrue(mShadeCarrier.updateState(c, false)); + assertFalse(mShadeCarrier.updateState(c, false)); } @Test public void testUpdateState_changed() { CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false); - assertTrue(mQSCarrier.updateState(c, false)); + assertTrue(mShadeCarrier.updateState(c, false)); CellSignalState other = c.changeVisibility(false); - assertTrue(mQSCarrier.updateState(other, false)); + assertTrue(mShadeCarrier.updateState(other, false)); } @Test public void testUpdateState_singleCarrier_first() { CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false); - assertTrue(mQSCarrier.updateState(c, true)); + assertTrue(mShadeCarrier.updateState(c, true)); } @Test public void testUpdateState_singleCarrier_noShowIcon() { CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false); - mQSCarrier.updateState(c, true); + mShadeCarrier.updateState(c, true); - assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility()); + assertEquals(View.GONE, mShadeCarrier.getRSSIView().getVisibility()); } @Test public void testUpdateState_multiCarrier_showIcon() { CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false); - mQSCarrier.updateState(c, false); + mShadeCarrier.updateState(c, false); - assertEquals(View.VISIBLE, mQSCarrier.getRSSIView().getVisibility()); + assertEquals(View.VISIBLE, mShadeCarrier.getRSSIView().getVisibility()); } @Test public void testUpdateState_changeSingleMultiSingle() { CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false); - mQSCarrier.updateState(c, true); - assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility()); + mShadeCarrier.updateState(c, true); + assertEquals(View.GONE, mShadeCarrier.getRSSIView().getVisibility()); - mQSCarrier.updateState(c, false); - assertEquals(View.VISIBLE, mQSCarrier.getRSSIView().getVisibility()); + mShadeCarrier.updateState(c, false); + assertEquals(View.VISIBLE, mShadeCarrier.getRSSIView().getVisibility()); - mQSCarrier.updateState(c, true); - assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility()); + mShadeCarrier.updateState(c, true); + assertEquals(View.GONE, mShadeCarrier.getRSSIView().getVisibility()); } @Test public void testCarrierNameMaxWidth_smallScreen_fromResource() { int maxEms = 10; - mContext.getOrCreateTestableResources().addOverride(R.integer.qs_carrier_max_em, maxEms); + mContext.getOrCreateTestableResources().addOverride(R.integer.shade_carrier_max_em, maxEms); mContext.getOrCreateTestableResources() .addOverride(R.bool.config_use_large_screen_shade_header, false); - TextView carrierText = mQSCarrier.requireViewById(R.id.qs_carrier_text); + TextView carrierText = mShadeCarrier.requireViewById(R.id.shade_carrier_text); - mQSCarrier.onConfigurationChanged(mContext.getResources().getConfiguration()); + mShadeCarrier.onConfigurationChanged(mContext.getResources().getConfiguration()); assertEquals(maxEms, carrierText.getMaxEms()); } @@ -138,12 +138,12 @@ public class QSCarrierTest extends SysuiTestCase { @Test public void testCarrierNameMaxWidth_largeScreen_maxInt() { int maxEms = 10; - mContext.getOrCreateTestableResources().addOverride(R.integer.qs_carrier_max_em, maxEms); + mContext.getOrCreateTestableResources().addOverride(R.integer.shade_carrier_max_em, maxEms); mContext.getOrCreateTestableResources() .addOverride(R.bool.config_use_large_screen_shade_header, true); - TextView carrierText = mQSCarrier.requireViewById(R.id.qs_carrier_text); + TextView carrierText = mShadeCarrier.requireViewById(R.id.shade_carrier_text); - mQSCarrier.onConfigurationChanged(mContext.getResources().getConfiguration()); + mShadeCarrier.onConfigurationChanged(mContext.getResources().getConfiguration()); assertEquals(Integer.MAX_VALUE, carrierText.getMaxEms()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index 569f90b64609..4438b98f6fad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -614,9 +614,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { public void onBiometricHelp_coEx_faceFailure() { createController(); - // GIVEN unlocking with fingerprint is possible - when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(anyInt())) - .thenReturn(true); + // GIVEN unlocking with fingerprint is possible and allowed + fingerprintUnlockIsPossibleAndAllowed(); String message = "A message"; mController.setVisible(true); @@ -641,9 +640,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { public void onBiometricHelp_coEx_faceUnavailable() { createController(); - // GIVEN unlocking with fingerprint is possible - when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(anyInt())) - .thenReturn(true); + // GIVEN unlocking with fingerprint is possible and allowed + fingerprintUnlockIsPossibleAndAllowed(); String message = "A message"; mController.setVisible(true); @@ -664,6 +662,35 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { mContext.getString(R.string.keyguard_suggest_fingerprint)); } + + @Test + public void onBiometricHelp_coEx_faceUnavailable_fpNotAllowed() { + createController(); + + // GIVEN unlocking with fingerprint is possible but not allowed + setupFingerprintUnlockPossible(true); + when(mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed()) + .thenReturn(false); + + String message = "A message"; + mController.setVisible(true); + + // WHEN there's a face unavailable message + mController.getKeyguardCallback().onBiometricHelp( + BIOMETRIC_HELP_FACE_NOT_AVAILABLE, + message, + BiometricSourceType.FACE); + + // THEN show sequential messages such as: 'face unlock unavailable' and + // 'try fingerprint instead' + verifyIndicationMessage( + INDICATION_TYPE_BIOMETRIC_MESSAGE, + message); + verifyIndicationMessage( + INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, + mContext.getString(R.string.keyguard_unlock)); + } + @Test public void onBiometricHelp_coEx_fpFailure_faceAlreadyUnlocked() { createController(); @@ -818,8 +845,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void faceErrorTimeout_whenFingerprintEnrolled_doesNotShowMessage() { createController(); - when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - getCurrentUser())).thenReturn(true); + fingerprintUnlockIsPossibleAndAllowed(); String message = "A message"; mController.setVisible(true); @@ -832,9 +858,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { public void sendFaceHelpMessages_fingerprintEnrolled() { createController(); - // GIVEN fingerprint enrolled - when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - getCurrentUser())).thenReturn(true); + // GIVEN unlocking with fingerprint is possible and allowed + fingerprintUnlockIsPossibleAndAllowed(); // WHEN help messages received that are allowed to show final String helpString = "helpString"; @@ -859,9 +884,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { public void doNotSendMostFaceHelpMessages_fingerprintEnrolled() { createController(); - // GIVEN fingerprint enrolled - when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - getCurrentUser())).thenReturn(true); + // GIVEN unlocking with fingerprint is possible and allowed + fingerprintUnlockIsPossibleAndAllowed(); // WHEN help messages received that aren't supposed to show final String helpString = "helpString"; @@ -886,9 +910,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { public void sendAllFaceHelpMessages_fingerprintNotEnrolled() { createController(); - // GIVEN fingerprint NOT enrolled - when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - getCurrentUser())).thenReturn(false); + // GIVEN fingerprint NOT possible + fingerprintUnlockIsNotPossible(); // WHEN help messages received final Set<CharSequence> helpStrings = new HashSet<>(); @@ -917,9 +940,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { public void sendTooDarkFaceHelpMessages_onTimeout_noFpEnrolled() { createController(); - // GIVEN fingerprint NOT enrolled - when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - getCurrentUser())).thenReturn(false); + // GIVEN fingerprint not possible + fingerprintUnlockIsNotPossible(); // WHEN help message received and deferred message is valid final String helpString = "helpMsg"; @@ -948,9 +970,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { public void sendTooDarkFaceHelpMessages_onTimeout_fingerprintEnrolled() { createController(); - // GIVEN fingerprint enrolled - when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - getCurrentUser())).thenReturn(true); + // GIVEN unlocking with fingerprint is possible and allowed + fingerprintUnlockIsPossibleAndAllowed(); // WHEN help message received and deferredMessage is valid final String helpString = "helpMsg"; @@ -1500,7 +1521,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void onBiometricError_faceLockedOutFirstTimeAndFpAllowed_showsTheFpFollowupMessage() { createController(); - fingerprintUnlockIsPossible(); + fingerprintUnlockIsPossibleAndAllowed(); onFaceLockoutError("first lockout"); verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, @@ -1559,7 +1580,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void onBiometricError_faceLockedOutAgainAndFpAllowed_showsTheFpFollowupMessage() { createController(); - fingerprintUnlockIsPossible(); + fingerprintUnlockIsPossibleAndAllowed(); onFaceLockoutError("first lockout"); clearInvocations(mRotateTextViewController); @@ -1668,7 +1689,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { public void onBiometricError_screenIsTurningOn_faceLockedOutFpIsAvailable_showsMessage() { createController(); screenIsTurningOn(); - fingerprintUnlockIsPossible(); + fingerprintUnlockIsPossibleAndAllowed(); onFaceLockoutError("lockout error"); verifyNoMoreInteractions(mRotateTextViewController); @@ -1746,8 +1767,9 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { setupFingerprintUnlockPossible(false); } - private void fingerprintUnlockIsPossible() { + private void fingerprintUnlockIsPossibleAndAllowed() { setupFingerprintUnlockPossible(true); + when(mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed()).thenReturn(true); } private void setupFingerprintUnlockPossible(boolean possible) { 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 7b59cc284181..08a9f3139d71 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.AnimatorTestRule2 +import androidx.core.animation.AnimatorTestRule 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 = AnimatorTestRule2() + @get:Rule val animatorTestRule = AnimatorTestRule() @Before fun setup() { 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 be3b7234a1a2..aff705f1f3bf 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 @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification import android.testing.AndroidTestingRunner import android.testing.TestableLooper -import androidx.core.animation.AnimatorTestRule2 +import androidx.core.animation.AnimatorTestRule import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager @@ -51,7 +51,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions @TestableLooper.RunWithLooper(setAsMainLooper = true) class NotificationWakeUpCoordinatorTest : SysuiTestCase() { - @get:Rule val animatorTestRule = AnimatorTestRule2() + @get:Rule val animatorTestRule = AnimatorTestRule() private val dumpManager: DumpManager = mock() private val headsUpManager: HeadsUpManager = mock() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java index 30708a7cb2fe..ac66ad9e9c8d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java @@ -97,6 +97,59 @@ public class HighPriorityProviderTest extends SysuiTestCase { } @Test + public void highImportanceConversation() { + // GIVEN notification is high importance and is a people notification + final Notification notification = new Notification.Builder(mContext, "test") + .build(); + final NotificationEntry entry = new NotificationEntryBuilder() + .setNotification(notification) + .setImportance(IMPORTANCE_HIGH) + .build(); + when(mPeopleNotificationIdentifier + .getPeopleNotificationType(entry)) + .thenReturn(TYPE_PERSON); + + // THEN it is high priority conversation + assertTrue(mHighPriorityProvider.isHighPriorityConversation(entry)); + } + + @Test + public void lowImportanceConversation() { + // GIVEN notification is high importance and is a people notification + final Notification notification = new Notification.Builder(mContext, "test") + .build(); + final NotificationEntry entry = new NotificationEntryBuilder() + .setNotification(notification) + .setImportance(IMPORTANCE_LOW) + .build(); + when(mPeopleNotificationIdentifier + .getPeopleNotificationType(entry)) + .thenReturn(TYPE_PERSON); + + // THEN it is low priority conversation + assertFalse(mHighPriorityProvider.isHighPriorityConversation(entry)); + } + + @Test + public void highImportanceConversationWhenAnyOfChildIsHighPriority() { + // GIVEN notification is high importance and is a people notification + final NotificationEntry summary = createNotifEntry(false); + final NotificationEntry lowPriorityChild = createNotifEntry(false); + final NotificationEntry highPriorityChild = createNotifEntry(true); + when(mPeopleNotificationIdentifier + .getPeopleNotificationType(summary)) + .thenReturn(TYPE_PERSON); + final GroupEntry groupEntry = new GroupEntryBuilder() + .setParent(GroupEntry.ROOT_ENTRY) + .setSummary(summary) + .setChildren(List.of(lowPriorityChild, highPriorityChild)) + .build(); + + // THEN the groupEntry is high priority conversation since it has a high priority child + assertTrue(mHighPriorityProvider.isHighPriorityConversation(groupEntry)); + } + + @Test public void messagingStyle() { // GIVEN notification is low importance but has messaging style final Notification notification = new Notification.Builder(mContext, "test") diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt index 742fcf5e03c3..55ea31571dfe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt @@ -17,6 +17,9 @@ package com.android.systemui.statusbar.notification.collection.coordinator import android.app.NotificationChannel +import android.app.NotificationManager.IMPORTANCE_DEFAULT +import android.app.NotificationManager.IMPORTANCE_HIGH +import android.app.NotificationManager.IMPORTANCE_LOW import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest @@ -31,10 +34,13 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner +import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl import com.android.systemui.statusbar.notification.collection.render.NodeController import com.android.systemui.statusbar.notification.icon.ConversationIconManager import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.withArgCaptor @@ -55,7 +61,8 @@ import org.mockito.Mockito.`when` as whenever class ConversationCoordinatorTest : SysuiTestCase() { // captured listeners and pluggables: private lateinit var promoter: NotifPromoter - private lateinit var peopleSectioner: NotifSectioner + private lateinit var peopleAlertingSectioner: NotifSectioner + private lateinit var peopleSilentSectioner: NotifSectioner private lateinit var peopleComparator: NotifComparator private lateinit var beforeRenderListListener: OnBeforeRenderListListener @@ -76,6 +83,7 @@ class ConversationCoordinatorTest : SysuiTestCase() { coordinator = ConversationCoordinator( peopleNotificationIdentifier, conversationIconManager, + HighPriorityProvider(peopleNotificationIdentifier, GroupMembershipManagerImpl()), headerController ) whenever(channel.isImportantConversation).thenReturn(true) @@ -90,12 +98,13 @@ class ConversationCoordinatorTest : SysuiTestCase() { verify(pipeline).addOnBeforeRenderListListener(capture()) } - peopleSectioner = coordinator.sectioner - peopleComparator = peopleSectioner.comparator!! + peopleAlertingSectioner = coordinator.peopleAlertingSectioner + peopleSilentSectioner = coordinator.peopleSilentSectioner + peopleComparator = peopleAlertingSectioner.comparator!! entry = NotificationEntryBuilder().setChannel(channel).build() - val section = NotifSection(peopleSectioner, 0) + val section = NotifSection(peopleAlertingSectioner, 0) entryA = NotificationEntryBuilder().setChannel(channel) .setSection(section).setTag("A").build() entryB = NotificationEntryBuilder().setChannel(channel) @@ -129,13 +138,67 @@ class ConversationCoordinatorTest : SysuiTestCase() { } @Test - fun testInPeopleSection() { + fun testInAlertingPeopleSectionWhenTheImportanceIsAtLeastDefault() { + // GIVEN + val alertingEntry = NotificationEntryBuilder().setChannel(channel) + .setImportance(IMPORTANCE_DEFAULT).build() + whenever(peopleNotificationIdentifier.getPeopleNotificationType(alertingEntry)) + .thenReturn(TYPE_PERSON) + + // put alerting people notifications in this section + assertThat(peopleAlertingSectioner.isInSection(alertingEntry)).isTrue() + } + + @Test + fun testInSilentPeopleSectionWhenTheImportanceIsLowerThanDefault() { + // GIVEN + val silentEntry = NotificationEntryBuilder().setChannel(channel) + .setImportance(IMPORTANCE_LOW).build() + whenever(peopleNotificationIdentifier.getPeopleNotificationType(silentEntry)) + .thenReturn(TYPE_PERSON) + + // THEN put silent people notifications in this section + assertThat(peopleSilentSectioner.isInSection(silentEntry)).isTrue() + // People Alerting sectioning happens before the silent one. + // It claims high important conversations and rest of conversations will be considered as silent. + assertThat(peopleAlertingSectioner.isInSection(silentEntry)).isFalse() + } + + @Test + fun testNotInPeopleSection() { + // GIVEN + val entry = NotificationEntryBuilder().setChannel(channel) + .setImportance(IMPORTANCE_LOW).build() + val importantEntry = NotificationEntryBuilder().setChannel(channel) + .setImportance(IMPORTANCE_HIGH).build() whenever(peopleNotificationIdentifier.getPeopleNotificationType(entry)) - .thenReturn(TYPE_PERSON) + .thenReturn(TYPE_NON_PERSON) + whenever(peopleNotificationIdentifier.getPeopleNotificationType(importantEntry)) + .thenReturn(TYPE_NON_PERSON) - // only put people notifications in this section - assertTrue(peopleSectioner.isInSection(entry)) - assertFalse(peopleSectioner.isInSection(NotificationEntryBuilder().build())) + // THEN - only put people notification either silent or alerting + assertThat(peopleSilentSectioner.isInSection(entry)).isFalse() + assertThat(peopleAlertingSectioner.isInSection(importantEntry)).isFalse() + } + + @Test + fun testInAlertingPeopleSectionWhenThereIsAnImportantChild(){ + // GIVEN + val altChildA = NotificationEntryBuilder().setTag("A") + .setImportance(IMPORTANCE_DEFAULT).build() + val altChildB = NotificationEntryBuilder().setTag("B") + .setImportance(IMPORTANCE_LOW).build() + val summary = NotificationEntryBuilder().setId(2) + .setImportance(IMPORTANCE_LOW).setChannel(channel).build() + val groupEntry = GroupEntryBuilder() + .setParent(GroupEntry.ROOT_ENTRY) + .setSummary(summary) + .setChildren(listOf(altChildA, altChildB)) + .build() + whenever(peopleNotificationIdentifier.getPeopleNotificationType(summary)) + .thenReturn(TYPE_PERSON) + // THEN + assertThat(peopleAlertingSectioner.isInSection(groupEntry)).isTrue() } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt index 8109e24a1e52..c2a2a40b7e5d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt @@ -25,6 +25,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.advanceTimeBy import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.NotifPipelineFlags @@ -69,6 +73,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { private val headsUpManager: HeadsUpManager = mock() private val keyguardNotifVisibilityProvider: KeyguardNotificationVisibilityProvider = mock() private val keyguardRepository = FakeKeyguardRepository() + private val keyguardTransitionRepository = FakeKeyguardTransitionRepository() private val notifPipelineFlags: NotifPipelineFlags = mock() private val notifPipeline: NotifPipeline = mock() private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock() @@ -118,6 +123,33 @@ class KeyguardCoordinatorTest : SysuiTestCase() { } @Test + fun unseenFilterStopsMarkingSeenNotifWhenTransitionToAod() { + whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true) + + // GIVEN: Keyguard is not showing, shade is not expanded, and a notification is present + keyguardRepository.setKeyguardShowing(false) + whenever(statusBarStateController.isExpanded).thenReturn(false) + runKeyguardCoordinatorTest { + val fakeEntry = NotificationEntryBuilder().build() + collectionListener.onEntryAdded(fakeEntry) + + // WHEN: The device transitions to AOD + keyguardTransitionRepository.sendTransitionStep( + TransitionStep(to = KeyguardState.AOD, transitionState = TransitionState.STARTED), + ) + testScheduler.runCurrent() + + // WHEN: The shade is expanded + whenever(statusBarStateController.isExpanded).thenReturn(true) + statusBarStateListener.onExpandedChanged(true) + testScheduler.runCurrent() + + // THEN: The notification is still treated as "unseen" and is not filtered out. + assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse() + } + } + + @Test fun unseenFilter_headsUpMarkedAsSeen() { whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true) @@ -373,6 +405,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { headsUpManager, keyguardNotifVisibilityProvider, keyguardRepository, + keyguardTransitionRepository, notifPipelineFlags, testScope.backgroundScope, sectionHeaderVisibilityProvider, 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 d5c0c5564af6..3d1253e2b05d 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 @@ -52,7 +52,6 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga 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; import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; @@ -73,7 +72,6 @@ public class RankingCoordinatorTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock private HighPriorityProvider mHighPriorityProvider; - @Mock private SectionStyleProvider mSectionStyleProvider; @Mock private NotifPipeline mNotifPipeline; @Mock private NodeController mAlertingHeaderController; @Mock private NodeController mSilentNodeController; @@ -100,7 +98,6 @@ public class RankingCoordinatorTest extends SysuiTestCase { mRankingCoordinator = new RankingCoordinator( mStatusBarStateController, mHighPriorityProvider, - mSectionStyleProvider, mAlertingHeaderController, mSilentHeaderController, mSilentNodeController); @@ -108,7 +105,6 @@ public class RankingCoordinatorTest extends SysuiTestCase { mEntry.setRanking(getRankingForUnfilteredNotif().build()); mRankingCoordinator.attach(mNotifPipeline); - verify(mSectionStyleProvider).setMinimizedSections(any()); verify(mNotifPipeline, times(2)).addPreGroupFilter(mNotifFilterCaptor.capture()); mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0); mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt new file mode 100644 index 000000000000..cbb08946a1b0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt @@ -0,0 +1,78 @@ +package com.android.systemui.statusbar.notification.interruption + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.NO_FSI_NOT_IMPORTANT_ENOUGH +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.NO_FSI_SUPPRESSED_BY_DND +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.DecisionImpl +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class NotificationInterruptStateProviderWrapperTest : SysuiTestCase() { + + @Test + fun decisionOfTrue() { + assertTrue(DecisionImpl.of(true).shouldInterrupt) + } + + @Test + fun decisionOfFalse() { + assertFalse(DecisionImpl.of(false).shouldInterrupt) + } + + @Test + fun decisionOfTrueInterned() { + assertEquals(DecisionImpl.of(true), DecisionImpl.of(true)) + } + + @Test + fun decisionOfFalseInterned() { + assertEquals(DecisionImpl.of(false), DecisionImpl.of(false)) + } + + @Test + fun fullScreenIntentDecisionShouldInterrupt() { + makeFsiDecision(FSI_DEVICE_NOT_INTERACTIVE).let { + assertTrue(it.shouldInterrupt) + assertFalse(it.wouldInterruptWithoutDnd) + } + } + + @Test + fun fullScreenIntentDecisionShouldNotInterrupt() { + makeFsiDecision(NO_FSI_NOT_IMPORTANT_ENOUGH).let { + assertFalse(it.shouldInterrupt) + assertFalse(it.wouldInterruptWithoutDnd) + } + } + + @Test + fun fullScreenIntentDecisionWouldInterruptWithoutDnd() { + makeFsiDecision(NO_FSI_SUPPRESSED_ONLY_BY_DND).let { + assertFalse(it.shouldInterrupt) + assertTrue(it.wouldInterruptWithoutDnd) + } + } + + @Test + fun fullScreenIntentDecisionWouldNotInterruptEvenWithoutDnd() { + makeFsiDecision(NO_FSI_SUPPRESSED_BY_DND).let { + assertFalse(it.shouldInterrupt) + assertFalse(it.wouldInterruptWithoutDnd) + } + } + + private fun makeFsiDecision(originalDecision: FullScreenIntentDecision) = + FullScreenIntentDecisionImpl(NotificationEntryBuilder().build(), originalDecision) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 7d022192f935..9186c35e2b47 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -100,7 +100,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { mNotificationTestHelper.setDefaultInflationFlags(FLAG_CONTENT_VIEW_ALL); FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags(); - fakeFeatureFlags.set(Flags.NOTIFICATION_ANIMATE_BIG_PICTURE, true); fakeFeatureFlags.set(Flags.SENSITIVE_REVEAL_ANIM, false); mNotificationTestHelper.setFeatureFlags(fakeFeatureFlags); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt new file mode 100644 index 000000000000..2cc375b3d0ed --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.notification.shelf.domain.interactor + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class NotificationShelfInteractorTest : SysuiTestCase() { + + private val keyguardRepository = FakeKeyguardRepository() + private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository() + private val underTest = + NotificationShelfInteractor(keyguardRepository, deviceEntryFaceAuthRepository) + + @Test + fun shelfIsNotStatic_whenKeyguardNotShowing() = runTest { + val shelfStatic by collectLastValue(underTest.isShelfStatic) + + keyguardRepository.setKeyguardShowing(false) + + assertThat(shelfStatic).isFalse() + } + + @Test + fun shelfIsNotStatic_whenKeyguardShowingAndNotBypass() = runTest { + val shelfStatic by collectLastValue(underTest.isShelfStatic) + + keyguardRepository.setKeyguardShowing(true) + deviceEntryFaceAuthRepository.isBypassEnabled.value = false + + assertThat(shelfStatic).isFalse() + } + + @Test + fun shelfIsStatic_whenBypass() = runTest { + val shelfStatic by collectLastValue(underTest.isShelfStatic) + + keyguardRepository.setKeyguardShowing(true) + deviceEntryFaceAuthRepository.isBypassEnabled.value = true + + assertThat(shelfStatic).isTrue() + } + + @Test + fun shelfOnKeyguard_whenKeyguardShowing() = runTest { + val onKeyguard by collectLastValue(underTest.isShowingOnKeyguard) + + keyguardRepository.setKeyguardShowing(true) + + assertThat(onKeyguard).isTrue() + } + + @Test + fun shelfNotOnKeyguard_whenKeyguardNotShowing() = runTest { + val onKeyguard by collectLastValue(underTest.isShowingOnKeyguard) + + keyguardRepository.setKeyguardShowing(false) + + assertThat(onKeyguard).isFalse() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt new file mode 100644 index 000000000000..439edaf3faaf --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt @@ -0,0 +1,90 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.notification.shelf.ui.viewmodel + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class NotificationShelfViewModelTest : SysuiTestCase() { + + private val keyguardRepository = FakeKeyguardRepository() + private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository() + private val interactor = + NotificationShelfInteractor(keyguardRepository, deviceEntryFaceAuthRepository) + private val underTest = NotificationShelfViewModel(interactor) + + @Test + fun canModifyColorOfNotifications_whenKeyguardNotShowing() = runTest { + val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications) + + keyguardRepository.setKeyguardShowing(false) + + assertThat(canModifyNotifColor).isTrue() + } + + @Test + fun canModifyColorOfNotifications_whenKeyguardShowingAndNotBypass() = runTest { + val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications) + + keyguardRepository.setKeyguardShowing(true) + deviceEntryFaceAuthRepository.isBypassEnabled.value = false + + assertThat(canModifyNotifColor).isTrue() + } + + @Test + fun cannotModifyColorOfNotifications_whenBypass() = runTest { + val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications) + + keyguardRepository.setKeyguardShowing(true) + deviceEntryFaceAuthRepository.isBypassEnabled.value = true + + assertThat(canModifyNotifColor).isFalse() + } + + @Test + fun isClickable_whenKeyguardShowing() = runTest { + val isClickable by collectLastValue(underTest.isClickable) + + keyguardRepository.setKeyguardShowing(true) + + assertThat(isClickable).isTrue() + } + + @Test + fun isNotClickable_whenKeyguardNotShowing() = runTest { + val isClickable by collectLastValue(underTest.isClickable) + + keyguardRepository.setKeyguardShowing(false) + + assertThat(isClickable).isFalse() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt index e6f10cdafe03..5279740a8702 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt @@ -23,6 +23,7 @@ import android.view.View.VISIBLE import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.statusbar.LockscreenShadeTransitionController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController @@ -48,6 +49,7 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController @Mock private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController + @Mock private lateinit var mediaDataManager: MediaDataManager @Mock private lateinit var stackLayout: NotificationStackScrollLayout private val testableResources = mContext.orCreateTestableResources @@ -67,7 +69,9 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { NotificationStackSizeCalculator( statusBarStateController = sysuiStatusBarStateController, lockscreenShadeTransitionController = lockscreenShadeTransitionController, - testableResources.resources) + mediaDataManager = mediaDataManager, + testableResources.resources + ) } @Test @@ -76,7 +80,11 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { val maxNotifications = computeMaxKeyguardNotifications( - rows, spaceForNotifications = 0f, spaceForShelf = 0f, shelfHeight = 0f) + rows, + spaceForNotifications = 0f, + spaceForShelf = 0f, + shelfHeight = 0f + ) assertThat(maxNotifications).isEqualTo(0) } @@ -91,7 +99,8 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { rows, spaceForNotifications = Float.MAX_VALUE, spaceForShelf = Float.MAX_VALUE, - shelfHeight) + shelfHeight + ) assertThat(maxNotifications).isEqualTo(numberOfRows) } @@ -111,6 +120,28 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { } @Test + fun computeMaxKeyguardNotifications_onLockscreenSpaceForMinHeightButNotIntrinsicHeight_returnsOne() { + setGapHeight(0f) + // No divider height since we're testing one element where index = 0 + + whenever(sysuiStatusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + whenever(lockscreenShadeTransitionController.fractionToShade).thenReturn(0f) + + val row = createMockRow(10f, isSticky = true) + whenever(row.getMinHeight(any())).thenReturn(5) + + val maxNotifications = + computeMaxKeyguardNotifications( + listOf(row), + /* spaceForNotifications= */ 5f, + /* spaceForShelf= */ 0f, + /* shelfHeight= */ 0f + ) + + assertThat(maxNotifications).isEqualTo(1) + } + + @Test fun computeMaxKeyguardNotifications_spaceForTwo_returnsTwo() { setGapHeight(gapHeight) val shelfHeight = shelfHeight + dividerHeight @@ -126,7 +157,11 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { val maxNotifications = computeMaxKeyguardNotifications( - rows, spaceForNotifications + 1, spaceForShelf, shelfHeight) + rows, + spaceForNotifications + 1, + spaceForShelf, + shelfHeight + ) assertThat(maxNotifications).isEqualTo(2) } @@ -136,24 +171,23 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { // Each row in separate section. setGapHeight(gapHeight) - val spaceForNotifications = + val notifSpace = listOf( rowHeight, dividerHeight + gapHeight + rowHeight, ) .sum() - val spaceForShelf = dividerHeight + gapHeight + shelfHeight - val spaceUsed = spaceForNotifications + spaceForShelf + val shelfSpace = dividerHeight + gapHeight + shelfHeight + val spaceUsed = notifSpace + shelfSpace val rows = listOf(createMockRow(rowHeight), createMockRow(rowHeight), createMockRow(rowHeight)) val maxNotifications = - computeMaxKeyguardNotifications(rows, spaceForNotifications, spaceForShelf, shelfHeight) + computeMaxKeyguardNotifications(rows, notifSpace, shelfSpace, shelfHeight) assertThat(maxNotifications).isEqualTo(2) - val height = - sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight) + val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight) assertThat(height).isEqualTo(spaceUsed) } @@ -170,11 +204,14 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { // test that we only use space required val maxNotifications = computeMaxKeyguardNotifications( - rows, spaceForNotifications + 1, spaceForShelf, shelfHeight) + rows, + spaceForNotifications + 1, + spaceForShelf, + shelfHeight + ) assertThat(maxNotifications).isEqualTo(1) - val height = - sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight) + val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight) assertThat(height).isEqualTo(spaceUsed) } @@ -200,60 +237,101 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { } @Test - fun spaceNeeded_onLockscreen_usesMinHeight() { + fun getSpaceNeeded_onLockscreenEnoughSpaceStickyHun_intrinsicHeight() { setGapHeight(0f) // No divider height since we're testing one element where index = 0 - val expandableView = createMockRow(rowHeight) + val row = createMockRow(10f, isSticky = true) + whenever(row.getMinHeight(any())).thenReturn(5) + + val space = + sizeCalculator.getSpaceNeeded( + row, + visibleIndex = 0, + previousView = null, + stack = stackLayout, + onLockscreen = true + ) + assertThat(space.whenEnoughSpace).isEqualTo(10f) + } + + @Test + fun getSpaceNeeded_onLockscreenEnoughSpaceNotStickyHun_minHeight() { + setGapHeight(0f) + // No divider height since we're testing one element where index = 0 + + val row = createMockRow(rowHeight) + whenever(row.heightWithoutLockscreenConstraints).thenReturn(10) + whenever(row.getMinHeight(any())).thenReturn(5) + + val space = + sizeCalculator.getSpaceNeeded( + row, + visibleIndex = 0, + previousView = null, + stack = stackLayout, + onLockscreen = true + ) + assertThat(space.whenEnoughSpace).isEqualTo(5) + } + + @Test + fun getSpaceNeeded_onLockscreenSavingSpaceStickyHun_minHeight() { + setGapHeight(0f) + // No divider height since we're testing one element where index = 0 + + val expandableView = createMockRow(10f, isSticky = true) whenever(expandableView.getMinHeight(any())).thenReturn(5) - whenever(expandableView.intrinsicHeight).thenReturn(10) val space = - sizeCalculator.spaceNeeded( + sizeCalculator.getSpaceNeeded( expandableView, visibleIndex = 0, previousView = null, stack = stackLayout, - onLockscreen = true) - assertThat(space).isEqualTo(5) + onLockscreen = true + ) + assertThat(space.whenSavingSpace).isEqualTo(5) } @Test - fun spaceNeeded_fsiHunOnLockscreen_usesIntrinsicHeight() { + fun getSpaceNeeded_onLockscreenSavingSpaceNotStickyHun_minHeight() { setGapHeight(0f) // No divider height since we're testing one element where index = 0 - val expandableView = createMockStickyRow(rowHeight) + val expandableView = createMockRow(rowHeight) whenever(expandableView.getMinHeight(any())).thenReturn(5) whenever(expandableView.intrinsicHeight).thenReturn(10) val space = - sizeCalculator.spaceNeeded( - expandableView, - visibleIndex = 0, - previousView = null, - stack = stackLayout, - onLockscreen = true) - assertThat(space).isEqualTo(10) + sizeCalculator.getSpaceNeeded( + expandableView, + visibleIndex = 0, + previousView = null, + stack = stackLayout, + onLockscreen = true + ) + assertThat(space.whenSavingSpace).isEqualTo(5) } @Test - fun spaceNeeded_notOnLockscreen_usesIntrinsicHeight() { + fun getSpaceNeeded_notOnLockscreen_intrinsicHeight() { setGapHeight(0f) // No divider height since we're testing one element where index = 0 val expandableView = createMockRow(rowHeight) - whenever(expandableView.getMinHeight(any())).thenReturn(5) - whenever(expandableView.intrinsicHeight).thenReturn(10) + whenever(expandableView.getMinHeight(any())).thenReturn(1) val space = - sizeCalculator.spaceNeeded( + sizeCalculator.getSpaceNeeded( expandableView, visibleIndex = 0, previousView = null, stack = stackLayout, - onLockscreen = false) - assertThat(space).isEqualTo(10) + onLockscreen = false + ) + assertThat(space.whenEnoughSpace).isEqualTo(rowHeight) + assertThat(space.whenSavingSpace).isEqualTo(rowHeight) } private fun computeMaxKeyguardNotifications( @@ -264,7 +342,11 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { ): Int { setupChildren(rows) return sizeCalculator.computeMaxKeyguardNotifications( - stackLayout, spaceForNotifications, spaceForShelf, shelfHeight) + stackLayout, + spaceForNotifications, + spaceForShelf, + shelfHeight + ) } private fun setupChildren(children: List<ExpandableView>) { @@ -280,30 +362,13 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { private fun createMockRow( height: Float = rowHeight, + isSticky: Boolean = false, isRemoved: Boolean = false, - visibility: Int = VISIBLE - ): ExpandableNotificationRow { - val row = mock(ExpandableNotificationRow::class.java) - val entry = mock(NotificationEntry::class.java) - val sbn = mock(StatusBarNotification::class.java) - whenever(entry.sbn).thenReturn(sbn) - whenever(row.entry).thenReturn(entry) - whenever(row.isRemoved).thenReturn(isRemoved) - whenever(row.visibility).thenReturn(visibility) - whenever(row.getMinHeight(any())).thenReturn(height.toInt()) - whenever(row.intrinsicHeight).thenReturn(height.toInt()) - return row - } - - private fun createMockStickyRow( - height: Float = rowHeight, - isRemoved: Boolean = false, - visibility: Int = VISIBLE + visibility: Int = VISIBLE, ): ExpandableNotificationRow { val row = mock(ExpandableNotificationRow::class.java) val entry = mock(NotificationEntry::class.java) - whenever(entry.isStickyAndNotDemoted).thenReturn(true) - + whenever(entry.isStickyAndNotDemoted).thenReturn(isSticky) val sbn = mock(StatusBarNotification::class.java) whenever(entry.sbn).thenReturn(sbn) whenever(row.entry).thenReturn(entry) @@ -311,6 +376,7 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() { whenever(row.visibility).thenReturn(visibility) whenever(row.getMinHeight(any())).thenReturn(height.toInt()) whenever(row.intrinsicHeight).thenReturn(height.toInt()) + whenever(row.heightWithoutLockscreenConstraints).thenReturn(height.toInt()) return row } 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 32f0adfa1954..63320693831c 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 @@ -133,6 +133,7 @@ import com.android.systemui.shade.QuickSettingsController; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeControllerImpl; import com.android.systemui.shade.ShadeExpansionStateManager; +import com.android.systemui.shade.ShadeLogger; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; @@ -221,6 +222,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private NotificationListContainer mNotificationListContainer; @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationPanelViewController mNotificationPanelViewController; + @Mock private ShadeLogger mShadeLogger; @Mock private NotificationPanelView mNotificationPanelView; @Mock private QuickSettingsController mQuickSettingsController; @Mock private IStatusBarService mBarService; @@ -469,6 +471,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mKeyguardViewMediator, new DisplayMetrics(), mMetricsLogger, + mShadeLogger, mUiBgExecutor, mNotificationMediaManager, mLockscreenUserManager, @@ -1275,12 +1278,13 @@ public class CentralSurfacesImplTest extends SysuiTestCase { new Intent(), /* onlyProvisioned = */false, /* dismissShade = */false); - verify(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any(Runnable.class)); ArgumentCaptor<OnDismissAction> onDismissActionCaptor = ArgumentCaptor.forClass(OnDismissAction.class); verify(mStatusBarKeyguardViewManager) - .dismissWithAction(onDismissActionCaptor.capture(), any(Runnable.class), eq(true)); + .dismissWithAction(onDismissActionCaptor.capture(), any(Runnable.class), eq(true), + eq(null)); assertThat(onDismissActionCaptor.getValue().onDismiss()).isFalse(); + verify(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any(Runnable.class)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java index eb0b9b3a3fb1..760a90b4d59a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java @@ -54,6 +54,7 @@ import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.policy.BatteryController; @@ -120,6 +121,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { @Mock private CommandQueue mCommandQueue; @Mock private KeyguardLogger mLogger; + @Mock private NotificationMediaManager mNotificationMediaManager; + private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider; private KeyguardStatusBarView mKeyguardStatusBarView; private KeyguardStatusBarViewController mController; @@ -167,7 +170,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { mSecureSettings, mCommandQueue, mFakeExecutor, - mLogger + mLogger, + mNotificationMediaManager ); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt index a2828d33375b..1cc0bd3cb36c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt @@ -25,7 +25,6 @@ import android.testing.AndroidTestingRunner import android.view.IWindowManager import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.DumpManager import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock @@ -52,7 +51,6 @@ class LetterboxBackgroundProviderTest : SysuiTestCase() { @get:Rule var expect: Expect = Expect.create() @Mock private lateinit var windowManager: IWindowManager - @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var wallpaperManager: WallpaperManager private lateinit var provider: LetterboxBackgroundProvider @@ -65,8 +63,7 @@ class LetterboxBackgroundProviderTest : SysuiTestCase() { setUpWallpaperManager() provider = - LetterboxBackgroundProvider( - windowManager, fakeExecutor, dumpManager, wallpaperManager, mainHandler) + LetterboxBackgroundProvider(windowManager, fakeExecutor, wallpaperManager, mainHandler) } private fun setUpWallpaperManager() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java index 6c0f6c2f65a5..07ffd112300b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java @@ -14,6 +14,8 @@ package com.android.systemui.statusbar.phone; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -44,6 +46,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.concurrent.atomic.AtomicBoolean; + @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest @@ -109,4 +113,31 @@ public class SystemUIDialogTest extends SysuiTestCase { dialog.dismiss(); assertFalse(dialog.isShowing()); } + + @Test public void startAndStopAreCalled() { + AtomicBoolean calledStart = new AtomicBoolean(false); + AtomicBoolean calledStop = new AtomicBoolean(false); + SystemUIDialog dialog = new SystemUIDialog(mContext) { + @Override + protected void start() { + calledStart.set(true); + } + + @Override + protected void stop() { + calledStop.set(true); + } + }; + + assertThat(calledStart.get()).isFalse(); + assertThat(calledStop.get()).isFalse(); + + dialog.show(); + assertThat(calledStart.get()).isTrue(); + assertThat(calledStop.get()).isFalse(); + + dialog.dismiss(); + assertThat(calledStart.get()).isTrue(); + assertThat(calledStop.get()).isTrue(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt index 746c92e485b7..02c459b11d07 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt @@ -16,12 +16,10 @@ package com.android.systemui.statusbar.phone -import android.animation.Animator import android.os.Handler import android.os.PowerManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper -import android.view.View import androidx.test.filters.SmallTest import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.SysuiTestCase @@ -39,10 +37,8 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock -import org.mockito.Mockito import org.mockito.Mockito.anyLong import org.mockito.Mockito.never -import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` @@ -111,27 +107,6 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { controller.onStartedWakingUp() } - @Test - fun testAnimClearsEndListener() { - val keyguardView = View(context) - val animator = spy(keyguardView.animate()) - val keyguardSpy = spy(keyguardView) - Mockito.`when`(keyguardSpy.animate()).thenReturn(animator) - val listener = ArgumentCaptor.forClass(Animator.AnimatorListener::class.java) - val endAction = ArgumentCaptor.forClass(Runnable::class.java) - controller.animateInKeyguard(keyguardSpy, Runnable {}) - Mockito.verify(animator).setListener(listener.capture()) - Mockito.verify(animator).withEndAction(endAction.capture()) - - // Verify that the listener is cleared if we cancel it. - listener.value.onAnimationCancel(null) - Mockito.verify(animator).setListener(null) - - // Verify that the listener is also cleared if the end action is triggered. - endAction.value.run() - verify(animator, times(2)).setListener(null) - } - /** * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal * animation to start. If the device is woken up during the screen off, we should *never* do diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt index 44fbd5b99894..6306a36d9730 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository +import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel @@ -29,6 +30,7 @@ class FakeMobileConnectionRepository( override val subId: Int, override val tableLogBuffer: TableLogBuffer, ) : MobileConnectionRepository { + override val carrierId = MutableStateFlow(UNKNOWN_CARRIER_ID) override val isEmergencyOnly = MutableStateFlow(false) override val isRoaming = MutableStateFlow(false) override val operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt index f9c72d523673..3591c1740329 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt @@ -67,6 +67,8 @@ class FakeMobileConnectionsRepository( override val mobileIsDefault = MutableStateFlow(false) + override val hasCarrierMergedConnection = MutableStateFlow(false) + override val defaultConnectionIsValidated = MutableStateFlow(false) private val subIdRepos = mutableMapOf<Int, MobileConnectionRepository>() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt index f2bb66a501ec..423c47661fa3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt @@ -593,7 +593,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() { val realRepo = MobileConnectionRepositoryImpl( - context, SUB_ID, defaultNetworkName = NetworkNameModel.Default("default"), networkNameSeparator = SEP, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index 934e1c64c6da..d1df6e3c2072 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -42,6 +42,7 @@ import android.telephony.TelephonyManager.DATA_SUSPENDED import android.telephony.TelephonyManager.DATA_UNKNOWN import android.telephony.TelephonyManager.ERI_OFF import android.telephony.TelephonyManager.ERI_ON +import android.telephony.TelephonyManager.EXTRA_CARRIER_ID import android.telephony.TelephonyManager.EXTRA_PLMN import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN import android.telephony.TelephonyManager.EXTRA_SHOW_SPN @@ -116,7 +117,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { underTest = MobileConnectionRepositoryImpl( - context, SUB_1_ID, DEFAULT_NAME, SEP, @@ -359,6 +359,36 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { } @Test + fun carrierId_initialValueCaptured() = + testScope.runTest { + whenever(telephonyManager.simCarrierId).thenReturn(1234) + + var latest: Int? = null + val job = underTest.carrierId.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(1234) + + job.cancel() + } + + @Test + fun carrierId_updatesOnBroadcast() = + testScope.runTest { + whenever(telephonyManager.simCarrierId).thenReturn(1234) + + var latest: Int? = null + val job = underTest.carrierId.onEach { latest = it }.launchIn(this) + + fakeBroadcastDispatcher.registeredReceivers.forEach { receiver -> + receiver.onReceive(context, carrierIdIntent(carrierId = 4321)) + } + + assertThat(latest).isEqualTo(4321) + + job.cancel() + } + + @Test fun carrierNetworkChange() = testScope.runTest { var latest: Boolean? = null @@ -796,6 +826,15 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager) } + private fun carrierIdIntent( + subId: Int = SUB_1_ID, + carrierId: Int, + ): Intent = + Intent(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED).apply { + putExtra(EXTRA_SUBSCRIPTION_ID, subId) + putExtra(EXTRA_CARRIER_ID, carrierId) + } + private fun spnIntent( subId: Int = SUB_1_ID, showSpn: Boolean = true, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt index 9da9ff72d380..4f15aed00230 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt @@ -117,7 +117,6 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() { underTest = MobileConnectionRepositoryImpl( - context, SUB_1_ID, DEFAULT_NAME, SEP, 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 ddff17aef2de..7cc59b67414b 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 @@ -68,6 +68,7 @@ import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.yield import org.junit.After import org.junit.Assert.assertThrows import org.junit.Assert.assertTrue @@ -155,7 +156,6 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { connectionFactory = MobileConnectionRepositoryImpl.Factory( fakeBroadcastDispatcher, - context = context, telephonyManager = telephonyManager, bgDispatcher = IMMEDIATE, logger = logger, @@ -767,9 +767,66 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { job.cancel() } + @Test + fun mobileIsDefault_carrierMergedViaMobile_isDefault() = + runBlocking(IMMEDIATE) { + val carrierMergedInfo = + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } + val caps = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(carrierMergedInfo) + } + + var latest: Boolean? = null + val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + + assertThat(latest).isTrue() + + job.cancel() + } + + @Test + fun mobileIsDefault_wifiDefault_mobileNotDefault() = + runBlocking(IMMEDIATE) { + val caps = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + } + + var latest: Boolean? = null + val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + + assertThat(latest).isFalse() + + job.cancel() + } + + @Test + fun mobileIsDefault_ethernetDefault_mobileNotDefault() = + runBlocking(IMMEDIATE) { + val caps = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true) + } + + var latest: Boolean? = null + val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + + assertThat(latest).isFalse() + + job.cancel() + } + /** Regression test for b/272586234. */ @Test - fun mobileIsDefault_carrierMergedViaWifi_isDefault() = + fun hasCarrierMergedConnection_carrierMergedViaWifi_isTrue() = runBlocking(IMMEDIATE) { val carrierMergedInfo = mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } @@ -780,9 +837,10 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { } var latest: Boolean? = null - val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this) getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + yield() assertThat(latest).isTrue() @@ -790,7 +848,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { } @Test - fun mobileIsDefault_carrierMergedViaMobile_isDefault() = + fun hasCarrierMergedConnection_carrierMergedViaMobile_isTrue() = runBlocking(IMMEDIATE) { val carrierMergedInfo = mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } @@ -801,9 +859,10 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { } var latest: Boolean? = null - val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this) getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + yield() assertThat(latest).isTrue() @@ -812,7 +871,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { /** Regression test for b/272586234. */ @Test - fun mobileIsDefault_carrierMergedViaWifiWithVcnTransport_isDefault() = + fun hasCarrierMergedConnection_carrierMergedViaWifiWithVcnTransport_isTrue() = runBlocking(IMMEDIATE) { val carrierMergedInfo = mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } @@ -823,9 +882,10 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { } var latest: Boolean? = null - val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this) getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + yield() assertThat(latest).isTrue() @@ -833,7 +893,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { } @Test - fun mobileIsDefault_carrierMergedViaMobileWithVcnTransport_isDefault() = + fun hasCarrierMergedConnection_carrierMergedViaMobileWithVcnTransport_isTrue() = runBlocking(IMMEDIATE) { val carrierMergedInfo = mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } @@ -844,9 +904,10 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { } var latest: Boolean? = null - val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this) getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + yield() assertThat(latest).isTrue() @@ -854,37 +915,100 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { } @Test - fun mobileIsDefault_wifiDefault_mobileNotDefault() = + fun hasCarrierMergedConnection_isCarrierMergedViaUnderlyingWifi_isTrue() = runBlocking(IMMEDIATE) { - val caps = + var latest: Boolean? = null + val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this) + + val underlyingNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } + val underlyingWifiCapabilities = mock<NetworkCapabilities>().also { whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(carrierMergedInfo) } + whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingWifiCapabilities) - var latest: Boolean? = null - val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + // WHEN the main capabilities have an underlying carrier merged network via WIFI + // transport and WifiInfo + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) + } - getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + yield() - assertThat(latest).isFalse() + // THEN there's a carrier merged connection + assertThat(latest).isTrue() job.cancel() } @Test - fun mobileIsDefault_ethernetDefault_mobileNotDefault() = + fun hasCarrierMergedConnection_isCarrierMergedViaUnderlyingCellular_isTrue() = runBlocking(IMMEDIATE) { - val caps = + var latest: Boolean? = null + val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this) + + val underlyingCarrierMergedNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } + val underlyingCapabilities = mock<NetworkCapabilities>().also { - whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true) + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo)) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) + .thenReturn(underlyingCapabilities) + + // WHEN the main capabilities have an underlying carrier merged network via CELLULAR + // transport and VcnTransportInfo + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks) + .thenReturn(listOf(underlyingCarrierMergedNetwork)) } + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + yield() + + // THEN there's a carrier merged connection + assertThat(latest).isTrue() + + job.cancel() + } + + /** Regression test for b/272586234. */ + @Test + fun hasCarrierMergedConnection_defaultNotCarrierMerged_butWifiRepoHasCarrierMerged_isTrue() = + runBlocking(IMMEDIATE) { var latest: Boolean? = null - val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this) + // WHEN the default callback isn't carrier merged + val carrierMergedInfo = + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(false) } + val caps = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(carrierMergedInfo) + } getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps) + yield() - assertThat(latest).isFalse() + // BUT the wifi repo has gotten updates that it *is* carrier merged + wifiRepository.setWifiNetwork(WIFI_NETWORK_CM) + yield() + + // THEN hasCarrierMergedConnection is true + assertThat(latest).isTrue() job.cancel() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt index 8d2c5695c7c4..f054422e6524 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt @@ -17,11 +17,11 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor import android.telephony.CellSignalStrength -import com.android.settingslib.SignalIcon import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS +import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import kotlinx.coroutines.flow.MutableStateFlow @@ -42,8 +42,10 @@ class FakeMobileIconInteractor( override val mobileIsDefault = MutableStateFlow(true) - private val _iconGroup = MutableStateFlow<SignalIcon.MobileIconGroup>(TelephonyIcons.THREE_G) - override val networkTypeIconGroup = _iconGroup + override val networkTypeIconGroup = + MutableStateFlow<NetworkTypeIconModel>( + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G) + ) override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo mode")) @@ -73,10 +75,6 @@ class FakeMobileIconInteractor( override val isForceHidden = MutableStateFlow(false) - fun setIconGroup(group: SignalIcon.MobileIconGroup) { - _iconGroup.value = group - } - fun setIsEmergencyOnly(emergency: Boolean) { _isEmergencyOnly.value = emergency } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt index d6fdad417b31..b2bbcfd3d6ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt @@ -49,6 +49,8 @@ class FakeMobileIconsInteractor( FIVE_G_OVERRIDE_KEY to TelephonyIcons.NR_5G, ) + private val interactorCache: MutableMap<Int, FakeMobileIconInteractor> = mutableMapOf() + override val isDefaultConnectionFailed = MutableStateFlow(false) override val filteredSubscriptions = MutableStateFlow<List<SubscriptionModel>>(listOf()) @@ -59,7 +61,6 @@ class FakeMobileIconsInteractor( override val alwaysShowDataRatIcon = MutableStateFlow(false) override val alwaysUseCdmaLevel = MutableStateFlow(false) - override val defaultDataSubId = MutableStateFlow(DEFAULT_DATA_SUB_ID) override val mobileIsDefault = MutableStateFlow(false) @@ -76,7 +77,15 @@ class FakeMobileIconsInteractor( /** Always returns a new fake interactor */ override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor { - return FakeMobileIconInteractor(tableLogBuffer) + return FakeMobileIconInteractor(tableLogBuffer).also { interactorCache[subId] = it } + } + + /** + * Returns the most recently created interactor for the given subId, or null if an interactor + * has never been created for that sub. + */ + fun getInteractorForSubId(subId: Int): FakeMobileIconInteractor? { + return interactorCache[subId] } companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index 2054e8b12eff..8d7f0f6035cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -19,7 +19,8 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor import android.telephony.CellSignalStrength import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import androidx.test.filters.SmallTest -import com.android.settingslib.SignalIcon.MobileIconGroup +import com.android.settingslib.mobile.MobileIconCarrierIdOverrides +import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState @@ -31,18 +32,24 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobile import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.THREE_G +import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.yield +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest class MobileIconInteractorTest : SysuiTestCase() { private lateinit var underTest: MobileIconInteractor @@ -50,29 +57,17 @@ class MobileIconInteractorTest : SysuiTestCase() { private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock()) private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID, mock()) - private val scope = CoroutineScope(IMMEDIATE) + private val testDispatcher = UnconfinedTestDispatcher() + private val testScope = TestScope(testDispatcher) @Before fun setUp() { - underTest = - MobileIconInteractorImpl( - scope, - mobileIconsInteractor.activeDataConnectionHasDataEnabled, - mobileIconsInteractor.alwaysShowDataRatIcon, - mobileIconsInteractor.alwaysUseCdmaLevel, - mobileIconsInteractor.mobileIsDefault, - mobileIconsInteractor.defaultMobileIconMapping, - mobileIconsInteractor.defaultMobileIconGroup, - mobileIconsInteractor.defaultDataSubId, - mobileIconsInteractor.isDefaultConnectionFailed, - mobileIconsInteractor.isForceHidden, - connectionRepository, - ) + underTest = createInteractor() } @Test fun gsm_level_default_unknown() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.isGsm.value = true var latest: Int? = null @@ -85,7 +80,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun gsm_usesGsmLevel() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.isGsm.value = true connectionRepository.primaryLevel.value = GSM_LEVEL connectionRepository.cdmaLevel.value = CDMA_LEVEL @@ -100,7 +95,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun gsm_alwaysShowCdmaTrue_stillUsesGsmLevel() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.isGsm.value = true connectionRepository.primaryLevel.value = GSM_LEVEL connectionRepository.cdmaLevel.value = CDMA_LEVEL @@ -116,7 +111,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun notGsm_level_default_unknown() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.isGsm.value = false var latest: Int? = null @@ -128,7 +123,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun notGsm_alwaysShowCdmaTrue_usesCdmaLevel() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.isGsm.value = false connectionRepository.primaryLevel.value = GSM_LEVEL connectionRepository.cdmaLevel.value = CDMA_LEVEL @@ -144,7 +139,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun notGsm_alwaysShowCdmaFalse_usesPrimaryLevel() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.isGsm.value = false connectionRepository.primaryLevel.value = GSM_LEVEL connectionRepository.cdmaLevel.value = CDMA_LEVEL @@ -160,7 +155,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun numberOfLevels_comesFromRepo() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Int? = null val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this) @@ -175,101 +170,106 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun iconGroup_three_g() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.resolvedNetworkType.value = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G)) - var latest: MobileIconGroup? = null + var latest: NetworkTypeIconModel? = null val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(TelephonyIcons.THREE_G) + assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)) job.cancel() } @Test fun iconGroup_updates_on_change() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.resolvedNetworkType.value = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G)) - var latest: MobileIconGroup? = null + var latest: NetworkTypeIconModel? = null val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) connectionRepository.resolvedNetworkType.value = DefaultNetworkType(mobileMappingsProxy.toIconKey(FOUR_G)) - yield() - assertThat(latest).isEqualTo(TelephonyIcons.FOUR_G) + assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.FOUR_G)) job.cancel() } @Test fun iconGroup_5g_override_type() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.resolvedNetworkType.value = OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE)) - var latest: MobileIconGroup? = null + var latest: NetworkTypeIconModel? = null val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(TelephonyIcons.NR_5G) + assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.NR_5G)) job.cancel() } @Test fun iconGroup_default_if_no_lookup() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.resolvedNetworkType.value = DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN)) - var latest: MobileIconGroup? = null + var latest: NetworkTypeIconModel? = null val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(FakeMobileIconsInteractor.DEFAULT_ICON) + assertThat(latest) + .isEqualTo(NetworkTypeIconModel.DefaultIcon(FakeMobileIconsInteractor.DEFAULT_ICON)) job.cancel() } @Test fun iconGroup_carrierMerged_usesOverride() = - runBlocking(IMMEDIATE) { + testScope.runTest { connectionRepository.resolvedNetworkType.value = CarrierMergedNetworkType - var latest: MobileIconGroup? = null + var latest: NetworkTypeIconModel? = null val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(CarrierMergedNetworkType.iconGroupOverride) + assertThat(latest) + .isEqualTo( + NetworkTypeIconModel.DefaultIcon(CarrierMergedNetworkType.iconGroupOverride) + ) job.cancel() } @Test - fun `icon group - checks default data`() = - runBlocking(IMMEDIATE) { - mobileIconsInteractor.defaultDataSubId.value = SUB_1_ID + fun overrideIcon_usesCarrierIdOverride() = + testScope.runTest { + val overrides = + mock<MobileIconCarrierIdOverrides>().also { + whenever(it.carrierIdEntryExists(anyInt())).thenReturn(true) + whenever(it.getOverrideFor(anyInt(), anyString(), any())).thenReturn(1234) + } + + underTest = createInteractor(overrides) + connectionRepository.resolvedNetworkType.value = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G)) - var latest: MobileIconGroup? = null + var latest: NetworkTypeIconModel? = null val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(TelephonyIcons.THREE_G) - - // Default data sub id changes to something else - mobileIconsInteractor.defaultDataSubId.value = 123 - yield() - - assertThat(latest).isEqualTo(TelephonyIcons.NOT_DEFAULT_DATA) + assertThat(latest) + .isEqualTo(NetworkTypeIconModel.OverriddenIcon(TelephonyIcons.THREE_G, 1234)) job.cancel() } @Test fun alwaysShowDataRatIcon_matchesParent() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.alwaysShowDataRatIcon.onEach { latest = it }.launchIn(this) @@ -284,7 +284,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun alwaysUseCdmaLevel_matchesParent() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.alwaysUseCdmaLevel.onEach { latest = it }.launchIn(this) @@ -299,7 +299,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun test_isDefaultDataEnabled_matchesParent() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.isDefaultDataEnabled.onEach { latest = it }.launchIn(this) @@ -314,7 +314,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun test_isDefaultConnectionFailed_matchedParent() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isDefaultConnectionFailed.launchIn(this) mobileIconsInteractor.isDefaultConnectionFailed.value = false @@ -328,12 +328,11 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun dataState_connected() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this) connectionRepository.dataConnectionState.value = DataConnectionState.Connected - yield() assertThat(latest).isTrue() @@ -342,7 +341,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun dataState_notConnected() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this) @@ -355,7 +354,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun `isInService - uses repository value`() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.isInService.onEach { latest = it }.launchIn(this) @@ -372,19 +371,17 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun `roaming - is gsm - uses connection model`() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.isRoaming.onEach { latest = it }.launchIn(this) connectionRepository.cdmaRoaming.value = true connectionRepository.isGsm.value = true connectionRepository.isRoaming.value = false - yield() assertThat(latest).isFalse() connectionRepository.isRoaming.value = true - yield() assertThat(latest).isTrue() @@ -393,21 +390,19 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun `roaming - is cdma - uses cdma roaming bit`() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.isRoaming.onEach { latest = it }.launchIn(this) connectionRepository.cdmaRoaming.value = false connectionRepository.isGsm.value = false connectionRepository.isRoaming.value = true - yield() assertThat(latest).isFalse() connectionRepository.cdmaRoaming.value = true connectionRepository.isGsm.value = false connectionRepository.isRoaming.value = false - yield() assertThat(latest).isTrue() @@ -416,7 +411,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun `roaming - false while carrierNetworkChangeActive`() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.isRoaming.onEach { latest = it }.launchIn(this) @@ -424,13 +419,11 @@ class MobileIconInteractorTest : SysuiTestCase() { connectionRepository.isGsm.value = false connectionRepository.isRoaming.value = true connectionRepository.carrierNetworkChangeActive.value = true - yield() assertThat(latest).isFalse() connectionRepository.cdmaRoaming.value = true connectionRepository.isGsm.value = true - yield() assertThat(latest).isFalse() @@ -439,7 +432,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun `network name - uses operatorAlphaShot when non null and repo is default`() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: NetworkNameModel? = null val job = underTest.networkName.onEach { latest = it }.launchIn(this) @@ -448,20 +441,17 @@ class MobileIconInteractorTest : SysuiTestCase() { // Default network name, operator name is non-null, uses the operator name connectionRepository.networkName.value = DEFAULT_NAME connectionRepository.operatorAlphaShort.value = testOperatorName - yield() assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName)) // Default network name, operator name is null, uses the default connectionRepository.operatorAlphaShort.value = null - yield() assertThat(latest).isEqualTo(DEFAULT_NAME) // Derived network name, operator name non-null, uses the derived name connectionRepository.networkName.value = DERIVED_NAME connectionRepository.operatorAlphaShort.value = testOperatorName - yield() assertThat(latest).isEqualTo(DERIVED_NAME) @@ -470,7 +460,7 @@ class MobileIconInteractorTest : SysuiTestCase() { @Test fun isForceHidden_matchesParent() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: Boolean? = null val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this) @@ -483,9 +473,25 @@ class MobileIconInteractorTest : SysuiTestCase() { job.cancel() } - companion object { - private val IMMEDIATE = Dispatchers.Main.immediate + private fun createInteractor( + overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl() + ) = + MobileIconInteractorImpl( + testScope.backgroundScope, + mobileIconsInteractor.activeDataConnectionHasDataEnabled, + mobileIconsInteractor.alwaysShowDataRatIcon, + mobileIconsInteractor.alwaysUseCdmaLevel, + mobileIconsInteractor.mobileIsDefault, + mobileIconsInteractor.defaultMobileIconMapping, + mobileIconsInteractor.defaultMobileIconGroup, + mobileIconsInteractor.isDefaultConnectionFailed, + mobileIconsInteractor.isForceHidden, + connectionRepository, + context, + overrides, + ) + companion object { private const val GSM_LEVEL = 1 private const val CDMA_LEVEL = 2 diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index 898e89770394..dc683868f727 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -88,6 +88,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { connectivityRepository, userSetupRepository, testScope.backgroundScope, + context, ) } @@ -455,20 +456,63 @@ class MobileIconsInteractorTest : SysuiTestCase() { } @Test - fun mobileIsDefault_usesRepoValue() = + fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() = + testScope.runTest { + var latest: Boolean? = null + val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + + connectionsRepository.mobileIsDefault.value = false + connectionsRepository.hasCarrierMergedConnection.value = false + + assertThat(latest).isFalse() + + job.cancel() + } + + @Test + fun mobileIsDefault_mobileTrueAndCarrierMergedFalse_true() = testScope.runTest { var latest: Boolean? = null val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) connectionsRepository.mobileIsDefault.value = true + connectionsRepository.hasCarrierMergedConnection.value = false + assertThat(latest).isTrue() + job.cancel() + } + + /** Regression test for b/272586234. */ + @Test + fun mobileIsDefault_mobileFalseAndCarrierMergedTrue_true() = + testScope.runTest { + var latest: Boolean? = null + val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) + connectionsRepository.mobileIsDefault.value = false - assertThat(latest).isFalse() + connectionsRepository.hasCarrierMergedConnection.value = true + + assertThat(latest).isTrue() + + job.cancel() + } + + @Test + fun mobileIsDefault_updatesWhenRepoUpdates() = + testScope.runTest { + var latest: Boolean? = null + val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this) connectionsRepository.mobileIsDefault.value = true assertThat(latest).isTrue() + connectionsRepository.mobileIsDefault.value = false + assertThat(latest).isFalse() + + connectionsRepository.hasCarrierMergedConnection.value = true + assertThat(latest).isTrue() + job.cancel() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt index a6d915243f60..e99be864e73f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt @@ -24,6 +24,7 @@ import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor +import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants @@ -71,9 +72,9 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() { setLevel(1) setIsDefaultDataEnabled(true) setIsFailedConnection(false) - setIconGroup(TelephonyIcons.THREE_G) setIsEmergencyOnly(false) setNumberOfLevels(4) + networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G) isDataConnected.value = true } commonImpl = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt index 1593e5c735a5..297cb9d691ba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt @@ -28,6 +28,7 @@ import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor +import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel @@ -77,9 +78,9 @@ class MobileIconViewModelTest : SysuiTestCase() { setLevel(1) setIsDefaultDataEnabled(true) setIsFailedConnection(false) - setIconGroup(THREE_G) setIsEmergencyOnly(false) setNumberOfLevels(4) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) isDataConnected.value = true } createAndSetViewModel() @@ -178,15 +179,71 @@ class MobileIconViewModelTest : SysuiTestCase() { } @Test - fun iconId_cutout_whenDefaultDataDisabled() = + fun icon_usesLevelFromInteractor() = + testScope.runTest { + var latest: SignalIconModel? = null + val job = underTest.icon.onEach { latest = it }.launchIn(this) + + interactor.level.value = 3 + assertThat(latest!!.level).isEqualTo(3) + + interactor.level.value = 1 + assertThat(latest!!.level).isEqualTo(1) + + job.cancel() + } + + @Test + fun icon_usesNumberOfLevelsFromInteractor() = + testScope.runTest { + var latest: SignalIconModel? = null + val job = underTest.icon.onEach { latest = it }.launchIn(this) + + interactor.numberOfLevels.value = 5 + assertThat(latest!!.numberOfLevels).isEqualTo(5) + + interactor.numberOfLevels.value = 2 + assertThat(latest!!.numberOfLevels).isEqualTo(2) + + job.cancel() + } + + @Test + fun icon_defaultDataDisabled_showExclamationTrue() = testScope.runTest { interactor.setIsDefaultDataEnabled(false) var latest: SignalIconModel? = null val job = underTest.icon.onEach { latest = it }.launchIn(this) - val expected = defaultSignal(level = 1, connected = false) - assertThat(latest).isEqualTo(expected) + assertThat(latest!!.showExclamationMark).isTrue() + + job.cancel() + } + + @Test + fun icon_defaultConnectionFailed_showExclamationTrue() = + testScope.runTest { + interactor.isDefaultConnectionFailed.value = true + + var latest: SignalIconModel? = null + val job = underTest.icon.onEach { latest = it }.launchIn(this) + + assertThat(latest!!.showExclamationMark).isTrue() + + job.cancel() + } + + @Test + fun icon_enabledAndNotFailed_showExclamationFalse() = + testScope.runTest { + interactor.setIsDefaultDataEnabled(true) + interactor.isDefaultConnectionFailed.value = false + + var latest: SignalIconModel? = null + val job = underTest.icon.onEach { latest = it }.launchIn(this) + + assertThat(latest!!.showExclamationMark).isFalse() job.cancel() } @@ -256,7 +313,7 @@ class MobileIconViewModelTest : SysuiTestCase() { THREE_G.dataType, ContentDescription.Resource(THREE_G.dataContentDescription) ) - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) var latest: Icon? = null val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this) @@ -267,10 +324,11 @@ class MobileIconViewModelTest : SysuiTestCase() { } @Test - fun networkType_nullWhenDisabled() = + fun networkType_null_whenDisabled() = testScope.runTest { - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) interactor.setIsDataEnabled(false) + interactor.mobileIsDefault.value = true var latest: Icon? = null val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this) @@ -280,15 +338,21 @@ class MobileIconViewModelTest : SysuiTestCase() { } @Test - fun networkType_nullWhenFailedConnection() = + fun networkTypeIcon_notNull_whenEnabled() = testScope.runTest { - interactor.setIconGroup(THREE_G) + val expected = + Icon.Resource( + THREE_G.dataType, + ContentDescription.Resource(THREE_G.dataContentDescription) + ) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) interactor.setIsDataEnabled(true) - interactor.setIsFailedConnection(true) + interactor.isDataConnected.value = true + interactor.mobileIsDefault.value = true var latest: Icon? = null val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this) - assertThat(latest).isNull() + assertThat(latest).isEqualTo(expected) job.cancel() } @@ -302,11 +366,11 @@ class MobileIconViewModelTest : SysuiTestCase() { ContentDescription.Resource(THREE_G.dataContentDescription) ) - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) var latest: Icon? = null val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this) - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) assertThat(latest).isEqualTo(initial) interactor.isDataConnected.value = false @@ -325,7 +389,7 @@ class MobileIconViewModelTest : SysuiTestCase() { THREE_G.dataType, ContentDescription.Resource(THREE_G.dataContentDescription) ) - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) interactor.setIsDataEnabled(true) var latest: Icon? = null val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this) @@ -343,7 +407,7 @@ class MobileIconViewModelTest : SysuiTestCase() { @Test fun networkType_alwaysShow_shownEvenWhenDisabled() = testScope.runTest { - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) interactor.setIsDataEnabled(false) interactor.alwaysShowDataRatIcon.value = true @@ -363,7 +427,7 @@ class MobileIconViewModelTest : SysuiTestCase() { @Test fun networkType_alwaysShow_shownEvenWhenDisconnected() = testScope.runTest { - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) interactor.isDataConnected.value = false interactor.alwaysShowDataRatIcon.value = true @@ -383,7 +447,7 @@ class MobileIconViewModelTest : SysuiTestCase() { @Test fun networkType_alwaysShow_shownEvenWhenFailedConnection() = testScope.runTest { - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) interactor.setIsFailedConnection(true) interactor.alwaysShowDataRatIcon.value = true @@ -404,7 +468,7 @@ class MobileIconViewModelTest : SysuiTestCase() { fun networkType_alwaysShow_notShownWhenInvalidDataTypeIcon() = testScope.runTest { // The UNKNOWN icon group doesn't have a valid data type icon ID - interactor.setIconGroup(UNKNOWN) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(UNKNOWN) interactor.alwaysShowDataRatIcon.value = true var latest: Icon? = null @@ -418,7 +482,7 @@ class MobileIconViewModelTest : SysuiTestCase() { @Test fun `network type - alwaysShow - shown when not default`() = testScope.runTest { - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) interactor.mobileIsDefault.value = false interactor.alwaysShowDataRatIcon.value = true @@ -438,7 +502,7 @@ class MobileIconViewModelTest : SysuiTestCase() { @Test fun `network type - not shown when not default`() = testScope.runTest { - interactor.setIconGroup(THREE_G) + interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G) interactor.isDataConnected.value = true interactor.mobileIsDefault.value = false @@ -564,16 +628,14 @@ class MobileIconViewModelTest : SysuiTestCase() { companion object { private const val SUB_1_ID = 1 + private const val NUM_LEVELS = 4 /** Convenience constructor for these tests */ - fun defaultSignal( - level: Int = 1, - connected: Boolean = true, - ): SignalIconModel { - return SignalIconModel(level, numberOfLevels = 4, showExclamationMark = !connected) + fun defaultSignal(level: Int = 1): SignalIconModel { + return SignalIconModel(level, NUM_LEVELS, showExclamationMark = false) } fun emptySignal(): SignalIconModel = - SignalIconModel(level = 0, numberOfLevels = 4, showExclamationMark = true) + SignalIconModel(level = 0, numberOfLevels = NUM_LEVELS, showExclamationMark = true) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt index ddb7f4d88d30..f8e1aa94c387 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel import androidx.test.filters.SmallTest +import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags @@ -24,6 +25,7 @@ import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirp import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor +import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy @@ -32,9 +34,8 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnec import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest @@ -69,14 +70,8 @@ class MobileIconsViewModelTest : SysuiTestCase() { FakeConnectivityRepository(), ) - val subscriptionIdsFlow = - interactor.filteredSubscriptions - .map { subs -> subs.map { it.subscriptionId } } - .stateIn(testScope.backgroundScope, SharingStarted.WhileSubscribed(), listOf()) - underTest = MobileIconsViewModel( - subscriptionIdsFlow, logger, verboseLogger, interactor, @@ -90,6 +85,32 @@ class MobileIconsViewModelTest : SysuiTestCase() { } @Test + fun subscriptionIdsFlow_matchesInteractor() = + testScope.runTest { + var latest: List<Int>? = null + val job = underTest.subscriptionIdsFlow.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = + listOf( + SubscriptionModel(subscriptionId = 1, isOpportunistic = false), + ) + assertThat(latest).isEqualTo(listOf(1)) + + interactor.filteredSubscriptions.value = + listOf( + SubscriptionModel(subscriptionId = 2, isOpportunistic = false), + SubscriptionModel(subscriptionId = 5, isOpportunistic = true), + SubscriptionModel(subscriptionId = 7, isOpportunistic = true), + ) + assertThat(latest).isEqualTo(listOf(2, 5, 7)) + + interactor.filteredSubscriptions.value = emptyList() + assertThat(latest).isEmpty() + + job.cancel() + } + + @Test fun `caching - mobile icon view model is reused for same sub id`() = testScope.runTest { val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME) @@ -116,8 +137,179 @@ class MobileIconsViewModelTest : SysuiTestCase() { assertThat(underTest.mobileIconSubIdCache).containsExactly(2, model2.commonImpl) } + @Test + fun firstMobileSubShowingNetworkTypeIcon_noSubs_false() = + testScope.runTest { + var latest: Boolean? = null + val job = + underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = emptyList() + + assertThat(latest).isFalse() + + job.cancel() + } + + @Test + fun firstMobileSubShowingNetworkTypeIcon_oneSub_notShowingRat_false() = + testScope.runTest { + var latest: Boolean? = null + val job = + underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = listOf(SUB_1) + // The unknown icon group doesn't show a RAT + interactor.getInteractorForSubId(1)!!.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN) + + assertThat(latest).isFalse() + + job.cancel() + } + + @Test + fun firstMobileSubShowingNetworkTypeIcon_oneSub_showingRat_true() = + testScope.runTest { + var latest: Boolean? = null + val job = + underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = listOf(SUB_1) + // The 3G icon group will show a RAT + interactor.getInteractorForSubId(1)!!.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G) + + assertThat(latest).isTrue() + + job.cancel() + } + + @Test + fun firstMobileSubShowingNetworkTypeIcon_updatesAsSubUpdates() = + testScope.runTest { + var latest: Boolean? = null + val job = + underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = listOf(SUB_1) + val sub1Interactor = interactor.getInteractorForSubId(1)!! + + sub1Interactor.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G) + assertThat(latest).isTrue() + + sub1Interactor.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN) + assertThat(latest).isFalse() + + sub1Interactor.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.LTE) + assertThat(latest).isTrue() + + job.cancel() + } + + @Test + fun firstMobileSubShowingNetworkTypeIcon_multipleSubs_lastSubNotShowingRat_false() = + testScope.runTest { + var latest: Boolean? = null + val job = + underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2) + interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G) + interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN) + + assertThat(latest).isFalse() + + job.cancel() + } + + @Test + fun firstMobileSubShowingNetworkTypeIcon_multipleSubs_lastSubShowingRat_true() = + testScope.runTest { + var latest: Boolean? = null + val job = + underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2) + interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN) + interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G) + + assertThat(latest).isTrue() + job.cancel() + } + + @Test + fun firstMobileSubShowingNetworkTypeIcon_subListUpdates_valAlsoUpdates() = + testScope.runTest { + var latest: Boolean? = null + val job = + underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2) + interactor.getInteractorForSubId(1)?.networkTypeIconGroup?.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN) + interactor.getInteractorForSubId(2)!!.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G) + + assertThat(latest).isTrue() + + // WHEN the sub list gets new subscriptions where the last subscription is not showing + // the network type icon + interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2, SUB_3) + interactor.getInteractorForSubId(3)!!.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN) + + // THEN the flow updates + assertThat(latest).isFalse() + + job.cancel() + } + + @Test + fun firstMobileSubShowingNetworkTypeIcon_subListReorders_valAlsoUpdates() = + testScope.runTest { + var latest: Boolean? = null + val job = + underTest.firstMobileSubShowingNetworkTypeIcon.onEach { latest = it }.launchIn(this) + + interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2) + // Immediately switch the order so that we've created both interactors + interactor.filteredSubscriptions.value = listOf(SUB_2, SUB_1) + val sub1Interactor = interactor.getInteractorForSubId(1)!! + val sub2Interactor = interactor.getInteractorForSubId(2)!! + + interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2) + sub1Interactor.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.UNKNOWN) + sub2Interactor.networkTypeIconGroup.value = + NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G) + assertThat(latest).isTrue() + + // WHEN sub1 becomes last and sub1 has no network type icon + interactor.filteredSubscriptions.value = listOf(SUB_2, SUB_1) + + // THEN the flow updates + assertThat(latest).isFalse() + + // WHEN sub2 becomes last and sub2 has a network type icon + interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2) + + // THEN the flow updates + assertThat(latest).isTrue() + + job.cancel() + } + companion object { private val SUB_1 = SubscriptionModel(subscriptionId = 1, isOpportunistic = false) private val SUB_2 = SubscriptionModel(subscriptionId = 2, isOpportunistic = false) + private val SUB_3 = SubscriptionModel(subscriptionId = 3, isOpportunistic = false) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt index 87d4f5c618a7..661002d275b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlo import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.DEFAULT_HIDDEN_ICONS_RESOURCE import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.HIDDEN_ICONS_TUNABLE_KEY +import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo import com.android.systemui.tuner.TunerService import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -491,6 +492,111 @@ class ConnectivityRepositoryImplTest : SysuiTestCase() { } @Test + fun defaultConnections_nullUnderlyingInfo_noError() { + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(null) + } + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + // No assert, just verify no error + } + + @Test + fun defaultConnections_underlyingInfoHasNullCapabilities_noError() { + val underlyingNetworkWithNull = mock<Network>() + whenever(connectivityManager.getNetworkCapabilities(underlyingNetworkWithNull)) + .thenReturn(null) + + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetworkWithNull)) + } + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + // No assert, just verify no error + } + + // This test verifies our internal API for completeness, but we don't expect this case to ever + // happen in practice. + @Test + fun defaultConnections_cellular_underlyingCarrierMergedViaWifi_allDefault() = + testScope.runTest { + var latest: DefaultConnectionModel? = null + val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this) + + // Underlying carrier merged network + val underlyingCarrierMergedNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } + val underlyingCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(carrierMergedInfo) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) + .thenReturn(underlyingCapabilities) + + // Main network with underlying network + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks) + .thenReturn(listOf(underlyingCarrierMergedNetwork)) + } + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + + assertThat(latest!!.mobile.isDefault).isTrue() + assertThat(latest!!.carrierMerged.isDefault).isTrue() + assertThat(latest!!.wifi.isDefault).isTrue() + + job.cancel() + } + + /** Test for b/225902574. */ + @Test + fun defaultConnections_cellular_underlyingCarrierMergedViaMobileWithVcnTransport_allDefault() = + testScope.runTest { + var latest: DefaultConnectionModel? = null + val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this) + + // Underlying carrier merged network + val underlyingCarrierMergedNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } + val underlyingCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo)) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) + .thenReturn(underlyingCapabilities) + + // Main network with underlying network + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks) + .thenReturn(listOf(underlyingCarrierMergedNetwork)) + } + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + + assertThat(latest!!.mobile.isDefault).isTrue() + assertThat(latest!!.carrierMerged.isDefault).isTrue() + assertThat(latest!!.wifi.isDefault).isTrue() + + job.cancel() + } + + @Test fun defaultConnections_multipleTransports_multipleDefault() = testScope.runTest { var latest: DefaultConnectionModel? = null @@ -548,6 +654,279 @@ class ConnectivityRepositoryImplTest : SysuiTestCase() { job.cancel() } + @Test + fun getMainOrUnderlyingWifiInfo_wifi_hasInfo() { + val wifiInfo = mock<WifiInfo>() + val capabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(wifiInfo) + } + + val result = capabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + assertThat(result).isEqualTo(wifiInfo) + } + + @Test + fun getMainOrUnderlyingWifiInfo_vcnWithWifi_hasInfo() { + val wifiInfo = mock<WifiInfo>() + val vcnInfo = VcnTransportInfo(wifiInfo) + val capabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(vcnInfo) + } + + val result = capabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + assertThat(result).isEqualTo(wifiInfo) + } + + @Test + fun getMainOrUnderlyingWifiInfo_notCellularOrWifiTransport_noInfo() { + val capabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) + whenever(it.transportInfo).thenReturn(mock<WifiInfo>()) + } + + val result = capabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + assertThat(result).isNull() + } + + @Test + fun getMainOrUnderlyingWifiInfo_cellular_underlyingWifi_hasInfo() { + val underlyingNetwork = mock<Network>() + val underlyingWifiInfo = mock<WifiInfo>() + val underlyingWifiCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(underlyingWifiInfo) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingWifiCapabilities) + + // WHEN the main capabilities have an underlying wifi network + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) + } + + val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + // THEN we fetch the underlying wifi info + assertThat(result).isEqualTo(underlyingWifiInfo) + } + + @Test + fun getMainOrUnderlyingWifiInfo_notCellular_underlyingWifi_noInfo() { + val underlyingNetwork = mock<Network>() + val underlyingWifiInfo = mock<WifiInfo>() + val underlyingWifiCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(underlyingWifiInfo) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingWifiCapabilities) + + // WHEN the main capabilities have an underlying wifi network but is *not* CELLULAR + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true) + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) + } + + val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + // THEN we DON'T fetch the underlying wifi info + assertThat(result).isNull() + } + + @Test + fun getMainOrUnderlyingWifiInfo_cellular_underlyingVcnWithWifi_hasInfo() { + val wifiInfo = mock<WifiInfo>() + val underlyingNetwork = mock<Network>() + val underlyingVcnInfo = VcnTransportInfo(wifiInfo) + val underlyingWifiCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(underlyingVcnInfo) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingWifiCapabilities) + + // WHEN the main capabilities have an underlying VCN network with wifi + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) + } + + val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + // THEN we fetch the wifi info + assertThat(result).isEqualTo(wifiInfo) + } + + @Test + fun getMainOrUnderlyingWifiInfo_notCellular_underlyingVcnWithWifi_noInfo() { + val underlyingNetwork = mock<Network>() + val underlyingVcnInfo = VcnTransportInfo(mock<WifiInfo>()) + val underlyingWifiCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(underlyingVcnInfo) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingWifiCapabilities) + + // WHEN the main capabilities have an underlying wifi network but it is *not* CELLULAR + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true) + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) + } + + val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + // THEN we DON'T fetch the underlying wifi info + assertThat(result).isNull() + } + + @Test + fun getMainOrUnderlyingWifiInfo_cellular_underlyingCellularWithCarrierMerged_hasInfo() { + // Underlying carrier merged network + val underlyingCarrierMergedNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } + val underlyingCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo)) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) + .thenReturn(underlyingCapabilities) + + // Main network with underlying network + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingCarrierMergedNetwork)) + } + + val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + assertThat(result).isEqualTo(carrierMergedInfo) + assertThat(result!!.isCarrierMerged).isTrue() + } + + @Test + fun getMainOrUnderlyingWifiInfo_multipleUnderlying_usesFirstNonNull() { + // First underlying: Not wifi + val underlyingNotWifiNetwork = mock<Network>() + val underlyingNotWifiCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) + whenever(it.transportInfo).thenReturn(null) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingNotWifiNetwork)) + .thenReturn(underlyingNotWifiCapabilities) + + // Second underlying: wifi + val underlyingWifiNetwork1 = mock<Network>() + val underlyingWifiInfo1 = mock<WifiInfo>() + val underlyingWifiCapabilities1 = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(underlyingWifiInfo1) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingWifiNetwork1)) + .thenReturn(underlyingWifiCapabilities1) + + // Third underlying: also wifi + val underlyingWifiNetwork2 = mock<Network>() + val underlyingWifiInfo2 = mock<WifiInfo>() + val underlyingWifiCapabilities2 = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(underlyingWifiInfo2) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingWifiNetwork2)) + .thenReturn(underlyingWifiCapabilities2) + + // WHEN the main capabilities has multiple underlying networks + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks) + .thenReturn( + listOf( + underlyingNotWifiNetwork, + underlyingWifiNetwork1, + underlyingWifiNetwork2, + ) + ) + } + + val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + // THEN the first wifi one is used + assertThat(result).isEqualTo(underlyingWifiInfo1) + } + + @Test + fun getMainOrUnderlyingWifiInfo_nestedUnderlying_doesNotLookAtNested() { + // WHEN there are two layers of underlying networks... + + // Nested network + val nestedUnderlyingNetwork = mock<Network>() + val nestedWifiInfo = mock<WifiInfo>() + val nestedCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(nestedWifiInfo) + } + whenever(connectivityManager.getNetworkCapabilities(nestedUnderlyingNetwork)) + .thenReturn(nestedCapabilities) + + // Underlying network containing the nested network + val underlyingNetwork = mock<Network>() + val underlyingCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(nestedUnderlyingNetwork)) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingCapabilities) + + // Main network containing the underlying network, which contains the nested network + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) + } + + val result = mainCapabilities.getMainOrUnderlyingWifiInfo(connectivityManager) + + // THEN only the first layer is checked, and the first layer has no wifi info + assertThat(result).isNull() + } + private fun createAndSetRepo() { underTest = ConnectivityRepositoryImpl( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt index f69e9a39909b..d30e0246c2dd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt @@ -29,6 +29,7 @@ import android.net.vcn.VcnTransportInfo import android.net.wifi.WifiInfo import android.net.wifi.WifiManager import android.net.wifi.WifiManager.TrafficStateCallback +import android.net.wifi.WifiManager.UNKNOWN_SSID import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -49,16 +50,14 @@ import com.android.systemui.util.mockito.nullable import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import java.util.concurrent.Executor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking -import org.junit.After +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.mockito.ArgumentMatchers.anyInt @@ -80,9 +79,10 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Mock private lateinit var connectivityManager: ConnectivityManager @Mock private lateinit var wifiManager: WifiManager private lateinit var executor: Executor - private lateinit var scope: CoroutineScope private lateinit var connectivityRepository: ConnectivityRepository + private val testScope = TestScope(UnconfinedTestDispatcher()) + @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -96,7 +96,6 @@ class WifiRepositoryImplTest : SysuiTestCase() { ) .thenReturn(flowOf(Unit)) executor = FakeExecutor(FakeSystemClock()) - scope = CoroutineScope(IMMEDIATE) connectivityRepository = ConnectivityRepositoryImpl( @@ -105,21 +104,16 @@ class WifiRepositoryImplTest : SysuiTestCase() { context, mock(), mock(), - scope, + testScope.backgroundScope, mock(), ) underTest = createRepo() } - @After - fun tearDown() { - scope.cancel() - } - @Test fun isWifiEnabled_initiallyGetsWifiManagerValue() = - runBlocking(IMMEDIATE) { + testScope.runTest { whenever(wifiManager.isWifiEnabled).thenReturn(true) underTest = createRepo() @@ -129,7 +123,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiEnabled_networkCapabilitiesChanged_valueUpdated() = - runBlocking(IMMEDIATE) { + testScope.runTest { // We need to call launch on the flows so that they start updating val networkJob = underTest.wifiNetwork.launchIn(this) val enabledJob = underTest.isWifiEnabled.launchIn(this) @@ -152,7 +146,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiEnabled_networkLost_valueUpdated() = - runBlocking(IMMEDIATE) { + testScope.runTest { // We need to call launch on the flows so that they start updating val networkJob = underTest.wifiNetwork.launchIn(this) val enabledJob = underTest.isWifiEnabled.launchIn(this) @@ -173,7 +167,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiEnabled_intentsReceived_valueUpdated() = - runBlocking(IMMEDIATE) { + testScope.runTest { val intentFlow = MutableSharedFlow<Unit>() whenever( broadcastDispatcher.broadcastFlow( @@ -203,7 +197,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiEnabled_bothIntentAndNetworkUpdates_valueAlwaysUpdated() = - runBlocking(IMMEDIATE) { + testScope.runTest { val intentFlow = MutableSharedFlow<Unit>() whenever( broadcastDispatcher.broadcastFlow( @@ -242,7 +236,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiDefault_initiallyGetsDefault() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) assertThat(underTest.isWifiDefault.value).isFalse() @@ -252,7 +246,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiDefault_wifiNetwork_isTrue() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val wifiInfo = mock<WifiInfo>().apply { whenever(this.ssid).thenReturn(SSID) } @@ -268,7 +262,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { /** Regression test for b/266628069. */ @Test fun isWifiDefault_transportInfoIsNotWifi_andNoWifiTransport_false() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val transportInfo = @@ -294,7 +288,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { /** Regression test for b/266628069. */ @Test fun isWifiDefault_transportInfoIsNotWifi_butHasWifiTransport_true() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val transportInfo = @@ -319,7 +313,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiDefault_carrierMergedViaCellular_isTrue() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val carrierMergedInfo = @@ -341,7 +335,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiDefault_carrierMergedViaCellular_withVcnTransport_isTrue() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val capabilities = @@ -360,7 +354,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiDefault_carrierMergedViaWifi_isTrue() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val carrierMergedInfo = @@ -382,7 +376,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiDefault_carrierMergedViaWifi_withVcnTransport_isTrue() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val capabilities = @@ -400,8 +394,8 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test - fun wifiNetwork_cellularAndWifiTransports_usesCellular_isTrue() = - runBlocking(IMMEDIATE) { + fun isWifiDefault_cellularAndWifiTransports_usesCellular_isTrue() = + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val capabilities = @@ -420,7 +414,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun isWifiDefault_cellularNotVcnNetwork_isFalse() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) val capabilities = @@ -437,8 +431,77 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test + fun isWifiDefault_isCarrierMergedViaUnderlyingWifi_isTrue() = + testScope.runTest { + val job = underTest.isWifiDefault.launchIn(this) + + val underlyingNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } + } + val underlyingWifiCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(carrierMergedInfo) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingWifiCapabilities) + + // WHEN the main capabilities have an underlying carrier merged network via WIFI + // transport and WifiInfo + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) + } + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + + // THEN the wifi network is carrier merged, so wifi is default + assertThat(underTest.isWifiDefault.value).isTrue() + + job.cancel() + } + + @Test + fun isWifiDefault_isCarrierMergedViaUnderlyingCellular_isTrue() = + testScope.runTest { + val job = underTest.isWifiDefault.launchIn(this) + + val underlyingCarrierMergedNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) } + val underlyingCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo)) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) + .thenReturn(underlyingCapabilities) + + // WHEN the main capabilities have an underlying carrier merged network via CELLULAR + // transport and VcnTransportInfo + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks) + .thenReturn(listOf(underlyingCarrierMergedNetwork)) + } + + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + + // THEN the wifi network is carrier merged, so wifi is default + assertThat(underTest.isWifiDefault.value).isTrue() + + job.cancel() + } + + @Test fun isWifiDefault_wifiNetworkLost_isFalse() = - runBlocking(IMMEDIATE) { + testScope.runTest { val job = underTest.isWifiDefault.launchIn(this) // First, add a network @@ -457,7 +520,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_initiallyGetsDefault() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -468,7 +531,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_primaryWifiNetworkAdded_flowHasNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -492,7 +555,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -511,8 +574,83 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test + fun wifiNetwork_isCarrierMergedViaUnderlyingWifi_flowHasCarrierMerged() = + testScope.runTest { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) + + val underlyingNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { + whenever(this.isCarrierMerged).thenReturn(true) + whenever(this.isPrimary).thenReturn(true) + } + val underlyingWifiCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.transportInfo).thenReturn(carrierMergedInfo) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingWifiCapabilities) + + // WHEN the main capabilities have an underlying carrier merged network via WIFI + // transport and WifiInfo + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork)) + } + + getNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + + // THEN the wifi network is carrier merged + assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue() + + job.cancel() + } + + @Test + fun wifiNetwork_isCarrierMergedViaUnderlyingCellular_flowHasCarrierMerged() = + testScope.runTest { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) + + val underlyingCarrierMergedNetwork = mock<Network>() + val carrierMergedInfo = + mock<WifiInfo>().apply { + whenever(this.isCarrierMerged).thenReturn(true) + whenever(this.isPrimary).thenReturn(true) + } + val underlyingCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo)) + } + whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork)) + .thenReturn(underlyingCapabilities) + + // WHEN the main capabilities have an underlying carrier merged network via CELLULAR + // transport and VcnTransportInfo + val mainCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(it.transportInfo).thenReturn(null) + whenever(it.underlyingNetworks) + .thenReturn(listOf(underlyingCarrierMergedNetwork)) + } + + getNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities) + + // THEN the wifi network is carrier merged + assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue() + + job.cancel() + } + + @Test fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -536,7 +674,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_isCarrierMerged_getsCorrectValues() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -571,7 +709,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_notValidated_networkNotValidated() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -588,7 +726,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_validated_networkValidated() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -605,7 +743,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_nonPrimaryWifiNetworkAdded_flowHasNoNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -626,7 +764,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { /** Regression test for b/266628069. */ @Test fun wifiNetwork_transportInfoIsNotWifi_flowHasNoNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -645,7 +783,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_cellularVcnNetworkAdded_flowHasNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -667,7 +805,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_nonPrimaryCellularVcnNetworkAdded_flowHasNoNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -691,7 +829,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_cellularNotVcnNetworkAdded_flowHasNoNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -710,7 +848,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_cellularAndWifiTransports_usesCellular() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -733,7 +871,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -766,7 +904,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_newNonPrimaryWifiNetwork_flowHasOldNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -799,7 +937,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_newNetworkCapabilities_flowHasNewData() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -842,7 +980,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_noCurrentNetwork_networkLost_flowHasNoNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -857,7 +995,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_currentNetworkLost_flowHasNoNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -876,7 +1014,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_unknownNetworkLost_flowHasPreviousNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -899,7 +1037,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiNetwork_notCurrentNetworkLost_flowHasCurrentNetwork() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: WifiNetworkModel? = null val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) @@ -925,7 +1063,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { /** Regression test for b/244173280. */ @Test fun wifiNetwork_multipleSubscribers_newSubscribersGetCurrentValue() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest1: WifiNetworkModel? = null val job1 = underTest.wifiNetwork.onEach { latest1 = it }.launchIn(this) @@ -952,8 +1090,151 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test + fun isWifiConnectedWithValidSsid_inactiveNetwork_false() = + testScope.runTest { + val job = underTest.wifiNetwork.launchIn(this) + + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.ssid).thenReturn(SSID) + // A non-primary network is inactive + whenever(this.isPrimary).thenReturn(false) + } + + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) + + assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() + + job.cancel() + } + + @Test + fun isWifiConnectedWithValidSsid_carrierMergedNetwork_false() = + testScope.runTest { + val job = underTest.wifiNetwork.launchIn(this) + + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.isCarrierMerged).thenReturn(true) + } + + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) + + assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() + + job.cancel() + } + + @Test + fun isWifiConnectedWithValidSsid_invalidNetwork_false() = + testScope.runTest { + val job = underTest.wifiNetwork.launchIn(this) + + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.isCarrierMerged).thenReturn(true) + whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID) + } + + getNetworkCallback() + .onCapabilitiesChanged( + NETWORK, + createWifiNetworkCapabilities(wifiInfo), + ) + + assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() + + job.cancel() + } + + @Test + fun isWifiConnectedWithValidSsid_activeNetwork_nullSsid_false() = + testScope.runTest { + val job = underTest.wifiNetwork.launchIn(this) + + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.ssid).thenReturn(null) + } + + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) + + assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() + + job.cancel() + } + + @Test + fun isWifiConnectedWithValidSsid_activeNetwork_unknownSsid_false() = + testScope.runTest { + val job = underTest.wifiNetwork.launchIn(this) + + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.ssid).thenReturn(UNKNOWN_SSID) + } + + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) + + assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() + + job.cancel() + } + + @Test + fun isWifiConnectedWithValidSsid_activeNetwork_validSsid_true() = + testScope.runTest { + val job = underTest.wifiNetwork.launchIn(this) + + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.ssid).thenReturn("FakeSsid") + } + + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) + + assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue() + + job.cancel() + } + + @Test + fun isWifiConnectedWithValidSsid_activeToInactive_trueToFalse() = + testScope.runTest { + val job = underTest.wifiNetwork.launchIn(this) + + // Start with active + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.ssid).thenReturn("FakeSsid") + } + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) + assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue() + + // WHEN the network is lost + getNetworkCallback().onLost(NETWORK) + + // THEN the isWifiConnected updates + assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() + + job.cancel() + } + + @Test fun wifiActivity_callbackGivesNone_activityFlowHasNone() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: DataActivityModel? = null val job = underTest.wifiActivity.onEach { latest = it }.launchIn(this) @@ -967,7 +1248,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiActivity_callbackGivesIn_activityFlowHasIn() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: DataActivityModel? = null val job = underTest.wifiActivity.onEach { latest = it }.launchIn(this) @@ -981,7 +1262,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiActivity_callbackGivesOut_activityFlowHasOut() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: DataActivityModel? = null val job = underTest.wifiActivity.onEach { latest = it }.launchIn(this) @@ -995,7 +1276,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { @Test fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() = - runBlocking(IMMEDIATE) { + testScope.runTest { var latest: DataActivityModel? = null val job = underTest.wifiActivity.onEach { latest = it }.launchIn(this) @@ -1015,7 +1296,7 @@ class WifiRepositoryImplTest : SysuiTestCase() { logger, tableLogger, executor, - scope, + testScope.backgroundScope, wifiManager, ) } @@ -1060,5 +1341,3 @@ class WifiRepositoryImplTest : SysuiTestCase() { } } } - -private val IMMEDIATE = Dispatchers.Main.immediate diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt index ab4e93ceee84..4e0c309512e8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.wifi.shared.model +import android.net.wifi.WifiManager.UNKNOWN_SSID import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -50,6 +51,42 @@ class WifiNetworkModelTest : SysuiTestCase() { WifiNetworkModel.CarrierMerged(NETWORK_ID, INVALID_SUBSCRIPTION_ID, 1) } + @Test + fun active_hasValidSsid_nullSsid_false() { + val network = + WifiNetworkModel.Active( + NETWORK_ID, + level = MAX_VALID_LEVEL, + ssid = null, + ) + + assertThat(network.hasValidSsid()).isFalse() + } + + @Test + fun active_hasValidSsid_unknownSsid_false() { + val network = + WifiNetworkModel.Active( + NETWORK_ID, + level = MAX_VALID_LEVEL, + ssid = UNKNOWN_SSID, + ) + + assertThat(network.hasValidSsid()).isFalse() + } + + @Test + fun active_hasValidSsid_validSsid_true() { + val network = + WifiNetworkModel.Active( + NETWORK_ID, + level = MAX_VALID_LEVEL, + ssid = "FakeSsid", + ) + + assertThat(network.hasValidSsid()).isTrue() + } + // Non-exhaustive logDiffs test -- just want to make sure the logging logic isn't totally broken @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt index 5c19108cc17e..0d51af2754f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt @@ -50,6 +50,7 @@ import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -98,12 +99,12 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { val viewModelCommon = WifiViewModel( airplaneModeViewModel, + shouldShowSignalSpacerProvider = { MutableStateFlow(false) }, connectivityConstants, context, tableLogBuffer, interactor, scope, - statusBarPipelineFlags, wifiConstants, ) viewModel = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt index ffe990bf1cf6..e6724d86ec55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt @@ -27,7 +27,6 @@ import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK -import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel @@ -46,6 +45,7 @@ import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.runBlocking import kotlinx.coroutines.yield @@ -66,7 +66,6 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase private lateinit var underTest: WifiViewModel - @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags @Mock private lateinit var tableLogBuffer: TableLogBuffer @Mock private lateinit var connectivityConstants: ConnectivityConstants @Mock private lateinit var wifiConstants: WifiConstants @@ -121,12 +120,12 @@ internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase underTest = WifiViewModel( airplaneModeViewModel, + shouldShowSignalSpacerProvider = { MutableStateFlow(false) }, connectivityConstants, context, tableLogBuffer, interactor, scope, - statusBarPipelineFlags, wifiConstants, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt index 802e360797a4..0e303b244094 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt @@ -39,8 +39,8 @@ import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWi import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.runBlocking @@ -53,7 +53,6 @@ import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") -@OptIn(ExperimentalCoroutinesApi::class) @SmallTest class WifiViewModelTest : SysuiTestCase() { @@ -68,6 +67,7 @@ class WifiViewModelTest : SysuiTestCase() { private lateinit var wifiRepository: FakeWifiRepository private lateinit var interactor: WifiInteractor private lateinit var airplaneModeViewModel: AirplaneModeViewModel + private val shouldShowSignalSpacerProviderFlow = MutableStateFlow(false) private lateinit var scope: CoroutineScope @Before @@ -473,6 +473,34 @@ class WifiViewModelTest : SysuiTestCase() { job.cancel() } + @Test + fun signalSpacer_firstSubNotShowingNetworkTypeIcon_outputsFalse() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.isSignalSpacerVisible.onEach { latest = it }.launchIn(this) + + shouldShowSignalSpacerProviderFlow.value = false + yield() + + assertThat(latest).isFalse() + + job.cancel() + } + + @Test + fun signalSpacer_firstSubIsShowingNetworkTypeIcon_outputsTrue() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.isSignalSpacerVisible.onEach { latest = it }.launchIn(this) + + shouldShowSignalSpacerProviderFlow.value = true + yield() + + assertThat(latest).isTrue() + + job.cancel() + } + private fun createAndSetViewModel() { // [WifiViewModel] creates its flows as soon as it's instantiated, and some of those flow // creations rely on certain config values that we mock out in individual tests. This method @@ -480,12 +508,12 @@ class WifiViewModelTest : SysuiTestCase() { underTest = WifiViewModel( airplaneModeViewModel, + { shouldShowSignalSpacerProviderFlow }, connectivityConstants, context, tableLogBuffer, interactor, scope, - statusBarPipelineFlags, wifiConstants, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java index 1eee08c22187..91c88cebff79 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java @@ -21,6 +21,7 @@ import static android.os.BatteryManager.EXTRA_PRESENT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker; +import static com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_QS; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; @@ -167,8 +168,10 @@ public class BatteryControllerTest extends SysuiTestCase { mBatteryController.setPowerSaveMode(false, mView); StaticInOrder inOrder = inOrder(staticMockMarker(BatterySaverUtils.class)); - inOrder.verify(() -> BatterySaverUtils.setPowerSaveMode(getContext(), true, true)); - inOrder.verify(() -> BatterySaverUtils.setPowerSaveMode(getContext(), false, true)); + inOrder.verify(() -> BatterySaverUtils.setPowerSaveMode(getContext(), true, true, + SAVER_ENABLED_QS)); + inOrder.verify(() -> BatterySaverUtils.setPowerSaveMode(getContext(), false, true, + SAVER_ENABLED_QS)); } @Test 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 01e94baab7c3..391c8ca4d286 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.AnimatorTestRule2; +import androidx.core.animation.AnimatorTestRule; 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 AnimatorTestRule2 mAnimatorTestRule = new AnimatorTestRule2(); + public static AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(); @Before public void setUp() throws Exception { diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java index 6e109eafd748..23a9207ec643 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java @@ -45,7 +45,7 @@ public class WakeLockTest extends SysuiTestCase { mInner = WakeLock.createWakeLockInner(mContext, WakeLockTest.class.getName(), PowerManager.PARTIAL_WAKE_LOCK); - mWakeLock = WakeLock.wrap(mInner, 20000); + mWakeLock = WakeLock.wrap(mInner, null, 20000); } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java new file mode 100644 index 000000000000..9cf3e443320d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java @@ -0,0 +1,91 @@ +/* + * 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.volume; + +import static android.media.AudioManager.CSD_WARNING_DOSE_REACHED_1X; +import static android.media.AudioManager.CSD_WARNING_DOSE_REPEATED_5X; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.app.Notification; +import android.app.NotificationManager; +import android.media.AudioManager; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.messages.nano.SystemMessageProto; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class CsdWarningDialogTest extends SysuiTestCase { + + private NotificationManager mNotificationManager; + private AudioManager mAudioManager; + + @Before + public void setup() { + mNotificationManager = mock(NotificationManager.class); + getContext().addMockSystemService(NotificationManager.class, mNotificationManager); + + mAudioManager = mock(AudioManager.class); + getContext().addMockSystemService(AudioManager.class, mAudioManager); + } + + @Test + public void create1XCsdDialogAndWait_sendsNotification() { + FakeExecutor executor = new FakeExecutor(new FakeSystemClock()); + // instantiate directly instead of via factory; we don't want executor to be @Background + CsdWarningDialog dialog = new CsdWarningDialog(CSD_WARNING_DOSE_REACHED_1X, mContext, + mAudioManager, mNotificationManager, executor, null); + + dialog.show(); + executor.advanceClockToLast(); + executor.runAllReady(); + dialog.dismiss(); + + verify(mNotificationManager).notify( + eq(SystemMessageProto.SystemMessage.NOTE_CSD_LOWER_AUDIO), any(Notification.class)); + } + + @Test + public void create5XCsdDiSalogAndWait_willNotSendNotification() { + FakeExecutor executor = new FakeExecutor(new FakeSystemClock()); + CsdWarningDialog dialog = new CsdWarningDialog(CSD_WARNING_DOSE_REPEATED_5X, mContext, + mAudioManager, mNotificationManager, executor, null); + + dialog.show(); + executor.advanceClockToLast(); + executor.runAllReady(); + dialog.dismiss(); + + verify(mNotificationManager, never()).notify( + eq(SystemMessageProto.SystemMessage.NOTE_CSD_LOWER_AUDIO), any(Notification.class)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index d419095921b8..e33bfd7d601e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -58,6 +58,7 @@ import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -102,6 +103,15 @@ public class VolumeDialogImplTest extends SysuiTestCase { InteractionJankMonitor mInteractionJankMonitor; @Mock private DumpManager mDumpManager; + @Mock CsdWarningDialog mCsdWarningDialog; + + private final CsdWarningDialog.Factory mCsdWarningDialogFactory = + new CsdWarningDialog.Factory() { + @Override + public CsdWarningDialog create(int warningType, Runnable onCleanup) { + return mCsdWarningDialog; + } + }; @Before public void setup() throws Exception { @@ -124,6 +134,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { mInteractionJankMonitor, mDeviceConfigProxy, mExecutor, + mCsdWarningDialogFactory, mDumpManager ); mDialog.init(0, null); @@ -352,6 +363,21 @@ public class VolumeDialogImplTest extends SysuiTestCase { mDialog.getDialogView().animate().cancel(); } + @Test + public void showCsdWarning_dialogShown() { + mDialog.showCsdWarningH(AudioManager.CSD_WARNING_DOSE_REACHED_1X, + CsdWarningDialog.NO_ACTION_TIMEOUT_MS); + + verify(mCsdWarningDialog).show(); + } + + @After + public void teardown() { + if (mDialog != null) { + mDialog.clearInternalHandleAfterTest(); + } + } + /* @Test public void testContentDescriptions() { 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 28bdca97552d..a42acd3464ba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -85,6 +85,9 @@ import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; +import com.android.launcher3.icons.BubbleBadgeIconFactory; +import com.android.launcher3.icons.BubbleIconFactory; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -127,11 +130,9 @@ import com.android.systemui.statusbar.policy.ZenModeController; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.bubbles.Bubble; -import com.android.wm.shell.bubbles.BubbleBadgeIconFactory; import com.android.wm.shell.bubbles.BubbleData; import com.android.wm.shell.bubbles.BubbleDataRepository; import com.android.wm.shell.bubbles.BubbleEntry; -import com.android.wm.shell.bubbles.BubbleIconFactory; import com.android.wm.shell.bubbles.BubbleLogger; import com.android.wm.shell.bubbles.BubbleStackView; import com.android.wm.shell.bubbles.BubbleViewInfoTask; @@ -1225,8 +1226,13 @@ public class BubblesTest extends SysuiTestCase { BubbleViewInfoTask.BubbleViewInfo info = BubbleViewInfoTask.BubbleViewInfo.populate(context, mBubbleController, mBubbleController.getStackView(), - new BubbleIconFactory(mContext), - new BubbleBadgeIconFactory(mContext), + new BubbleIconFactory(mContext, + mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size)), + new BubbleBadgeIconFactory(mContext, + mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size), + mContext.getResources().getColor(R.color.important_conversation), + mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.importance_ring_stroke_width)), bubble, true /* skipInflation */); verify(userContext, times(1)).getPackageManager(); @@ -1251,6 +1257,7 @@ public class BubblesTest extends SysuiTestCase { stackView.showManageMenu(true); assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */); assertTrue(stackView.isManageMenuSettingsVisible()); + assertTrue(stackView.isManageMenuDontBubbleVisible()); } @Test @@ -1268,6 +1275,7 @@ public class BubblesTest extends SysuiTestCase { stackView.showManageMenu(true); assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */); assertFalse(stackView.isManageMenuSettingsVisible()); + assertFalse(stackView.isManageMenuDontBubbleVisible()); } @Test diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java index 1bab99787de4..1ec4e8c48707 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java @@ -22,12 +22,14 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.Instrumentation; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; import android.os.ParcelFileDescriptor; import android.testing.DexmakerShareClassLoaderRule; import android.testing.LeakCheck; +import android.testing.TestWithLooperRule; import android.testing.TestableLooper; import android.util.Log; @@ -73,12 +75,21 @@ public abstract class SysuiTestCase { @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); + + // set the highest order so it's the innermost rule + @Rule(order = Integer.MAX_VALUE) + public TestWithLooperRule mlooperRule = new TestWithLooperRule(); + public TestableDependency mDependency; private Instrumentation mRealInstrumentation; private FakeBroadcastDispatcher mFakeBroadcastDispatcher; @Before public void SysuiSetup() throws Exception { + // Manually associate a Display to context for Robolectric test. Similar to b/214297409 + if (isRobolectricTest()) { + mContext = mContext.createDefaultDisplayContext(); + } SystemUIInitializer initializer = SystemUIInitializerFactory.createFromConfigNoAssert(mContext); initializer.init(true); @@ -215,6 +226,10 @@ public abstract class SysuiTestCase { idler.waitForIdle(); } + public static boolean isRobolectricTest() { + return Build.FINGERPRINT.contains("robolectric"); + } + private static final void validateThread(Looper l) { if (Looper.myLooper() == l) { throw new RuntimeException( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java index 0674ea855d7f..5ff57aad9f5d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java @@ -18,6 +18,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.UserHandle; import android.testing.LeakCheck; @@ -56,6 +57,11 @@ public class SysuiTestableContext extends TestableContext { return context; } + public SysuiTestableContext createDefaultDisplayContext() { + Display display = getBaseContext().getSystemService(DisplayManager.class).getDisplays()[0]; + return (SysuiTestableContext) createDisplayContext(display); + } + public void cleanUpReceivers(String testName) { Set<BroadcastReceiver> copy; synchronized (mRegisteredReceivers) { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt new file mode 100644 index 000000000000..738f09ddce3d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt @@ -0,0 +1,63 @@ +/* + * 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.keyguard.data.repository + +import com.android.keyguard.FaceAuthUiEvent +import com.android.systemui.keyguard.shared.model.AuthenticationStatus +import com.android.systemui.keyguard.shared.model.DetectionStatus +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.filterNotNull + +class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository { + + override val isAuthenticated = MutableStateFlow(false) + override val canRunFaceAuth = MutableStateFlow(false) + private val _authenticationStatus = MutableStateFlow<AuthenticationStatus?>(null) + override val authenticationStatus: Flow<AuthenticationStatus> = + _authenticationStatus.filterNotNull() + fun setAuthenticationStatus(status: AuthenticationStatus) { + _authenticationStatus.value = status + } + private val _detectionStatus = MutableStateFlow<DetectionStatus?>(null) + override val detectionStatus: Flow<DetectionStatus> + get() = _detectionStatus.filterNotNull() + fun setDetectionStatus(status: DetectionStatus) { + _detectionStatus.value = status + } + override val isLockedOut = MutableStateFlow(false) + private val _runningAuthRequest = MutableStateFlow<Pair<FaceAuthUiEvent, Boolean>?>(null) + val runningAuthRequest: StateFlow<Pair<FaceAuthUiEvent, Boolean>?> = + _runningAuthRequest.asStateFlow() + + private val _isAuthRunning = MutableStateFlow(false) + override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning + + override val isBypassEnabled = MutableStateFlow(false) + + override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) { + _runningAuthRequest.value = uiEvent to fallbackToDetection + _isAuthRunning.value = true + } + + override fun cancel() { + _isAuthRunning.value = false + _runningAuthRequest.value = null + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt new file mode 100644 index 000000000000..9383a0a68844 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt @@ -0,0 +1,36 @@ +/* + * 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 + +import android.content.Context +import com.android.systemui.plugins.qs.QSFactory +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.plugins.qs.QSTileView + +class FakeQSFactory(private val tileCreator: (String) -> QSTile?) : QSFactory { + override fun createTile(tileSpec: String): QSTile? { + return tileCreator(tileSpec) + } + + override fun createTileView( + context: Context?, + tile: QSTile?, + collapsedView: Boolean + ): QSTileView { + throw NotImplementedError("Not implemented") + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeCustomTileAddedRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeCustomTileAddedRepository.kt new file mode 100644 index 000000000000..777130409aad --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeCustomTileAddedRepository.kt @@ -0,0 +1,36 @@ +/* + * 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.content.ComponentName + +class FakeCustomTileAddedRepository : CustomTileAddedRepository { + + private val tileAddedRegistry = mutableSetOf<Pair<Int, ComponentName>>() + + override fun isTileAdded(componentName: ComponentName, userId: Int): Boolean { + return (userId to componentName) in tileAddedRegistry + } + + override fun setTileAdded(componentName: ComponentName, userId: Int, added: Boolean) { + if (added) { + tileAddedRegistry.add(userId to componentName) + } else { + tileAddedRegistry.remove(userId to componentName) + } + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt new file mode 100644 index 000000000000..2865710c2eae --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt @@ -0,0 +1,61 @@ +/* + * 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.util.Log +import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END +import com.android.systemui.qs.pipeline.shared.TileSpec +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeTileSpecRepository : TileSpecRepository { + + private val tilesPerUser = mutableMapOf<Int, MutableStateFlow<List<TileSpec>>>() + + override fun tilesSpecs(userId: Int): Flow<List<TileSpec>> { + return getFlow(userId).asStateFlow().also { Log.d("Fabian", "Retrieving flow for $userId") } + } + + override suspend fun addTile(userId: Int, tile: TileSpec, position: Int) { + if (tile == TileSpec.Invalid) return + with(getFlow(userId)) { + value = + value.toMutableList().apply { + if (position == POSITION_AT_END) { + add(tile) + } else { + add(position, tile) + } + } + } + } + + override suspend fun removeTiles(userId: Int, tiles: Collection<TileSpec>) { + with(getFlow(userId)) { + value = + value.toMutableList().apply { removeAll(tiles.filter { it != TileSpec.Invalid }) } + } + } + + override suspend fun setTiles(userId: Int, tiles: List<TileSpec>) { + getFlow(userId).value = tiles.filter { it != TileSpec.Invalid } + } + + private fun getFlow(userId: Int): MutableStateFlow<List<TileSpec>> = + tilesPerUser.getOrPut(userId) { MutableStateFlow(emptyList()) } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/wakelock/WakeLockFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/wakelock/WakeLockFake.java index 553b8a42edc8..cd2ff0b13027 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/wakelock/WakeLockFake.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/wakelock/WakeLockFake.java @@ -55,7 +55,7 @@ public class WakeLockFake implements WakeLock { private WakeLock mWakeLock; public Builder(Context context) { - super(context); + super(context, null); } public void setWakeLock(WakeLock wakeLock) { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/widget/FakeListAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/widget/FakeListAdapter.kt new file mode 100644 index 000000000000..231373b50c47 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/widget/FakeListAdapter.kt @@ -0,0 +1,47 @@ +/* + * 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.widget + +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter + +class FakeListAdapter(private var items: List<FakeListAdapterItem> = emptyList()) : BaseAdapter() { + + fun setItems(items: List<FakeListAdapterItem>) { + this.items = items + notifyDataSetChanged() + } + + override fun getCount(): Int = items.size + + override fun getItem(position: Int): Any = items[position].data + + override fun getItemId(position: Int): Long = items[position].id + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View = + items[position].view(position, convertView, parent) + + class FakeListAdapterItem( + /** Result returned in [Adapter#getView] */ + val view: (position: Int, convertView: View?, parent: ViewGroup?) -> View, + /** Returned in [Adapter#getItemId] */ + val id: Long = 0, + /** Returned in [Adapter#getItem] */ + val data: Any = Unit, + ) +} diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt index 380c1fcbf732..156d2fc2cb3a 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt @@ -25,14 +25,18 @@ import java.util.concurrent.Executor * It could be used when no activity context is available * TODO(b/232369816): use Jetpack WM library when non-activity contexts supported b/169740873 */ -class ScreenSizeFoldProvider(private val context: Context) : FoldProvider { +class ScreenSizeFoldProvider(context: Context) : FoldProvider { + private var isFolded: Boolean = false private var callbacks: MutableList<FoldCallback> = arrayListOf() - private var lastWidth: Int = 0 + + init { + onConfigurationChange(context.resources.configuration) + } override fun registerCallback(callback: FoldCallback, executor: Executor) { callbacks += callback - onConfigurationChange(context.resources.configuration) + callback.onFoldUpdated(isFolded) } override fun unregisterCallback(callback: FoldCallback) { @@ -40,16 +44,14 @@ class ScreenSizeFoldProvider(private val context: Context) : FoldProvider { } fun onConfigurationChange(newConfig: Configuration) { - if (lastWidth == newConfig.smallestScreenWidthDp) { + val newIsFolded = + newConfig.smallestScreenWidthDp < INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP + if (newIsFolded == isFolded) { return } - if (newConfig.smallestScreenWidthDp > INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP) { - callbacks.forEach { it.onFoldUpdated(false) } - } else { - callbacks.forEach { it.onFoldUpdated(true) } - } - lastWidth = newConfig.smallestScreenWidthDp + isFolded = newIsFolded + callbacks.forEach { it.onFoldUpdated(isFolded) } } } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt index 0b019d1285e3..30418883eaf8 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt @@ -35,7 +35,7 @@ class UnfoldRemoteFilter( private var inProgress = false - private var processedProgress: Float = 0.0f + private var processedProgress: Float = 1.0f set(newProgress) { if (inProgress) { logCounter({ "$TAG#filtered_progress" }, newProgress) diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index a633a5e41882..46001a73e518 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -256,6 +256,12 @@ constructor( } } + override fun markScreenAsTurnedOn() { + if (!isFolded) { + isUnfoldHandled = true + } + } + override fun onScreenTurningOn() { isScreenOn = true updateHingeAngleProviderState() diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt index f09b53dc8436..2ee2940fa2a6 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt @@ -35,5 +35,12 @@ interface ScreenStatusProvider : CallbackController<ScreenListener> { * Called when the screen is starting to be turned on. */ fun onScreenTurningOn() + + /** + * Called when the screen is already turned on but it happened before the creation + * of the unfold progress provider, so we won't play the actual animation but we treat + * the current state of the screen as 'turned on' + */ + fun markScreenAsTurnedOn() } } diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk index cbca3f03fb0f..a41d0e57cd21 100644 --- a/packages/overlays/Android.mk +++ b/packages/overlays/Android.mk @@ -32,6 +32,7 @@ LOCAL_REQUIRED_MODULES := \ NavigationBarModeGesturalOverlayWideBack \ NavigationBarModeGesturalOverlayExtraWideBack \ TransparentNavigationBarOverlay \ + NotesRoleEnabledOverlay \ preinstalled-packages-platform-overlays.xml include $(BUILD_PHONY_PACKAGE) diff --git a/packages/overlays/NotesRoleEnabledOverlay/Android.bp b/packages/overlays/NotesRoleEnabledOverlay/Android.bp new file mode 100644 index 000000000000..68ebd9652399 --- /dev/null +++ b/packages/overlays/NotesRoleEnabledOverlay/Android.bp @@ -0,0 +1,30 @@ +// +// Copyright 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +runtime_resource_overlay { + name: "NotesRoleEnabledOverlay", + theme: "NotesRoleEnabled", + product_specific: true, +} diff --git a/packages/overlays/NotesRoleEnabledOverlay/AndroidManifest.xml b/packages/overlays/NotesRoleEnabledOverlay/AndroidManifest.xml new file mode 100644 index 000000000000..c01178d1727d --- /dev/null +++ b/packages/overlays/NotesRoleEnabledOverlay/AndroidManifest.xml @@ -0,0 +1,26 @@ +<!-- +/** + * 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. + */ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.role.notes.enabled" + android:versionCode="1" + android:versionName="1.0"> + <overlay android:targetPackage="android" + android:priority="1"/> + + <application android:label="@string/notes_role_enabled_overlay_title" android:hasCode="false"/> +</manifest>
\ No newline at end of file diff --git a/packages/overlays/NotesRoleEnabledOverlay/res/values/config.xml b/packages/overlays/NotesRoleEnabledOverlay/res/values/config.xml new file mode 100644 index 000000000000..f27f5f42ae6b --- /dev/null +++ b/packages/overlays/NotesRoleEnabledOverlay/res/values/config.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. + */ +--> +<resources> + <!-- Whether the default notes role should be enabled. In builds without + device-specific overlays, this can be controlled in developer options. --> + <bool name="config_enableDefaultNotes">true</bool> + + <!-- Whether the default notes role for work profile should be enabled. + In builds without device-specific overlays, this can be controlled in + developer options. --> + <bool name="config_enableDefaultNotesForWorkProfile">true</bool> +</resources> diff --git a/packages/overlays/NotesRoleEnabledOverlay/res/values/strings.xml b/packages/overlays/NotesRoleEnabledOverlay/res/values/strings.xml new file mode 100644 index 000000000000..3edbb571c4d1 --- /dev/null +++ b/packages/overlays/NotesRoleEnabledOverlay/res/values/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Name of overlay [CHAR LIMIT=64] --> + <string name="notes_role_enabled_overlay_title" translatable="false">Notes Role enabled</string> +</resources>
\ No newline at end of file diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index 47027342974d..21d09792f1c7 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -402,5 +402,7 @@ message SystemMessage { // Package: android NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF = 1006; + // Notify the user that audio was lowered based on Calculated Sound Dose (CSD) + NOTE_CSD_LOWER_AUDIO = 1007; } } diff --git a/services/Android.bp b/services/Android.bp index 6e6c55325e3d..b0a0e5e44a8c 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -112,6 +112,7 @@ filegroup { ":services.searchui-sources", ":services.selectiontoolbar-sources", ":services.smartspace-sources", + ":services.soundtrigger-sources", ":services.systemcaptions-sources", ":services.translation-sources", ":services.texttospeech-sources", @@ -169,6 +170,7 @@ java_library { "services.searchui", "services.selectiontoolbar", "services.smartspace", + "services.soundtrigger", "services.systemcaptions", "services.translation", "services.texttospeech", diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 51325e72204d..0bdb0c80d219 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -112,6 +112,7 @@ import android.util.IntArray; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.view.Display; import android.view.IWindow; import android.view.InputDevice; @@ -160,6 +161,7 @@ import com.android.server.accessibility.magnification.WindowMagnificationManager import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.pm.UserManagerInternal; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.utils.Slogf; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.WindowManagerInternal; import com.android.settingslib.RestrictedLockUtils; @@ -301,7 +303,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final List<SendWindowStateChangedEventRunnable> mSendWindowStateChangedEventRunnables = new ArrayList<>(); - private int mCurrentUserId = UserHandle.USER_SYSTEM; + @GuardedBy("mLock") + private @UserIdInt int mCurrentUserId = UserHandle.USER_SYSTEM; + + // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation: + // when the UiAutomation is set in a visible background user, mCurrentUserId points to that user + // and mRealCurrentUserId points to the "real" current user; otherwise, mRealCurrentUserId + // is set as UserHandle.USER_CURRENT. + @GuardedBy("mLock") + private @UserIdInt int mRealCurrentUserId = UserHandle.USER_CURRENT; + + // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation + // purposes - in the long term, the whole service should be refactored so it handles "visible" + // users, not current user. Notice that because this is temporary, it's not trying to optimize + // performance / utilization (for example, it's not using an IntArray) + @GuardedBy("mLock") + @Nullable // only set when device supports visible background users + private final SparseBooleanArray mVisibleBgUserIds; //TODO: Remove this hack private boolean mInitialized; @@ -316,6 +334,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private SparseArray<SurfaceControl> mA11yOverlayLayers = new SparseArray<>(); private final FlashNotificationsController mFlashNotificationsController; + private final UserManagerInternal mUmi; private AccessibilityUserState getCurrentUserStateLocked() { return getUserStateLocked(mCurrentUserId); @@ -445,6 +464,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mHasInputFilter = true; } mFlashNotificationsController = new FlashNotificationsController(mContext); + mUmi = LocalServices.getService(UserManagerInternal.class); + // TODO(b/255426725): not used on tests + mVisibleBgUserIds = null; + init(); } @@ -477,6 +500,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mProxyManager = new ProxyManager(mLock, mA11yWindowManager, mContext, mMainHandler, mUiAutomationManager, this); mFlashNotificationsController = new FlashNotificationsController(mContext); + mUmi = LocalServices.getService(UserManagerInternal.class); + + if (UserManager.isVisibleBackgroundUsersEnabled()) { + mVisibleBgUserIds = new SparseBooleanArray(); + mUmi.addUserVisibilityListener((u, v) -> onUserVisibilityChanged(u, v)); + } else { + mVisibleBgUserIds = null; + } + init(); } @@ -493,6 +525,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return mCurrentUserId; } + @GuardedBy("mLock") + @Override + public SparseBooleanArray getVisibleUserIdsLocked() { + return mVisibleBgUserIds; + } + @Override public boolean isAccessibilityButtonShown() { return mIsAccessibilityButtonShown; @@ -1362,6 +1400,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public void registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo, + int userId, int flags) { if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { mTraceManager.logTrace(LOG_TAG + ".registerUiTestAutomationService", @@ -1374,6 +1413,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE); synchronized (mLock) { + changeCurrentUserForTestAutomationIfNeededLocked(userId); mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient, mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(), mWindowManagerService, @@ -1390,7 +1430,47 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } synchronized (mLock) { mUiAutomationManager.unregisterUiTestAutomationServiceLocked(serviceClient); + restoreCurrentUserAfterTestAutomationIfNeededLocked(); + } + } + + // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation + @GuardedBy("mLock") + private void changeCurrentUserForTestAutomationIfNeededLocked(@UserIdInt int userId) { + if (mVisibleBgUserIds == null) { + Slogf.d(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(%d): ignoring " + + "because device doesn't support visible background users", userId); + return; + } + if (!mVisibleBgUserIds.get(userId)) { + Slogf.wtf(LOG_TAG, "Cannot change current user to %d as it's not visible " + + "(mVisibleUsers=%s)", userId, mVisibleBgUserIds); + return; + } + if (mCurrentUserId == userId) { + Slogf.w(LOG_TAG, "NOT changing current user for test automation purposes as it is " + + "already %d", mCurrentUserId); + return; + } + Slogf.i(LOG_TAG, "Changing current user from %d to %d for test automation purposes", + mCurrentUserId, userId); + mRealCurrentUserId = mCurrentUserId; + switchUser(userId); + } + + // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation + @GuardedBy("mLock") + private void restoreCurrentUserAfterTestAutomationIfNeededLocked() { + if (mVisibleBgUserIds == null) { + Slogf.d(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): ignoring " + + "because device doesn't support visible background users"); + return; } + Slogf.i(LOG_TAG, "Restoring current user to %d after using %d for test automation purposes", + mRealCurrentUserId, mCurrentUserId); + int currentUserId = mRealCurrentUserId; + mRealCurrentUserId = UserHandle.USER_CURRENT; + switchUser(currentUserId); } @Override @@ -2291,8 +2371,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private void updateServicesLocked(AccessibilityUserState userState) { Map<ComponentName, AccessibilityServiceConnection> componentNameToServiceMap = userState.mComponentNameToServiceMap; - boolean isUnlockingOrUnlocked = LocalServices.getService(UserManagerInternal.class) - .isUserUnlockingOrUnlocked(userState.mUserId); + boolean isUnlockingOrUnlocked = mUmi.isUserUnlockingOrUnlocked(userState.mUserId); for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); @@ -2593,6 +2672,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + private void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) { + if (DEBUG) { + Slogf.d(LOG_TAG, "onUserVisibilityChanged(): %d => %b", userId, visible); + } + synchronized (mLock) { + if (visible) { + mVisibleBgUserIds.put(userId, visible); + } else { + mVisibleBgUserIds.delete(userId); + } + } + } + /** * Called when any property of the user state has changed. * @@ -4025,7 +4117,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)"); pw.println(); pw.append("currentUserId=").append(String.valueOf(mCurrentUserId)); + if (mRealCurrentUserId != UserHandle.USER_CURRENT + && mCurrentUserId != mRealCurrentUserId) { + pw.append(" (set for UiAutomation purposes; \"real\" current user is ") + .append(String.valueOf(mRealCurrentUserId)).append(")"); + } pw.println(); + if (mVisibleBgUserIds != null) { + pw.append("visibleBgUserIds=").append(mVisibleBgUserIds.toString()); + pw.println(); + } pw.append("hasWindowMagnificationConnection=").append( String.valueOf(getWindowMagnificationMgr().isConnected())); pw.println(); @@ -4052,6 +4153,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } pw.println(); mProxyManager.dump(fd, pw, args); + mA11yDisplayListener.dump(fd, pw, args); } } @@ -4437,6 +4539,20 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub /* do nothing */ } + void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Accessibility Display Listener:"); + pw.println(" SystemUI uid: " + mSystemUiUid); + int size = mDisplaysList.size(); + pw.printf(" %d valid display%s: ", size, (size == 1 ? "" : "s")); + for (int i = 0; i < size; i++) { + pw.print(mDisplaysList.get(i).getDisplayId()); + if (i < size - 1) { + pw.print(", "); + } + } + pw.println(); + } + private boolean isValidDisplay(@Nullable Display display) { if (display == null || display.getType() == Display.TYPE_OVERLAY) { return false; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java index c37ea501bbc9..88656239e59b 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java @@ -39,6 +39,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.ArraySet; import android.util.Slog; +import android.util.SparseBooleanArray; import android.view.accessibility.AccessibilityEvent; import android.view.inputmethod.InputMethodInfo; @@ -88,6 +89,12 @@ public class AccessibilitySecurityPolicy { */ int getCurrentUserIdLocked(); // TODO: Should include resolveProfileParentLocked, but that was already in SecurityPolicy + + // TODO(b/255426725): temporary hack; see comment on A11YMS.mVisibleBgUserIds + /** + * Returns the {@link android.os.UserManager#getVisibleUsers() visible users}. + */ + @Nullable SparseBooleanArray getVisibleUserIdsLocked(); } private final Context mContext; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java index baed181ebd43..a8a536590004 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java @@ -51,6 +51,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection; import com.android.internal.annotations.VisibleForTesting; import com.android.server.accessibility.AccessibilitySecurityPolicy.AccessibilityUserManager; +import com.android.server.utils.Slogf; import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; @@ -59,6 +60,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * This class provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and @@ -67,6 +69,7 @@ import java.util.List; public class AccessibilityWindowManager { private static final String LOG_TAG = "AccessibilityWindowManager"; private static final boolean DEBUG = false; + private static final boolean VERBOSE = false; private static int sNextWindowId; @@ -209,6 +212,9 @@ public class AccessibilityWindowManager { * Constructor for DisplayWindowsObserver. */ DisplayWindowsObserver(int displayId) { + if (DEBUG) { + Slogf.d(LOG_TAG, "Creating DisplayWindowsObserver for displayId %d", displayId); + } mDisplayId = displayId; } @@ -430,12 +436,27 @@ public class AccessibilityWindowManager { synchronized (mLock) { updateWindowsByWindowAttributesLocked(windows); if (DEBUG) { - Slog.i(LOG_TAG, "Display Id = " + mDisplayId); - Slog.i(LOG_TAG, "Windows changed: " + windows); + Slogf.i(LOG_TAG, "mDisplayId=%d, topFocusedDisplayId=%d, currentUserId=%d, " + + "visibleBgUsers=%s", mDisplayId, topFocusedDisplayId, + mAccessibilityUserManager.getCurrentUserIdLocked(), + mAccessibilityUserManager.getVisibleUserIdsLocked()); + if (VERBOSE) { + Slogf.i(LOG_TAG, "%d windows changed: %s ", windows.size(), windows); + } else { + List<String> windowsInfo = windows.stream() + .map(w -> "{displayId=" + w.displayId + ", title=" + w.title + "}") + .collect(Collectors.toList()); + Slogf.i(LOG_TAG, "%d windows changed: %s", windows.size(), windowsInfo); + } } if (shouldUpdateWindowsLocked(forceSend, windows)) { mTopFocusedDisplayId = topFocusedDisplayId; mTopFocusedWindowToken = topFocusedWindowToken; + if (DEBUG) { + Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): updating windows for " + + "display %d and token %s", + topFocusedDisplayId, topFocusedWindowToken); + } cacheWindows(windows); // Lets the policy update the focused and active windows. updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), @@ -443,6 +464,11 @@ public class AccessibilityWindowManager { // Someone may be waiting for the windows - advertise it. mLock.notifyAll(); } + else if (DEBUG) { + Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): NOT updating windows for " + + "display %d and token %s", + topFocusedDisplayId, topFocusedWindowToken); + } } } @@ -472,6 +498,12 @@ public class AccessibilityWindowManager { } final int windowCount = windows.size(); + if (VERBOSE) { + Slogf.v(LOG_TAG, + "shouldUpdateWindowsLocked(): mDisplayId=%d, windowCount=%d, " + + "mCachedWindowInfos.size()=%d, windows.size()=%d", mDisplayId, + windowCount, mCachedWindowInfos.size(), windows.size()); + } // We computed the windows and if they changed notify the client. if (mCachedWindowInfos.size() != windowCount) { // Different size means something changed. @@ -1274,7 +1306,7 @@ public class AccessibilityWindowManager { */ @Nullable public RemoteAccessibilityConnection getConnectionLocked(int userId, int windowId) { - if (DEBUG) { + if (VERBOSE) { Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); } RemoteAccessibilityConnection connection = mGlobalInteractionConnections.get(windowId); diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java index 2188b99a3d83..2f3e4c075a5d 100644 --- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.app.UiAutomation; import android.content.ComponentName; import android.content.Context; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; @@ -34,6 +35,7 @@ import android.view.Display; import android.view.accessibility.AccessibilityEvent; import com.android.internal.util.DumpUtils; +import com.android.server.utils.Slogf; import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; @@ -51,12 +53,8 @@ class UiAutomationManager { private UiAutomationService mUiAutomationService; - private AccessibilityServiceInfo mUiAutomationServiceInfo; - private AbstractAccessibilityServiceConnection.SystemSupport mSystemSupport; - private AccessibilityTrace mTrace; - private int mUiAutomationFlags; UiAutomationManager(Object lock) { @@ -97,9 +95,10 @@ class UiAutomationManager { WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm, int flags) { + accessibilityServiceInfo.setComponentName(COMPONENT_NAME); + Slogf.i(LOG_TAG, "Registering UiTestAutomationService (id=%s) when called by user %d", + accessibilityServiceInfo.getId(), Binder.getCallingUserHandle().getIdentifier()); synchronized (mLock) { - accessibilityServiceInfo.setComponentName(COMPONENT_NAME); - if (mUiAutomationService != null) { throw new IllegalStateException( "UiAutomationService " + mUiAutomationService.mServiceInterface @@ -116,7 +115,6 @@ class UiAutomationManager { mUiAutomationFlags = flags; mSystemSupport = systemSupport; - mTrace = trace; // Ignore registering UiAutomation if it is not allowed to use the accessibility // subsystem. if (!useAccessibility()) { @@ -126,7 +124,6 @@ class UiAutomationManager { mainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal, systemActionPerformer, awm); mUiAutomationServiceOwner = owner; - mUiAutomationServiceInfo = accessibilityServiceInfo; mUiAutomationService.mServiceInterface = serviceClient; try { mUiAutomationService.mServiceInterface.asBinder().linkToDeath(mUiAutomationService, diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 8d039fc02026..2a964b8b701f 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2073,15 +2073,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @Override public void onSaveRequestSuccess(@NonNull String servicePackageName, @Nullable IntentSender intentSender) { - // Log onSaveRequest result. - mSaveEventLogger.maybeSetIsSaved(true); - final long saveRequestFinishTimestamp = SystemClock.elapsedRealtime() - mLatencyBaseTime; - mSaveEventLogger.maybeSetLatencySaveFinishMillis(saveRequestFinishTimestamp); - mSaveEventLogger.logAndEndEvent(); - synchronized (mLock) { mSessionFlags.mShowingSaveUi = false; - + // Log onSaveRequest result. + mSaveEventLogger.maybeSetIsSaved(true); + final long saveRequestFinishTimestamp = + SystemClock.elapsedRealtime() - mLatencyBaseTime; + mSaveEventLogger.maybeSetLatencySaveFinishMillis(saveRequestFinishTimestamp); + mSaveEventLogger.logAndEndEvent(); if (mDestroyed) { Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: " + id + " destroyed"); @@ -2108,14 +2107,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @NonNull String servicePackageName) { boolean showMessage = !TextUtils.isEmpty(message); - // Log onSaveRequest result. - final long saveRequestFinishTimestamp = SystemClock.elapsedRealtime() - mLatencyBaseTime; - mSaveEventLogger.maybeSetLatencySaveFinishMillis(saveRequestFinishTimestamp); - mSaveEventLogger.logAndEndEvent(); - synchronized (mLock) { mSessionFlags.mShowingSaveUi = false; - + // Log onSaveRequest result. + final long saveRequestFinishTimestamp = + SystemClock.elapsedRealtime() - mLatencyBaseTime; + mSaveEventLogger.maybeSetLatencySaveFinishMillis(saveRequestFinishTimestamp); + mSaveEventLogger.logAndEndEvent(); if (mDestroyed) { Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: " + id + " destroyed"); @@ -2228,8 +2226,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // AutoFillUiCallback @Override public void save() { - mSaveEventLogger.maybeSetSaveButtonClicked(true); synchronized (mLock) { + mSaveEventLogger.maybeSetSaveButtonClicked(true); if (mDestroyed) { Slog.w(TAG, "Call to Session#save() rejected - session: " + id + " destroyed"); @@ -2247,10 +2245,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // AutoFillUiCallback @Override public void cancelSave() { - mSaveEventLogger.maybeSetDialogDismissed(true); synchronized (mLock) { mSessionFlags.mShowingSaveUi = false; - + mSaveEventLogger.maybeSetDialogDismissed(true); if (mDestroyed) { Slog.w(TAG, "Call to Session#cancelSave() rejected - session: " + id + " destroyed"); diff --git a/services/backup/java/com/android/server/backup/BackupAndRestoreFeatureFlags.java b/services/backup/java/com/android/server/backup/BackupAndRestoreFeatureFlags.java index 1990fe277af9..98aebddddac9 100644 --- a/services/backup/java/com/android/server/backup/BackupAndRestoreFeatureFlags.java +++ b/services/backup/java/com/android/server/backup/BackupAndRestoreFeatureFlags.java @@ -77,4 +77,19 @@ public class BackupAndRestoreFeatureFlags { /* name= */ "full_backup_utils_route_buffer_size_bytes", /* defaultValue= */ 32 * 1024); // 32 KB } + + /** + * Retrieves the value of the flag + * "unified_restore_continue_after_transport_failure_in_kv_restore". + * If true, Unified restore task will continue to next package if key-value restore of a + * package fails due to Transport-level failure. See b/128499560 for more context. + */ + @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) + public static boolean getUnifiedRestoreContinueAfterTransportFailureInKvRestore() { + return DeviceConfig.getBoolean( + NAMESPACE, + /* name= */ + "unified_restore_continue_after_transport_failure_in_kv_restore", + /* defaultValue= */ true); + } } diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 18e28de75782..1656b6f0ab9b 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -57,6 +57,7 @@ import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.backup.BackupAgentTimeoutParameters; +import com.android.server.backup.BackupAndRestoreFeatureFlags; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.BackupUtils; import com.android.server.backup.OperationStorage; @@ -168,11 +169,13 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { private final BackupEligibilityRules mBackupEligibilityRules; @VisibleForTesting - PerformUnifiedRestoreTask(UserBackupManagerService backupManagerService) { + PerformUnifiedRestoreTask( + UserBackupManagerService backupManagerService, + TransportConnection transportConnection) { mListener = null; mAgentTimeoutParameters = null; mOperationStorage = null; - mTransportConnection = null; + mTransportConnection = transportConnection; mTransportManager = null; mEphemeralOpToken = 0; mUserId = 0; @@ -731,13 +734,18 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { ParcelFileDescriptor.MODE_TRUNCATE); if (transport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) { - // Transport-level failure, so we wind everything up and - // terminate the restore operation. + // Transport-level failure. This failure could be specific to package currently in + // restore. Slog.e(TAG, "Error getting restore data for " + packageName); EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); stage.close(); downloadFile.delete(); - executeNextState(UnifiedRestoreState.FINAL); + UnifiedRestoreState nextState = + BackupAndRestoreFeatureFlags + .getUnifiedRestoreContinueAfterTransportFailureInKvRestore() + ? UnifiedRestoreState.RUNNING_QUEUE + : UnifiedRestoreState.FINAL; + executeNextState(nextState); return; } @@ -1358,6 +1366,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { executeNextState(UnifiedRestoreState.RUNNING_QUEUE); } + @VisibleForTesting void executeNextState(UnifiedRestoreState nextState) { if (MORE_DEBUG) { Slog.i(TAG, " => executing next step on " @@ -1369,6 +1378,26 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { backupManagerService.getBackupHandler().sendMessage(msg); } + @VisibleForTesting + UnifiedRestoreState getCurrentUnifiedRestoreStateForTesting() { + return mState; + } + + @VisibleForTesting + void setCurrentUnifiedRestoreStateForTesting(UnifiedRestoreState state) { + mState = state; + } + + @VisibleForTesting + void setStateDirForTesting(File stateDir) { + mStateDir = stateDir; + } + + @VisibleForTesting + void initiateOneRestoreForTesting(PackageInfo app, long appVersionCode) { + initiateOneRestore(app, appVersionCode); + } + // restore observer support void sendStartRestore(int numPackages) { if (mObserver != null) { diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 542cc2f0a0a6..d2c41a461d1c 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -19,6 +19,7 @@ package com.android.server.companion; import static android.Manifest.permission.MANAGE_COMPANION_DEVICES; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; +import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION; import static android.content.pm.PackageManager.CERT_INPUT_SHA256; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; @@ -898,12 +899,9 @@ public class CompanionDeviceManagerService extends SystemService { public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) throws RemoteException { - enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand"); - final CompanionDeviceShellCommand cmd = new CompanionDeviceShellCommand( - CompanionDeviceManagerService.this, - mAssociationStore, - mDevicePresenceMonitor); - cmd.exec(this, in, out, err, args, callback, resultReceiver); + new CompanionDeviceShellCommand(CompanionDeviceManagerService.this, mAssociationStore, + mDevicePresenceMonitor, mTransportManager) + .exec(this, in, out, err, args, callback, resultReceiver); } @Override @@ -1066,6 +1064,10 @@ public class CompanionDeviceManagerService extends SystemService { // No role was granted to for this association, there is nothing else we need to here. return true; } + // Do not need to remove the system role since it was pre-granted by the system. + if (deviceProfile.equals(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)) { + return true; + } // Check if the applications is associated with another devices with the profile. If so, // it should remain the role holder. diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java index 6889bcd63355..6de3585d8d17 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java @@ -22,6 +22,7 @@ import android.os.Binder; import android.os.ShellCommand; import com.android.server.companion.presence.CompanionDevicePresenceMonitor; +import com.android.server.companion.transport.CompanionTransportManager; import java.io.PrintWriter; import java.util.List; @@ -32,13 +33,16 @@ class CompanionDeviceShellCommand extends ShellCommand { private final CompanionDeviceManagerService mService; private final AssociationStore mAssociationStore; private final CompanionDevicePresenceMonitor mDevicePresenceMonitor; + private final CompanionTransportManager mTransportManager; CompanionDeviceShellCommand(CompanionDeviceManagerService service, AssociationStore associationStore, - CompanionDevicePresenceMonitor devicePresenceMonitor) { + CompanionDevicePresenceMonitor devicePresenceMonitor, + CompanionTransportManager transportManager) { mService = service; mAssociationStore = associationStore; mDevicePresenceMonitor = devicePresenceMonitor; + mTransportManager = transportManager; } @Override @@ -107,6 +111,12 @@ class CompanionDeviceShellCommand extends ShellCommand { } break; + case "create-dummy-transport": + // This command creates a RawTransport in order to test Transport listeners + associationId = getNextIntArgRequired(); + mTransportManager.createDummyTransport(associationId); + break; + default: return handleDefaultCommands(cmd); } @@ -165,5 +175,8 @@ class CompanionDeviceShellCommand extends ShellCommand { pw.println(" for a long time (90 days or as configured via "); pw.println(" \"debug.cdm.cdmservice.cleanup_time_window\" system property). "); pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY."); + + pw.println(" create-dummy-transport <ASSOCIATION_ID>"); + pw.println(" Create a dummy RawTransport for testing puspose only"); } } diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java index 092eb4ea9014..9677b70f4916 100644 --- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java +++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java @@ -44,6 +44,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import com.android.server.companion.AssociationStore; +import java.io.FileDescriptor; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -301,25 +302,31 @@ public class CompanionTransportManager { int sdk = Build.VERSION.SDK_INT; String release = Build.VERSION.RELEASE; - if (Build.isDebuggable()) { - // Debug builds cannot pass attestation verification. Use hardcoded key instead. + + if (sdk < SECURE_CHANNEL_AVAILABLE_SDK || remoteSdk < SECURE_CHANNEL_AVAILABLE_SDK) { + // If either device is Android T or below, use raw channel + // TODO: depending on the release version, either + // 1) using a RawTransport for old T versions + // 2) or an Ukey2 handshaked transport for UKey2 backported T versions + Slog.d(TAG, "Secure channel is not supported. Using raw transport"); + transport = new RawTransport(transport.getAssociationId(), transport.getFd(), mContext); + } else if (Build.isDebuggable()) { + // If device is debug build, use hardcoded test key for authentication Slog.d(TAG, "Creating an unauthenticated secure channel"); final byte[] testKey = "CDM".getBytes(StandardCharsets.UTF_8); transport = new SecureTransport(transport.getAssociationId(), transport.getFd(), mContext, testKey, null); - } else if (remoteSdk == NON_ANDROID) { + } else if (sdk == NON_ANDROID || remoteSdk == NON_ANDROID) { + // If either device is not Android, then use app-specific pre-shared key // TODO: pass in a real preSharedKey + Slog.d(TAG, "Creating a PSK-authenticated secure channel"); transport = new SecureTransport(transport.getAssociationId(), transport.getFd(), mContext, new byte[0], null); - } else if (sdk >= SECURE_CHANNEL_AVAILABLE_SDK - && remoteSdk >= SECURE_CHANNEL_AVAILABLE_SDK) { - Slog.i(TAG, "Creating a secure channel"); + } else { + // If none of the above applies, then use secure channel with attestation verification + Slog.d(TAG, "Creating a secure channel"); transport = new SecureTransport(transport.getAssociationId(), transport.getFd(), mContext); - } else { - // TODO: depending on the release version, either - // 1) using a RawTransport for old T versions - // 2) or an Ukey2 handshaked transport for UKey2 backported T versions } addMessageListenersToTransport(transport); transport.start(); @@ -344,6 +351,21 @@ public class CompanionTransportManager { this.mSecureTransportEnabled = enabled; } + /** + * For testing purpose only. + * + * Create a dummy RawTransport and notify onTransportChanged listeners. + */ + public void createDummyTransport(int associationId) { + synchronized (mTransports) { + FileDescriptor fd = new FileDescriptor(); + ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd); + Transport transport = new RawTransport(associationId, pfd, mContext); + mTransports.put(associationId, transport); + notifyOnTransportsChanged(); + } + } + private boolean isSecureTransportEnabled() { boolean enabled = !Build.IS_DEBUGGABLE || mSecureTransportEnabled; diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index 291c05877c17..96446422dd85 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -151,15 +151,14 @@ public class VirtualDeviceManagerService extends SystemService { } void onCameraAccessBlocked(int appUid) { - synchronized (mVirtualDeviceManagerLock) { - for (int i = 0; i < mVirtualDevices.size(); i++) { - CharSequence deviceName = mVirtualDevices.valueAt(i).getDisplayName(); - mVirtualDevices.valueAt(i).showToastWhereUidIsRunning(appUid, - getContext().getString( - com.android.internal.R.string.vdm_camera_access_denied, - deviceName), - Toast.LENGTH_LONG, Looper.myLooper()); - } + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + VirtualDeviceImpl virtualDevice = virtualDevicesSnapshot.get(i); + virtualDevice.showToastWhereUidIsRunning(appUid, + getContext().getString( + com.android.internal.R.string.vdm_camera_access_denied, + virtualDevice.getDisplayName()), + Toast.LENGTH_LONG, Looper.myLooper()); } } @@ -265,6 +264,16 @@ public class VirtualDeviceManagerService extends SystemService { cdm.removeOnAssociationsChangedListener(mCdmAssociationListener); } + private ArrayList<VirtualDeviceImpl> getVirtualDevicesSnapshot() { + synchronized (mVirtualDeviceManagerLock) { + ArrayList<VirtualDeviceImpl> virtualDevices = new ArrayList<>(mVirtualDevices.size()); + for (int i = 0; i < mVirtualDevices.size(); i++) { + virtualDevices.add(mVirtualDevices.valueAt(i)); + } + return virtualDevices; + } + } + class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub { private final VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback = @@ -314,6 +323,17 @@ public class VirtualDeviceManagerService extends SystemService { Objects.requireNonNull(activityListener); Objects.requireNonNull(soundEffectListener); + final UserHandle userHandle = getCallingUserHandle(); + final CameraAccessController cameraAccessController = + getCameraAccessController(userHandle); + final int deviceId = sNextUniqueIndex.getAndIncrement(); + final Consumer<ArraySet<Integer>> runningAppsChangedCallback = + runningUids -> notifyRunningAppsChanged(deviceId, runningUids); + VirtualDeviceImpl virtualDevice = new VirtualDeviceImpl(getContext(), + associationInfo, VirtualDeviceManagerService.this, token, callingUid, + deviceId, cameraAccessController, + mPendingTrampolineCallback, activityListener, + soundEffectListener, runningAppsChangedCallback, params); synchronized (mVirtualDeviceManagerLock) { if (mVirtualDevices.size() == 0) { final long callindId = Binder.clearCallingIdentity(); @@ -323,21 +343,9 @@ public class VirtualDeviceManagerService extends SystemService { Binder.restoreCallingIdentity(callindId); } } - - final UserHandle userHandle = getCallingUserHandle(); - final CameraAccessController cameraAccessController = - getCameraAccessController(userHandle); - final int deviceId = sNextUniqueIndex.getAndIncrement(); - final Consumer<ArraySet<Integer>> runningAppsChangedCallback = - runningUids -> notifyRunningAppsChanged(deviceId, runningUids); - VirtualDeviceImpl virtualDevice = new VirtualDeviceImpl(getContext(), - associationInfo, VirtualDeviceManagerService.this, token, callingUid, - deviceId, cameraAccessController, - mPendingTrampolineCallback, activityListener, - soundEffectListener, runningAppsChangedCallback, params); mVirtualDevices.put(deviceId, virtualDevice); - return virtualDevice; } + return virtualDevice; } @Override // Binder call @@ -399,12 +407,11 @@ public class VirtualDeviceManagerService extends SystemService { if (displayId == Display.INVALID_DISPLAY || displayId == Display.DEFAULT_DISPLAY) { return Context.DEVICE_ID_DEFAULT; } - synchronized (mVirtualDeviceManagerLock) { - for (int i = 0; i < mVirtualDevices.size(); i++) { - VirtualDeviceImpl virtualDevice = mVirtualDevices.valueAt(i); - if (virtualDevice.isDisplayOwnedByVirtualDevice(displayId)) { - return virtualDevice.getDeviceId(); - } + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + VirtualDeviceImpl virtualDevice = virtualDevicesSnapshot.get(i); + if (virtualDevice.isDisplayOwnedByVirtualDevice(displayId)) { + return virtualDevice.getDeviceId(); } } return Context.DEVICE_ID_DEFAULT; @@ -496,10 +503,9 @@ public class VirtualDeviceManagerService extends SystemService { return; } fout.println("Created virtual devices: "); - synchronized (mVirtualDeviceManagerLock) { - for (int i = 0; i < mVirtualDevices.size(); i++) { - mVirtualDevices.valueAt(i).dump(fd, fout, args); - } + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + virtualDevicesSnapshot.get(i).dump(fd, fout, args); } } } @@ -516,33 +522,30 @@ public class VirtualDeviceManagerService extends SystemService { @Override public int getDeviceOwnerUid(int deviceId) { + VirtualDeviceImpl virtualDevice; synchronized (mVirtualDeviceManagerLock) { - VirtualDeviceImpl virtualDevice = mVirtualDevices.get(deviceId); - return virtualDevice != null ? virtualDevice.getOwnerUid() : Process.INVALID_UID; + virtualDevice = mVirtualDevices.get(deviceId); } + return virtualDevice != null ? virtualDevice.getOwnerUid() : Process.INVALID_UID; } @Override public @Nullable VirtualSensor getVirtualSensor(int deviceId, int handle) { + VirtualDeviceImpl virtualDevice; synchronized (mVirtualDeviceManagerLock) { - VirtualDeviceImpl virtualDevice = mVirtualDevices.get(deviceId); - if (virtualDevice != null) { - return virtualDevice.getVirtualSensorByHandle(handle); - } + virtualDevice = mVirtualDevices.get(deviceId); } - return null; + return virtualDevice != null ? virtualDevice.getVirtualSensorByHandle(handle) : null; } @Override public @NonNull ArraySet<Integer> getDeviceIdsForUid(int uid) { + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); ArraySet<Integer> result = new ArraySet<>(); - synchronized (mVirtualDeviceManagerLock) { - int size = mVirtualDevices.size(); - for (int i = 0; i < size; i++) { - VirtualDeviceImpl device = mVirtualDevices.valueAt(i); - if (device.isAppRunningOnVirtualDevice(uid)) { - result.add(device.getDeviceId()); - } + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + VirtualDeviceImpl device = virtualDevicesSnapshot.get(i); + if (device.isAppRunningOnVirtualDevice(uid)) { + result.add(device.getDeviceId()); } } return result; @@ -630,12 +633,10 @@ public class VirtualDeviceManagerService extends SystemService { @Override public boolean isAppRunningOnAnyVirtualDevice(int uid) { - synchronized (mVirtualDeviceManagerLock) { - int size = mVirtualDevices.size(); - for (int i = 0; i < size; i++) { - if (mVirtualDevices.valueAt(i).isAppRunningOnVirtualDevice(uid)) { - return true; - } + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + if (virtualDevicesSnapshot.get(i).isAppRunningOnVirtualDevice(uid)) { + return true; } } return false; @@ -643,12 +644,10 @@ public class VirtualDeviceManagerService extends SystemService { @Override public boolean isDisplayOwnedByAnyVirtualDevice(int displayId) { - synchronized (mVirtualDeviceManagerLock) { - int size = mVirtualDevices.size(); - for (int i = 0; i < size; i++) { - if (mVirtualDevices.valueAt(i).isDisplayOwnedByVirtualDevice(displayId)) { - return true; - } + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + if (virtualDevicesSnapshot.get(i).isDisplayOwnedByVirtualDevice(displayId)) { + return true; } } return false; diff --git a/services/core/Android.bp b/services/core/Android.bp index c8caab93d76c..cfdf3ac5915b 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -174,7 +174,6 @@ java_library_static { "android.hardware.configstore-V1.1-java", "android.hardware.ir-V1-java", "android.hardware.rebootescrow-V1-java", - "android.hardware.soundtrigger-V2.3-java", "android.hardware.power.stats-V2-java", "android.hardware.power-V4-java", "android.hidl.manager-V1.2-java", diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java index c6f63dd73a25..12ee13183221 100644 --- a/services/core/java/android/os/BatteryStatsInternal.java +++ b/services/core/java/android/os/BatteryStatsInternal.java @@ -39,12 +39,14 @@ public abstract class BatteryStatsInternal { public static final int CPU_WAKEUP_SUBSYSTEM_UNKNOWN = -1; public static final int CPU_WAKEUP_SUBSYSTEM_ALARM = 1; public static final int CPU_WAKEUP_SUBSYSTEM_WIFI = 2; + public static final int CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER = 3; /** @hide */ @IntDef(prefix = {"CPU_WAKEUP_SUBSYSTEM_"}, value = { CPU_WAKEUP_SUBSYSTEM_UNKNOWN, CPU_WAKEUP_SUBSYSTEM_ALARM, CPU_WAKEUP_SUBSYSTEM_WIFI, + CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER, }) @Retention(RetentionPolicy.SOURCE) @interface CpuWakeupSubsystem { diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java index 3ecf93328219..8fc30e43d1a0 100644 --- a/services/core/java/com/android/server/BinaryTransparencyService.java +++ b/services/core/java/com/android/server/BinaryTransparencyService.java @@ -80,7 +80,7 @@ import android.util.apk.ApkSignatureVerifier; import android.util.apk.ApkSigningBlockUtils; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.expresslog.Histogram; +import com.android.modules.expresslog.Histogram; import com.android.internal.os.IBinaryTransparencyService; import com.android.internal.util.FrameworkStatsLog; import com.android.server.pm.ApexManager; diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java index 3487613d313c..5156c541011f 100644 --- a/services/core/java/com/android/server/DockObserver.java +++ b/services/core/java/com/android/server/DockObserver.java @@ -70,7 +70,7 @@ final class DockObserver extends SystemService { private boolean mUpdatesStopped; - private final boolean mKeepDreamingWhenUndocking; + private final boolean mKeepDreamingWhenUnplugging; private final boolean mAllowTheaterModeWakeFromDock; private final List<ExtconStateConfig> mExtconStateConfigs; @@ -167,8 +167,8 @@ final class DockObserver extends SystemService { mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mAllowTheaterModeWakeFromDock = context.getResources().getBoolean( com.android.internal.R.bool.config_allowTheaterModeWakeFromDock); - mKeepDreamingWhenUndocking = context.getResources().getBoolean( - com.android.internal.R.bool.config_keepDreamingWhenUndocking); + mKeepDreamingWhenUnplugging = context.getResources().getBoolean( + com.android.internal.R.bool.config_keepDreamingWhenUnplugging); mDeviceProvisionedObserver = new DeviceProvisionedObserver(mHandler); mExtconStateConfigs = loadExtconStateConfigs(context); @@ -237,7 +237,7 @@ final class DockObserver extends SystemService { } private boolean allowWakeFromDock() { - if (mKeepDreamingWhenUndocking) { + if (mKeepDreamingWhenUnplugging) { return false; } return (mAllowTheaterModeWakeFromDock diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 409f0541eed7..123cd3288343 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -27,6 +27,7 @@ per-file **IpSec* = file:/services/core/java/com/android/server/net/OWNERS per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS +per-file *SoundTrigger* = file:/media/java/android/media/soundtrigger/OWNERS per-file *Storage* = file:/core/java/android/os/storage/OWNERS per-file *TimeUpdate* = file:/services/core/java/com/android/server/timezonedetector/OWNERS per-file DynamicSystemService.java = file:/packages/DynamicSystemInstallationService/OWNERS diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 92889c05d9f4..d256aead97e8 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -426,7 +426,7 @@ public class PackageWatchdog { } int impact = registeredObserver.onHealthCheckFailed( versionedPackage, failureReason, mitigationCount); - if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE + if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0 && impact < currentObserverImpact) { currentObserverToNotify = registeredObserver; currentObserverImpact = impact; @@ -466,7 +466,7 @@ public class PackageWatchdog { if (registeredObserver != null) { int impact = registeredObserver.onHealthCheckFailed( failingPackage, failureReason, 1); - if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE + if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0 && impact < currentObserverImpact) { currentObserverToNotify = registeredObserver; currentObserverImpact = impact; @@ -494,7 +494,7 @@ public class PackageWatchdog { PackageHealthObserver registeredObserver = observer.registeredObserver; if (registeredObserver != null) { int impact = registeredObserver.onBootLoop(mitigationCount); - if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE + if (impact != PackageHealthObserverImpact.USER_IMPACT_LEVEL_0 && impact < currentObserverImpact) { currentObserverToNotify = registeredObserver; currentObserverImpact = impact; @@ -576,19 +576,23 @@ public class PackageWatchdog { /** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */ @Retention(SOURCE) - @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_NONE, - PackageHealthObserverImpact.USER_IMPACT_LOW, - PackageHealthObserverImpact.USER_IMPACT_MEDIUM, - PackageHealthObserverImpact.USER_IMPACT_HIGH}) + @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_LEVEL_0, + PackageHealthObserverImpact.USER_IMPACT_LEVEL_10, + PackageHealthObserverImpact.USER_IMPACT_LEVEL_30, + PackageHealthObserverImpact.USER_IMPACT_LEVEL_50, + PackageHealthObserverImpact.USER_IMPACT_LEVEL_70, + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100}) public @interface PackageHealthObserverImpact { /** No action to take. */ - int USER_IMPACT_NONE = 0; + int USER_IMPACT_LEVEL_0 = 0; /* Action has low user impact, user of a device will barely notice. */ - int USER_IMPACT_LOW = 1; - /* Action has medium user impact, user of a device will likely notice. */ - int USER_IMPACT_MEDIUM = 3; + int USER_IMPACT_LEVEL_10 = 10; + /* Actions having medium user impact, user of a device will likely notice. */ + int USER_IMPACT_LEVEL_30 = 30; + int USER_IMPACT_LEVEL_50 = 50; + int USER_IMPACT_LEVEL_70 = 70; /* Action has high user impact, a last resort, user of a device will be very frustrated. */ - int USER_IMPACT_HIGH = 5; + int USER_IMPACT_LEVEL_100 = 100; } /** Register instances of this interface to receive notifications on package failure. */ @@ -633,7 +637,7 @@ public class PackageWatchdog { * boot loop (including this time). */ default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) { - return PackageHealthObserverImpact.USER_IMPACT_NONE; + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; } /** diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index c5eb25b9981e..3fd6fe8afba6 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -26,8 +26,8 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.IActivityManager; -import android.app.IUidObserver; import android.app.SearchManager; +import android.app.UidObserver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -360,35 +360,18 @@ public final class PinnerService extends SystemService { private void registerUidListener() { try { - mAm.registerUidObserver(new IUidObserver.Stub() { + mAm.registerUidObserver(new UidObserver() { @Override - public void onUidGone(int uid, boolean disabled) throws RemoteException { + public void onUidGone(int uid, boolean disabled) { mPinnerHandler.sendMessage(PooledLambda.obtainMessage( PinnerService::handleUidGone, PinnerService.this, uid)); } @Override - public void onUidActive(int uid) throws RemoteException { + public void onUidActive(int uid) { mPinnerHandler.sendMessage(PooledLambda.obtainMessage( PinnerService::handleUidActive, PinnerService.this, uid)); } - - @Override - public void onUidIdle(int uid, boolean disabled) throws RemoteException { - } - - @Override - public void onUidStateChanged(int uid, int procState, long procStateSeq, - int capability) throws RemoteException { - } - - @Override - public void onUidCachedChanged(int uid, boolean cached) throws RemoteException { - } - - @Override - public void onUidProcAdjChanged(int uid) throws RemoteException { - } }, UID_OBSERVER_GONE | UID_OBSERVER_ACTIVE, 0, null); } catch (RemoteException e) { Slog.e(TAG, "Failed to register uid observer", e); diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index 3de65f94decf..6e2e5f75b8f3 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -107,7 +107,7 @@ public class RescueParty { static final String NAMESPACE_TO_PACKAGE_MAPPING_FLAG = "namespace_to_package_mapping"; @VisibleForTesting - static final long FACTORY_RESET_THROTTLE_DURATION_MS = TimeUnit.MINUTES.toMillis(10); + static final long DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN = 10; private static final String NAME = "rescue-party-observer"; @@ -117,6 +117,8 @@ public class RescueParty { "persist.device_config.configuration.disable_rescue_party"; private static final String PROP_DISABLE_FACTORY_RESET_FLAG = "persist.device_config.configuration.disable_rescue_party_factory_reset"; + private static final String PROP_THROTTLE_DURATION_MIN_FLAG = + "persist.device_config.configuration.rescue_party_throttle_duration_min"; private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT | ApplicationInfo.FLAG_SYSTEM; @@ -489,13 +491,14 @@ public class RescueParty { switch(rescueLevel) { case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: - return PackageHealthObserverImpact.USER_IMPACT_LOW; + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_10; case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: case LEVEL_WARM_REBOOT: + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_50; case LEVEL_FACTORY_RESET: - return PackageHealthObserverImpact.USER_IMPACT_HIGH; + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_100; default: - return PackageHealthObserverImpact.USER_IMPACT_NONE; + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; } } @@ -633,7 +636,7 @@ public class RescueParty { return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, mayPerformReboot(failedPackage))); } else { - return PackageHealthObserverImpact.USER_IMPACT_NONE; + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; } } @@ -677,7 +680,7 @@ public class RescueParty { @Override public int onBootLoop(int mitigationCount) { if (isDisabled()) { - return PackageHealthObserverImpact.USER_IMPACT_NONE; + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; } return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true)); } @@ -721,7 +724,9 @@ public class RescueParty { private boolean shouldThrottleReboot() { Long lastResetTime = SystemProperties.getLong(PROP_LAST_FACTORY_RESET_TIME_MS, 0); long now = System.currentTimeMillis(); - return now < lastResetTime + FACTORY_RESET_THROTTLE_DURATION_MS; + long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG, + DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN); + return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin); } private boolean isPersistentSystemApp(@NonNull String packageName) { diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/core/java/com/android/server/SoundTriggerInternal.java index cc398d930c7e..e6c1750c4a1d 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java +++ b/services/core/java/com/android/server/SoundTriggerInternal.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.soundtrigger; +package com.android.server; import android.annotation.NonNull; import android.annotation.Nullable; @@ -29,15 +29,13 @@ import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; import android.media.permission.Identity; import android.os.IBinder; -import com.android.server.voiceinteraction.VoiceInteractionManagerService; - import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.List; /** * Provides a local service for managing voice-related recoginition models. This is primarily used - * by the {@link VoiceInteractionManagerService}. + * by the {@code VoiceInteractionManagerService}. */ public interface SoundTriggerInternal { /** diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 78cbf2bd80d8..6adccf677bc7 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -26,6 +26,17 @@ import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT; import static android.app.ActivityManager.PROCESS_STATE_RECEIVER; import static android.app.ActivityManager.PROCESS_STATE_TOP; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BIND_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_COMPONENT_DISABLED; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_EXECUTING_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_NONE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_END; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_TASK; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_STOP_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UID_IDLE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UNBIND_SERVICE; import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_DEPRECATED; import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_DISABLED; import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_OK; @@ -88,6 +99,7 @@ import static com.android.internal.messages.nano.SystemMessageProto.SystemMessag import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED; import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER; import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED; @@ -116,6 +128,7 @@ import android.annotation.UptimeMillisLong; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; +import android.app.ActivityManagerInternal.OomAdjReason; import android.app.ActivityManagerInternal.ServiceNotificationPolicy; import android.app.ActivityThread; import android.app.AppGlobals; @@ -1006,6 +1019,24 @@ public final class ActiveServices { r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), service, neededGrants, callingUid, callingProcessName, callingPackage)); + // 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. + final boolean isFgs = r.isForeground || r.fgRequired; + if (isFgs) { + // 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. + // Use that as a shortcut if possible to avoid having to recheck all the conditions. + final boolean whileInUseAllowsUiJobScheduling = + ActivityManagerService.doesReasonCodeAllowSchedulingUserInitiatedJobs( + r.mAllowWhileInUsePermissionInFgsReason); + r.updateAllowUiJobScheduling(whileInUseAllowsUiJobScheduling + || mAm.canScheduleUserInitiatedJobs(callingUid, callingPid, callingPackage)); + } else { + r.updateAllowUiJobScheduling(false); + } + if (fgRequired) { // We are now effectively running a foreground service. synchronized (mAm.mProcessStats.mLock) { @@ -1145,7 +1176,7 @@ public final class ActiveServices { } finally { /* Will be a no-op if nothing pending */ mAm.updateOomAdjPendingTargetsLocked( - OomAdjuster.OOM_ADJ_REASON_START_SERVICE); + OOM_ADJ_REASON_START_SERVICE); } } else { unbindServiceLocked(connection); @@ -1235,8 +1266,7 @@ public final class ActiveServices { /* ignore - local call */ } finally { /* Will be a no-op if nothing pending */ - mAm.updateOomAdjPendingTargetsLocked( - OomAdjuster.OOM_ADJ_REASON_START_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE); } } else { // Starting a service try { @@ -1310,7 +1340,7 @@ public final class ActiveServices { false /* packageFrozen */, true /* enqueueOomAdj */); /* Will be a no-op if nothing pending */ - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE); if (error != null) { return new ComponentName("!!", error); } @@ -1495,7 +1525,7 @@ public final class ActiveServices { stopServiceLocked(service, true); } if (size > 0) { - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_UID_IDLE); } } } @@ -3240,6 +3270,12 @@ public final class ActiveServices { return; } Slog.e(TAG_SERVICE, "Short FGS timed out: " + sr); + final long now = SystemClock.uptimeMillis(); + logFGSStateChangeLocked(sr, + FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, + now > sr.mFgsEnterTime ? (int) (now - sr.mFgsEnterTime) : 0, + FGS_STOP_REASON_UNKNOWN, + FGS_TYPE_POLICY_CHECK_UNKNOWN); try { sr.app.getThread().scheduleTimeoutService(sr, sr.getShortFgsInfo().getStartId()); } catch (RemoteException e) { @@ -3289,7 +3325,7 @@ public final class ActiveServices { Slog.e(TAG_SERVICE, "Short FGS procstate demoted: " + sr); - mAm.updateOomAdjLocked(sr.app, OomAdjuster.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT); + mAm.updateOomAdjLocked(sr.app, OOM_ADJ_REASON_SHORT_FGS_TIMEOUT); } } @@ -3623,7 +3659,7 @@ public final class ActiveServices { needOomAdj = true; if (bringUpServiceLocked(s, service.getFlags(), callerFg, false, permissionsReviewRequired, packageFrozen, true) != null) { - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_BIND_SERVICE); return 0; } } @@ -3648,7 +3684,7 @@ public final class ActiveServices { mAm.enqueueOomAdjTargetLocked(s.app); } if (needOomAdj) { - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_BIND_SERVICE); } final int packageState = wasStopped @@ -3780,7 +3816,8 @@ public final class ActiveServices { } } - serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false); + serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false, + OOM_ADJ_REASON_EXECUTING_SERVICE); } } finally { Binder.restoreCallingIdentity(origId); @@ -3871,7 +3908,7 @@ public final class ActiveServices { } } - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_UNBIND_SERVICE); } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -3918,7 +3955,8 @@ public final class ActiveServices { } } - serviceDoneExecutingLocked(r, inDestroying, false, false); + serviceDoneExecutingLocked(r, inDestroying, false, false, + OOM_ADJ_REASON_UNBIND_SERVICE); } } finally { Binder.restoreCallingIdentity(origId); @@ -4353,11 +4391,11 @@ public final class ActiveServices { /** * Bump the given service record into executing state. * @param oomAdjReason The caller requests it to perform the oomAdjUpdate not {@link - * OomAdjuster#OOM_ADJ_REASON_NONE}. + * ActivityManagerInternal#OOM_ADJ_REASON_NONE}. * @return {@code true} if it performed oomAdjUpdate. */ private boolean bumpServiceExecutingLocked( - ServiceRecord r, boolean fg, String why, @OomAdjuster.OomAdjReason int oomAdjReason) { + ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING " + why + " of " + r + " in app " + r.app); else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING " @@ -4409,7 +4447,7 @@ public final class ActiveServices { } } boolean oomAdjusted = false; - if (oomAdjReason != OomAdjuster.OOM_ADJ_REASON_NONE && r.app != null + if (oomAdjReason != OOM_ADJ_REASON_NONE && r.app != null && r.app.mState.getCurProcState() > ActivityManager.PROCESS_STATE_SERVICE) { // Force an immediate oomAdjUpdate, so the client app could be in the correct process // state before doing any service related transactions @@ -4433,8 +4471,7 @@ public final class ActiveServices { + " rebind=" + rebind); if ((!i.requested || rebind) && i.apps.size() > 0) { try { - bumpServiceExecutingLocked(r, execInFg, "bind", - OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE); + bumpServiceExecutingLocked(r, execInFg, "bind", OOM_ADJ_REASON_BIND_SERVICE); if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestServiceBinding=" + i.intent.getIntent() + ". bindSeq=" + mBindServiceSeqCounter); @@ -4450,13 +4487,15 @@ public final class ActiveServices { // Keep the executeNesting count accurate. if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e); final boolean inDestroying = mDestroyingServices.contains(r); - serviceDoneExecutingLocked(r, inDestroying, inDestroying, false); + serviceDoneExecutingLocked(r, inDestroying, inDestroying, false, + OOM_ADJ_REASON_UNBIND_SERVICE); throw e; } catch (RemoteException e) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r); // Keep the executeNesting count accurate. final boolean inDestroying = mDestroyingServices.contains(r); - serviceDoneExecutingLocked(r, inDestroying, inDestroying, false); + serviceDoneExecutingLocked(r, inDestroying, inDestroying, false, + OOM_ADJ_REASON_UNBIND_SERVICE); return false; } } @@ -4834,7 +4873,7 @@ public final class ActiveServices { // Ignore, it's been logged and nothing upstack cares. } finally { /* Will be a no-op if nothing pending */ - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE); } } @@ -5186,13 +5225,14 @@ public final class ActiveServices { final ProcessServiceRecord psr = app.mServices; final boolean newService = psr.startService(r); - bumpServiceExecutingLocked(r, execInFg, "create", OomAdjuster.OOM_ADJ_REASON_NONE); + bumpServiceExecutingLocked(r, execInFg, "create", + OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */); mAm.updateLruProcessLocked(app, false, null); updateServiceForegroundLocked(psr, /* oomAdj= */ false); // Force an immediate oomAdjUpdate, so the client app could be in the correct process state // before doing any service related transactions mAm.enqueueOomAdjTargetLocked(app); - mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE); + mAm.updateOomAdjLocked(app, OOM_ADJ_REASON_START_SERVICE); boolean created = false; try { @@ -5226,7 +5266,8 @@ public final class ActiveServices { if (!created) { // Keep the executeNesting count accurate. final boolean inDestroying = mDestroyingServices.contains(r); - serviceDoneExecutingLocked(r, inDestroying, inDestroying, false); + serviceDoneExecutingLocked(r, inDestroying, inDestroying, false, + OOM_ADJ_REASON_STOP_SERVICE); // Cleanup. if (newService) { @@ -5312,7 +5353,8 @@ public final class ActiveServices { mAm.grantImplicitAccess(r.userId, si.intent, si.callingId, UserHandle.getAppId(r.appInfo.uid) ); - bumpServiceExecutingLocked(r, execInFg, "start", OomAdjuster.OOM_ADJ_REASON_NONE); + bumpServiceExecutingLocked(r, execInFg, "start", + OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */); if (r.fgRequired && !r.fgWaiting) { if (!r.isForeground) { if (DEBUG_BACKGROUND_CHECK) { @@ -5338,7 +5380,7 @@ public final class ActiveServices { if (!oomAdjusted) { mAm.enqueueOomAdjTargetLocked(r.app); - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE); } ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args); slice.setInlineCountLimit(4); @@ -5364,10 +5406,11 @@ public final class ActiveServices { // Keep nesting count correct final boolean inDestroying = mDestroyingServices.contains(r); for (int i = 0, size = args.size(); i < size; i++) { - serviceDoneExecutingLocked(r, inDestroying, inDestroying, true); + serviceDoneExecutingLocked(r, inDestroying, inDestroying, true, + OOM_ADJ_REASON_STOP_SERVICE); } /* Will be a no-op if nothing pending */ - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_STOP_SERVICE); if (caughtException instanceof TransactionTooLargeException) { throw (TransactionTooLargeException)caughtException; } @@ -5454,7 +5497,7 @@ public final class ActiveServices { if (ibr.hasBound) { try { oomAdjusted |= bumpServiceExecutingLocked(r, false, "bring down unbind", - OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + OOM_ADJ_REASON_UNBIND_SERVICE); ibr.hasBound = false; ibr.requested = false; r.app.getThread().scheduleUnbindService(r, @@ -5608,7 +5651,7 @@ public final class ActiveServices { } else { try { oomAdjusted |= bumpServiceExecutingLocked(r, false, "destroy", - oomAdjusted ? 0 : OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + oomAdjusted ? 0 : OOM_ADJ_REASON_STOP_SERVICE); mDestroyingServices.add(r); r.destroying = true; r.app.getThread().scheduleStopService(r); @@ -5630,7 +5673,7 @@ public final class ActiveServices { if (!oomAdjusted) { mAm.enqueueOomAdjTargetLocked(r.app); if (!enqueueOomAdj) { - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_STOP_SERVICE); } } if (r.bindings.size() > 0) { @@ -5755,8 +5798,7 @@ public final class ActiveServices { if (s.app != null && s.app.getThread() != null && b.intent.apps.size() == 0 && b.intent.hasBound) { try { - bumpServiceExecutingLocked(s, false, "unbind", - OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + bumpServiceExecutingLocked(s, false, "unbind", OOM_ADJ_REASON_UNBIND_SERVICE); if (b.client != s.app && c.notHasFlag(Context.BIND_WAIVE_PRIORITY) && s.app.mState.getSetProcState() <= PROCESS_STATE_HEAVY_WEIGHT) { // If this service's process is not already in the cached list, @@ -5879,7 +5921,8 @@ public final class ActiveServices { } } final long origId = Binder.clearCallingIdentity(); - serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj); + serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj, + OOM_ADJ_REASON_EXECUTING_SERVICE); Binder.restoreCallingIdentity(origId); } else { Slog.w(TAG, "Done executing unknown service from pid " @@ -5898,11 +5941,11 @@ public final class ActiveServices { r.tracker.setStarted(false, memFactor, now); } } - serviceDoneExecutingLocked(r, true, true, enqueueOomAdj); + serviceDoneExecutingLocked(r, true, true, enqueueOomAdj, OOM_ADJ_REASON_PROCESS_END); } private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, - boolean finishing, boolean enqueueOomAdj) { + boolean finishing, boolean enqueueOomAdj, @OomAdjReason int oomAdjReason) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r + ": nesting=" + r.executeNesting + ", inDestroying=" + inDestroying + ", app=" + r.app); @@ -5938,7 +5981,7 @@ public final class ActiveServices { if (enqueueOomAdj) { mAm.enqueueOomAdjTargetLocked(r.app); } else { - mAm.updateOomAdjLocked(r.app, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjLocked(r.app, oomAdjReason); } } r.executeFg = false; @@ -6008,7 +6051,7 @@ public final class ActiveServices { bringDownServiceLocked(sr, true); } /* Will be a no-op if nothing pending */ - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE); } } catch (RemoteException e) { Slog.w(TAG, "Exception in new application when starting service " @@ -6068,7 +6111,7 @@ public final class ActiveServices { } } if (needOomAdj) { - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_PROCESS_END); } } @@ -6139,7 +6182,7 @@ public final class ActiveServices { bringDownServiceLocked(mTmpCollectionResults.get(i), true); } if (size > 0) { - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_COMPONENT_DISABLED); } if (fullStop && !mTmpCollectionResults.isEmpty()) { // if we're tearing down the app's entire service state, account for possible @@ -6266,7 +6309,7 @@ public final class ActiveServices { } } if (needOomAdj) { - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_REMOVE_TASK); } } @@ -6437,7 +6480,7 @@ public final class ActiveServices { } } - mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_STOP_SERVICE); if (!allowRestart) { psr.stopAllServices(); @@ -7215,47 +7258,52 @@ public final class ActiveServices { */ protected boolean dumpService(FileDescriptor fd, PrintWriter pw, String name, int[] users, String[] args, int opti, boolean dumpAll) { - final ArrayList<ServiceRecord> services = new ArrayList<>(); - - final Predicate<ServiceRecord> filter = DumpUtils.filterRecord(name); + try { + mAm.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false); + final ArrayList<ServiceRecord> services = new ArrayList<>(); - synchronized (mAm) { - if (users == null) { - users = mAm.mUserController.getUsers(); - } + final Predicate<ServiceRecord> filter = DumpUtils.filterRecord(name); - for (int user : users) { - ServiceMap smap = mServiceMap.get(user); - if (smap == null) { - continue; + synchronized (mAm) { + if (users == null) { + users = mAm.mUserController.getUsers(); } - ArrayMap<ComponentName, ServiceRecord> alls = smap.mServicesByInstanceName; - for (int i=0; i<alls.size(); i++) { - ServiceRecord r1 = alls.valueAt(i); - if (filter.test(r1)) { - services.add(r1); + for (int user : users) { + ServiceMap smap = mServiceMap.get(user); + if (smap == null) { + continue; + } + ArrayMap<ComponentName, ServiceRecord> alls = smap.mServicesByInstanceName; + for (int i=0; i<alls.size(); i++) { + ServiceRecord r1 = alls.valueAt(i); + + if (filter.test(r1)) { + services.add(r1); + } } } } - } - if (services.size() <= 0) { - return false; - } + if (services.size() <= 0) { + return false; + } - // Sort by component name. - services.sort(Comparator.comparing(WithComponentName::getComponentName)); + // Sort by component name. + services.sort(Comparator.comparing(WithComponentName::getComponentName)); - boolean needSep = false; - for (int i=0; i<services.size(); i++) { - if (needSep) { - pw.println(); + boolean needSep = false; + for (int i=0; i<services.size(); i++) { + if (needSep) { + pw.println(); + } + needSep = true; + dumpService("", fd, pw, services.get(i), args, dumpAll); } - needSep = true; - dumpService("", fd, pw, services.get(i), args, dumpAll); + return true; + } finally { + mAm.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true); } - return true; } /** @@ -7337,26 +7385,12 @@ public final class ActiveServices { } 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); - } + r.mAllowWhileInUsePermissionInFgsReason = allowWhileInUse; } void resetFgsRestrictionLocked(ServiceRecord r) { r.mAllowWhileInUsePermissionInFgs = false; + r.mAllowWhileInUsePermissionInFgsReason = REASON_DENIED; r.mAllowStartForeground = REASON_DENIED; r.mInfoAllowStartForeground = null; r.mInfoTempFgsAllowListReason = null; @@ -7400,14 +7434,17 @@ public final class ActiveServices { final int uidState = mAm.getUidStateLocked(callingUid); if (ret == REASON_DENIED) { - // Is the calling UID at PROCESS_STATE_TOP or above? + // Allow FGS while-in-use if the caller's process state is PROCESS_STATE_PERSISTENT, + // PROCESS_STATE_PERSISTENT_UI or PROCESS_STATE_TOP. if (uidState <= PROCESS_STATE_TOP) { ret = getReasonCodeFromProcState(uidState); } } if (ret == REASON_DENIED) { - // Does the calling UID have any visible activity? + // Allow FGS while-in-use if the caller has visible activity. + // Here we directly check ActivityTaskManagerService, instead of checking + // PendingStartActivityUids in ActivityManagerService, which gives the same result. final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid); if (isCallingUidVisible) { ret = REASON_UID_VISIBLE; @@ -7415,7 +7452,8 @@ public final class ActiveServices { } if (ret == REASON_DENIED) { - // Is the allow activity background start flag on? + // Allow FGS while-in-use if the background activity start flag is on. Because + // activity start can lead to FGS start in TOP state and obtain while-in-use. if (backgroundStartPrivileges.allowsBackgroundActivityStarts()) { ret = REASON_START_ACTIVITY_FLAG; } @@ -7424,6 +7462,7 @@ public final class ActiveServices { if (ret == REASON_DENIED) { boolean isCallerSystem = false; final int callingAppId = UserHandle.getAppId(callingUid); + // Allow FGS while-in-use for a list of special UIDs. switch (callingAppId) { case ROOT_UID: case SYSTEM_UID: @@ -7442,6 +7481,10 @@ public final class ActiveServices { } if (ret == REASON_DENIED) { + // Allow FGS while-in-use if the WindowManager allows background activity start. + // This is mainly to get the 10 seconds grace period if any activity in the caller has + // either started or finished very recently. The binding flag + // BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS is also allowed by the check here. final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, pr -> { if (pr.uid == callingUid) { if (pr.getWindowProcessController().areBackgroundFgsStartsAllowed()) { @@ -7456,6 +7499,12 @@ public final class ActiveServices { } if (ret == REASON_DENIED) { + // Allow FGS while-in-use if the caller UID is in ActivityManagerService's + // mFgsWhileInUseTempAllowList. This is a temp allowlist to allow FGS while-in-use. It + // is used when MediaSessionService's bluetooth button or play/resume/stop commands are + // issued. The typical temp allowlist duration is 10 seconds. + // This temp allowlist mechanism can also be called by other system_server internal + // components such as Telephone/VOIP if they want to start a FGS and get while-in-use. if (mAm.mInternal.isTempAllowlistedForFgsWhileInUse(callingUid)) { return REASON_TEMP_ALLOWED_WHILE_IN_USE; } @@ -7463,6 +7512,8 @@ public final class ActiveServices { if (ret == REASON_DENIED) { if (targetProcess != null) { + // Allow FGS while-in-use if the caller of the instrumentation has + // START_ACTIVITIES_FROM_BACKGROUND permission. ActiveInstrumentation instr = targetProcess.getActiveInstrumentation(); if (instr != null && instr.mHasBackgroundActivityStartsPermission) { ret = REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION; @@ -7471,6 +7522,9 @@ public final class ActiveServices { } if (ret == REASON_DENIED) { + // Allow FGS while-in-use if the caller has START_ACTIVITIES_FROM_BACKGROUND + // permission, because starting an activity can lead to starting FGS from the TOP state + // and obtain while-in-use. if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid) == PERMISSION_GRANTED) { ret = REASON_BACKGROUND_ACTIVITY_PERMISSION; @@ -7478,6 +7532,8 @@ public final class ActiveServices { } if (ret == REASON_DENIED) { + // Allow FGS while-in-use if the caller is in the while-in-use allowlist. Right now + // AttentionService and SystemCaptionsService packageName are in this allowlist. if (verifyPackage(callingPackage, callingUid)) { final boolean isAllowedPackage = mAllowListWhileInUsePermissionInFgs.contains(callingPackage); @@ -7492,7 +7548,7 @@ public final class ActiveServices { } if (ret == REASON_DENIED) { - // Is the calling UID a device owner app? + // Allow FGS while-in-use if the caller is the device owner. final boolean isDeviceOwner = mAm.mInternal.isDeviceOwner(callingUid); if (isDeviceOwner) { ret = REASON_DEVICE_OWNER; @@ -7897,7 +7953,8 @@ public final class ActiveServices { boolean allowWhileInUsePermissionInFgs; @PowerExemptionManager.ReasonCode int fgsStartReasonCode; if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER - || state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT) { + || state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT + || state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT) { allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgsAtEntering; fgsStartReasonCode = r.mAllowStartForegroundAtEntering; } else { @@ -7931,9 +7988,9 @@ public final class ActiveServices { r.mFgsDelegation != null ? r.mFgsDelegation.mOptions.mClientUid : INVALID_UID, r.mFgsDelegation != null ? r.mFgsDelegation.mOptions.mDelegationService : ForegroundServiceDelegationOptions.DELEGATION_SERVICE_DEFAULT, - 0, - null, - null); + 0 /* api_sate */, + null /* api_type */, + null /* api_timestamp */); int event = 0; if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) { @@ -7942,7 +7999,9 @@ public final class ActiveServices { event = EventLogTags.AM_FOREGROUND_SERVICE_STOP; } else if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED) { event = EventLogTags.AM_FOREGROUND_SERVICE_DENIED; - } else { + } else if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT) { + event = EventLogTags.AM_FOREGROUND_SERVICE_TIMED_OUT; + }else { // Unknown event. return; } diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index ae5dbe11495a..44e198b53761 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -213,7 +213,7 @@ final class ActivityManagerConstants extends ContentObserver { private static final boolean DEFAULT_USE_TIERED_CACHED_ADJ = false; private static final long DEFAULT_TIERED_CACHED_ADJ_DECAY_TIME = 60 * 1000; - private static final boolean DEFAULT_USE_MODERN_TRIM = false; + private static final boolean DEFAULT_USE_MODERN_TRIM = true; /** * Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ef7d5ae43396..97d34b8dd718 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -44,6 +44,14 @@ 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; import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_BEGIN; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_END; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHELL; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SYSTEM_INIT; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT; @@ -199,6 +207,7 @@ import android.app.ActivityManagerInternal.BindServiceEventListener; import android.app.ActivityManagerInternal.BroadcastEventListener; import android.app.ActivityManagerInternal.ForegroundServiceStateListener; import android.app.ActivityManagerInternal.MediaProjectionTokenEvent; +import android.app.ActivityManagerInternal.OomAdjReason; import android.app.ActivityTaskManager.RootTaskInfo; import android.app.ActivityThread; import android.app.AnrController; @@ -368,7 +377,6 @@ import android.util.FeatureFlagUtils; import android.util.IndentingPrintWriter; import android.util.IntArray; import android.util.Log; -import android.util.LogWriter; import android.util.Pair; import android.util.PrintWriterPrinter; import android.util.Slog; @@ -1968,7 +1976,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM); addPidLocked(app); updateLruProcessLocked(app, false, null); - updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + updateOomAdjLocked(OOM_ADJ_REASON_SYSTEM_INIT); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( @@ -2502,7 +2510,7 @@ public class ActivityManagerService extends IActivityManager.Stub // bind background threads to little cores // this is expected to fail inside of framework tests because apps can't touch cpusets directly // make sure we've already adjusted system_server's internal view of itself first - updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + updateOomAdjLocked(OOM_ADJ_REASON_SYSTEM_INIT); try { Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(), Process.THREAD_GROUP_SYSTEM); @@ -3387,7 +3395,7 @@ public class ActivityManagerService extends IActivityManager.Stub handleAppDiedLocked(app, pid, false, true, fromBinderDied); if (doOomAdj) { - updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); + updateOomAdjLocked(OOM_ADJ_REASON_PROCESS_END); } if (doLowMem) { mAppProfiler.doLowMemReportIfNeededLocked(app); @@ -4843,7 +4851,7 @@ public class ActivityManagerService extends IActivityManager.Stub } if (!didSomething) { - updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); + updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN); checkTime(startTime, "finishAttachApplicationInner: after updateOomAdjLocked"); } @@ -5485,7 +5493,7 @@ public class ActivityManagerService extends IActivityManager.Stub "setProcessLimit()"); synchronized (this) { mConstants.setOverrideMaxCachedProcesses(max); - trimApplicationsLocked(true, OomAdjuster.OOM_ADJ_REASON_PROCESS_END); + trimApplicationsLocked(true, OOM_ADJ_REASON_PROCESS_END); } } @@ -5513,7 +5521,7 @@ public class ActivityManagerService extends IActivityManager.Stub pr.mState.setForcingToImportant(null); clearProcessForegroundLocked(pr); } - updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY); } } @@ -5560,7 +5568,7 @@ public class ActivityManagerService extends IActivityManager.Stub } if (changed) { - updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY); } } } @@ -6181,8 +6189,8 @@ 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); + for (int s = psr.numberOfRunningServices() - 1; s >= 0; --s) { + final ServiceRecord sr = psr.getRunningServiceAt(s); if (sr.isForeground && sr.mAllowUiJobScheduling) { return true; } @@ -6197,12 +6205,7 @@ public class ActivityManagerService extends IActivityManager.Stub * {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean) user-initiated job}. */ // 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) { + boolean canScheduleUserInitiatedJobs(int uid, int pid, String pkgName) { synchronized (this) { final ProcessRecord processRecord; synchronized (mPidsSelfLocked) { @@ -6232,7 +6235,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 (!skipWhileInUseCheck && mServices.canAllowWhileInUsePermissionInFgsLocked( + if (mServices.canAllowWhileInUsePermissionInFgsLocked( pid, uid, pkgName, processRecord, backgroundStartPrivileges)) { return true; } @@ -6869,7 +6872,7 @@ public class ActivityManagerService extends IActivityManager.Stub new HostingRecord(HostingRecord.HOSTING_TYPE_ADDED_APPLICATION, customProcess != null ? customProcess : info.processName)); updateLruProcessLocked(app, false, null); - updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); + updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN); } // Report usage as process is persistent and being started. @@ -6986,7 +6989,7 @@ public class ActivityManagerService extends IActivityManager.Stub mOomAdjProfiler.onWakefulnessChanged(wakefulness); mOomAdjuster.onWakefulnessChanged(wakefulness); - updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + updateOomAdjLocked(OOM_ADJ_REASON_UI_VISIBILITY); } } } @@ -7748,7 +7751,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (changed) { - updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY); } } } finally { @@ -8728,7 +8731,9 @@ public class ActivityManagerService extends IActivityManager.Stub // '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) { + if (recoverable) { + mAppErrors.sendRecoverableCrashToAppExitInfo(r, crashInfo); + } else { mAppErrors.crashApplication(r, crashInfo); } } @@ -9508,7 +9513,7 @@ public class ActivityManagerService extends IActivityManager.Stub mAppProfiler.setMemFactorOverrideLocked(level); // Kick off an oom adj update since we forced a mem factor update. - updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + updateOomAdjLocked(OOM_ADJ_REASON_SHELL); } } @@ -13408,7 +13413,7 @@ public class ActivityManagerService extends IActivityManager.Stub proc.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BACKUP); // Try not to kill the process during backup - updateOomAdjLocked(proc, OomAdjuster.OOM_ADJ_REASON_NONE); + updateOomAdjLocked(proc, OOM_ADJ_REASON_BACKUP); // If the process is already attached, schedule the creation of the backup agent now. // If it is not yet live, this will be done when it attaches to the framework. @@ -13532,7 +13537,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Not backing this app up any more; reset its OOM adjustment final ProcessRecord proc = backupTarget.app; - updateOomAdjLocked(proc, OomAdjuster.OOM_ADJ_REASON_NONE); + updateOomAdjLocked(proc, OOM_ADJ_REASON_BACKUP); proc.setInFullBackup(false); proc.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_BACKUP); @@ -13713,7 +13718,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (!sdkSandboxManagerLocal.canRegisterBroadcastReceiver( /*IntentFilter=*/ filter, flags, onlyProtectedBroadcasts)) { throw new SecurityException("SDK sandbox not allowed to register receiver" - + " with the given IntentFilter: " + filter.toString()); + + " with the given IntentFilter: " + filter.toLongString()); } } @@ -13923,7 +13928,7 @@ public class ActivityManagerService extends IActivityManager.Stub // If we actually concluded any broadcasts, we might now be able // to trim the recipients' apps from our working set if (doTrim) { - trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER); + trimApplicationsLocked(false, OOM_ADJ_REASON_FINISH_RECEIVER); return; } } @@ -15185,7 +15190,7 @@ public class ActivityManagerService extends IActivityManager.Stub queue.finishReceiverLocked(callerApp, resultCode, resultData, resultExtras, resultAbort, true); // updateOomAdjLocked() will be done here - trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER); + trimApplicationsLocked(false, OOM_ADJ_REASON_FINISH_RECEIVER); } } finally { @@ -16130,7 +16135,7 @@ public class ActivityManagerService extends IActivityManager.Stub item.foregroundServiceTypes = fgServiceTypes; } if (oomAdj) { - updateOomAdjLocked(proc, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + updateOomAdjLocked(proc, OOM_ADJ_REASON_UI_VISIBILITY); } } @@ -16196,7 +16201,7 @@ public class ActivityManagerService extends IActivityManager.Stub * {@link #enqueueOomAdjTargetLocked}. */ @GuardedBy("this") - void updateOomAdjPendingTargetsLocked(@OomAdjuster.OomAdjReason int oomAdjReason) { + void updateOomAdjPendingTargetsLocked(@OomAdjReason int oomAdjReason) { mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason); } @@ -16215,7 +16220,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @GuardedBy("this") - final void updateOomAdjLocked(@OomAdjuster.OomAdjReason int oomAdjReason) { + final void updateOomAdjLocked(@OomAdjReason int oomAdjReason) { mOomAdjuster.updateOomAdjLocked(oomAdjReason); } @@ -16227,8 +16232,7 @@ public class ActivityManagerService extends IActivityManager.Stub * @return whether updateOomAdjLocked(app) was successful. */ @GuardedBy("this") - final boolean updateOomAdjLocked( - ProcessRecord app, @OomAdjuster.OomAdjReason int oomAdjReason) { + final boolean updateOomAdjLocked(ProcessRecord app, @OomAdjReason int oomAdjReason) { return mOomAdjuster.updateOomAdjLocked(app, oomAdjReason); } @@ -16461,16 +16465,14 @@ public class ActivityManagerService extends IActivityManager.Stub mOomAdjuster.setUidTempAllowlistStateLSP(uid, onAllowlist); } - private void trimApplications( - boolean forceFullOomAdj, @OomAdjuster.OomAdjReason int oomAdjReason) { + private void trimApplications(boolean forceFullOomAdj, @OomAdjReason int oomAdjReason) { synchronized (this) { trimApplicationsLocked(forceFullOomAdj, oomAdjReason); } } @GuardedBy("this") - private void trimApplicationsLocked( - boolean forceFullOomAdj, @OomAdjuster.OomAdjReason int oomAdjReason) { + private void trimApplicationsLocked(boolean forceFullOomAdj, @OomAdjReason int oomAdjReason) { // First remove any unused application processes whose package // has been removed. boolean didSomething = false; @@ -17442,7 +17444,7 @@ public class ActivityManagerService extends IActivityManager.Stub } pr.mState.setHasOverlayUi(hasOverlayUi); //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid); - updateOomAdjLocked(pr, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY); } } @@ -17577,7 +17579,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void trimApplications() { - ActivityManagerService.this.trimApplications(true, OomAdjuster.OOM_ADJ_REASON_ACTIVITY); + ActivityManagerService.this.trimApplications(true, OOM_ADJ_REASON_ACTIVITY); } public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) { @@ -17626,9 +17628,9 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void updateOomAdj() { + public void updateOomAdj(@OomAdjReason int oomAdjReason) { synchronized (ActivityManagerService.this) { - ActivityManagerService.this.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + ActivityManagerService.this.updateOomAdjLocked(oomAdjReason); } } @@ -18288,8 +18290,7 @@ public class ActivityManagerService extends IActivityManager.Stub // sends to the activity. After this race issue between WM/ATMS and AMS is solved, this // workaround can be removed. (b/213288355) if (isNewPending) { - mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid, - OomAdjuster.OOM_ADJ_REASON_ACTIVITY); + mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid, OOM_ADJ_REASON_ACTIVITY); } // We need to update the network rules for the app coming to the top state so that // it can access network when the device or the app is in a restricted state diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 350ac3bd4360..17a0d62c27b3 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -59,12 +59,12 @@ import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.app.IProcessObserver; import android.app.IStopUserCallback; -import android.app.IUidObserver; import android.app.IUserSwitchObserver; import android.app.KeyguardManager; import android.app.ProcessStateEnum; import android.app.ProfilerInfo; import android.app.RemoteServiceException.CrashedByAdbException; +import android.app.UidObserver; import android.app.UserSwitchObserver; import android.app.WaitResult; import android.app.usage.AppStandbyInfo; @@ -247,6 +247,10 @@ final class ActivityManagerShellCommand extends ShellCommand { return runSendBroadcast(pw); case "compact": return runCompact(pw); + case "freeze": + return runFreeze(pw); + case "unfreeze": + return runUnfreeze(pw); case "instrument": getOutPrintWriter().println("Error: must be invoked through 'am instrument'."); return -1; @@ -1074,20 +1078,10 @@ final class ActivityManagerShellCommand extends ShellCommand { boolean isFullCompact = op.equals("full"); boolean isSomeCompact = op.equals("some"); if (isFullCompact || isSomeCompact) { - String processName = getNextArgRequired(); - synchronized (mInternal.mProcLock) { - // Default to current user - int userId = mInterface.getCurrentUserId(); - String userOpt = getNextOption(); - if (userOpt != null && "--user".equals(userOpt)) { - int inputUserId = UserHandle.parseUserArg(getNextArgRequired()); - if (inputUserId != UserHandle.USER_CURRENT) { - userId = inputUserId; - } - } - final int uid = - mInternal.getPackageManagerInternal().getPackageUid(processName, 0, userId); - app = mInternal.getProcessRecordLocked(processName, uid); + app = getProcessFromShell(); + if (app == null) { + getErrPrintWriter().println("Error: could not find process"); + return -1; } pw.println("Process record found pid: " + app.mPid); if (isFullCompact) { @@ -1143,6 +1137,93 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } + @NeverCompile + int runFreeze(PrintWriter pw) throws RemoteException { + String freezerOpt = getNextOption(); + boolean isSticky = false; + if (freezerOpt != null) { + isSticky = freezerOpt.equals("--sticky"); + } + ProcessRecord app = getProcessFromShell(); + if (app == null) { + getErrPrintWriter().println("Error: could not find process"); + return -1; + } + pw.println("Freezing pid: " + app.mPid + " sticky=" + isSticky); + synchronized (mInternal) { + synchronized (mInternal.mProcLock) { + app.mOptRecord.setFreezeSticky(isSticky); + mInternal.mOomAdjuster.mCachedAppOptimizer.freezeAppAsyncInternalLSP(app, 0, true); + } + } + return 0; + } + + @NeverCompile + int runUnfreeze(PrintWriter pw) throws RemoteException { + String freezerOpt = getNextOption(); + boolean isSticky = false; + if (freezerOpt != null) { + isSticky = freezerOpt.equals("--sticky"); + } + ProcessRecord app = getProcessFromShell(); + if (app == null) { + getErrPrintWriter().println("Error: could not find process"); + return -1; + } + pw.println("Unfreezing pid: " + app.mPid); + synchronized (mInternal) { + synchronized (mInternal.mProcLock) { + synchronized (mInternal.mOomAdjuster.mCachedAppOptimizer.mFreezerLock) { + app.mOptRecord.setFreezeSticky(isSticky); + mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppInternalLSP(app, 0, + false); + } + } + } + return 0; + } + + /** + * Parses from the shell the process name and user id if provided and provides the corresponding + * {@link ProcessRecord)} If no user is provided, it will fallback to current user. + * Example usage: {@code <processname> --user current} or {@code <processname>} + * @return process record of process, null if none found. + * @throws RemoteException + */ + @NeverCompile + ProcessRecord getProcessFromShell() throws RemoteException { + ProcessRecord app; + String processName = getNextArgRequired(); + synchronized (mInternal.mProcLock) { + // Default to current user + int userId = getUserIdFromShellOrFallback(); + final int uid = + mInternal.getPackageManagerInternal().getPackageUid(processName, 0, userId); + app = mInternal.getProcessRecordLocked(processName, uid); + } + return app; + } + + /** + * @return User id from command line provided in the form of + * {@code --user <userid|current|all>} and if the argument is not found it will fallback + * to current user. + * @throws RemoteException + */ + @NeverCompile + int getUserIdFromShellOrFallback() throws RemoteException { + int userId = mInterface.getCurrentUserId(); + String userOpt = getNextOption(); + if (userOpt != null && "--user".equals(userOpt)) { + int inputUserId = UserHandle.parseUserArg(getNextArgRequired()); + if (inputUserId != UserHandle.USER_CURRENT) { + userId = inputUserId; + } + } + return userId; + } + int runDumpHeap(PrintWriter pw) throws RemoteException { final PrintWriter err = getErrPrintWriter(); boolean managed = true; @@ -1858,7 +1939,7 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } - static final class MyUidObserver extends IUidObserver.Stub + static final class MyUidObserver extends UidObserver implements ActivityManagerService.OomAdjObserver { final IActivityManager mInterface; final ActivityManagerService mInternal; @@ -1883,8 +1964,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } @Override - public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) - throws RemoteException { + public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) { synchronized (this) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { @@ -1903,7 +1983,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } @Override - public void onUidGone(int uid, boolean disabled) throws RemoteException { + public void onUidGone(int uid, boolean disabled) { synchronized (this) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { @@ -1921,7 +2001,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } @Override - public void onUidActive(int uid) throws RemoteException { + public void onUidActive(int uid) { synchronized (this) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { @@ -1935,7 +2015,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } @Override - public void onUidIdle(int uid, boolean disabled) throws RemoteException { + public void onUidIdle(int uid, boolean disabled) { synchronized (this) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { @@ -1953,7 +2033,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } @Override - public void onUidCachedChanged(int uid, boolean cached) throws RemoteException { + public void onUidCachedChanged(int uid, boolean cached) { synchronized (this) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { @@ -1967,10 +2047,6 @@ final class ActivityManagerShellCommand extends ShellCommand { } @Override - public void onUidProcAdjChanged(int uid) throws RemoteException { - } - - @Override public void onOomAdjMessage(String msg) { synchronized (this) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); @@ -4066,6 +4142,14 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" Perform a native compaction for process with <pid>."); pw.println(" some: execute file compaction."); pw.println(" full: execute anon + file compaction."); + pw.println(" freeze [--sticky] <processname> [--user <USER_ID>]"); + pw.println(" Freeze a process."); + pw.println(" --sticky: persists the frozen state for the process lifetime or"); + pw.println(" until an unfreeze is triggered via shell"); + pw.println(" unfreeze [--sticky] <processname> [--user <USER_ID>]"); + pw.println(" Unfreeze a process."); + pw.println(" --sticky: persists the unfrozen state for the process lifetime or"); + pw.println(" until a freeze is triggered via shell"); pw.println(" instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]"); pw.println(" [--user <USER_ID> | current]"); pw.println(" [--no-hidden-api-checks [--no-test-api-access]]"); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index c343ec24412a..061bcd740f6b 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -555,6 +555,15 @@ class AppErrors { } } + void sendRecoverableCrashToAppExitInfo( + ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) { + if (r == null || crashInfo == null + || !"Native crash".equals(crashInfo.exceptionClassName)) return; + synchronized (mService) { + mService.mProcessList.noteAppRecoverableCrash(r); + } + } + /** * Bring up the "unexpected error" dialog box for a crashing app. * Deal with edge cases (intercepts from instrumented applications, diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java index 44436369fb31..4c0dd115a3cc 100644 --- a/services/core/java/com/android/server/am/AppExitInfoTracker.java +++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java @@ -308,6 +308,16 @@ public final class AppExitInfoTracker { mKillHandler.obtainMessage(KillHandler.MSG_APP_KILL, raw).sendToTarget(); } + void scheduleNoteAppRecoverableCrash(final ProcessRecord app) { + if (!mAppExitInfoLoaded.get() || app == null || app.info == null) return; + + ApplicationExitInfo raw = obtainRawRecord(app, System.currentTimeMillis()); + raw.setReason(ApplicationExitInfo.REASON_CRASH_NATIVE); + raw.setSubReason(ApplicationExitInfo.SUBREASON_UNKNOWN); + raw.setDescription("recoverable_crash"); + mKillHandler.obtainMessage(KillHandler.MSG_APP_RECOVERABLE_CRASH, raw).sendToTarget(); + } + void scheduleNoteAppKill(final int pid, final int uid, final @Reason int reason, final @SubReason int subReason, final String msg) { if (!mAppExitInfoLoaded.get()) { @@ -421,8 +431,24 @@ public final class AppExitInfoTracker { scheduleLogToStatsdLocked(info, true); } + /** + * Make note when ActivityManagerService gets a recoverable native crash, as the process isn't + * being killed but the crash should still be added to AppExitInfo. Also, because we're not + * crashing, don't log out to statsd. + */ + @VisibleForTesting + @GuardedBy("mLock") + void handleNoteAppRecoverableCrashLocked(final ApplicationExitInfo raw) { + addExitInfoLocked(raw, /* recoverable */ true); + } + @GuardedBy("mLock") private ApplicationExitInfo addExitInfoLocked(ApplicationExitInfo raw) { + return addExitInfoLocked(raw, /* recoverable */ false); + } + + @GuardedBy("mLock") + private ApplicationExitInfo addExitInfoLocked(ApplicationExitInfo raw, boolean recoverable) { if (!mAppExitInfoLoaded.get()) { Slog.w(TAG, "Skipping saving the exit info due to ongoing loading from storage"); return null; @@ -438,7 +464,7 @@ public final class AppExitInfoTracker { } } for (int i = 0; i < packages.length; i++) { - addExitInfoInnerLocked(packages[i], uid, info); + addExitInfoInnerLocked(packages[i], uid, info, recoverable); } schedulePersistProcessExitInfo(false); @@ -845,7 +871,8 @@ public final class AppExitInfoTracker { } @GuardedBy("mLock") - private void addExitInfoInnerLocked(String packageName, int uid, ApplicationExitInfo info) { + private void addExitInfoInnerLocked(String packageName, int uid, ApplicationExitInfo info, + boolean recoverable) { AppExitInfoContainer container = mData.get(packageName, uid); if (container == null) { container = new AppExitInfoContainer(mAppExitInfoHistoryListSize); @@ -859,7 +886,11 @@ public final class AppExitInfoTracker { } mData.put(packageName, uid, container); } - container.addExitInfoLocked(info); + if (recoverable) { + container.addRecoverableCrashLocked(info); + } else { + container.addExitInfoLocked(info); + } } @GuardedBy("mLock") @@ -1284,38 +1315,40 @@ public final class AppExitInfoTracker { * A container class of {@link android.app.ApplicationExitInfo} */ final class AppExitInfoContainer { - private SparseArray<ApplicationExitInfo> mInfos; // index is pid + private SparseArray<ApplicationExitInfo> mInfos; // index is a pid + private SparseArray<ApplicationExitInfo> mRecoverableCrashes; // index is a pid private int mMaxCapacity; private int mUid; // Application uid, not isolated uid. AppExitInfoContainer(final int maxCapacity) { mInfos = new SparseArray<ApplicationExitInfo>(); + mRecoverableCrashes = new SparseArray<ApplicationExitInfo>(); mMaxCapacity = maxCapacity; } @GuardedBy("mLock") - void getExitInfoLocked(final int filterPid, final int maxNum, - ArrayList<ApplicationExitInfo> results) { + void getInfosLocked(SparseArray<ApplicationExitInfo> map, final int filterPid, + final int maxNum, ArrayList<ApplicationExitInfo> results) { if (filterPid > 0) { - ApplicationExitInfo r = mInfos.get(filterPid); + ApplicationExitInfo r = map.get(filterPid); if (r != null) { results.add(r); } } else { - final int numRep = mInfos.size(); + final int numRep = map.size(); if (maxNum <= 0 || numRep <= maxNum) { // Return all records. for (int i = 0; i < numRep; i++) { - results.add(mInfos.valueAt(i)); + results.add(map.valueAt(i)); } Collections.sort(results, (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp())); } else { if (maxNum == 1) { // Most of the caller might be only interested with the most recent one - ApplicationExitInfo r = mInfos.valueAt(0); + ApplicationExitInfo r = map.valueAt(0); for (int i = 1; i < numRep; i++) { - ApplicationExitInfo t = mInfos.valueAt(i); + ApplicationExitInfo t = map.valueAt(i); if (r.getTimestamp() < t.getTimestamp()) { r = t; } @@ -1326,7 +1359,7 @@ public final class AppExitInfoTracker { ArrayList<ApplicationExitInfo> list = mTmpInfoList2; list.clear(); for (int i = 0; i < numRep; i++) { - list.add(mInfos.valueAt(i)); + list.add(map.valueAt(i)); } Collections.sort(list, (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp())); @@ -1340,24 +1373,30 @@ public final class AppExitInfoTracker { } @GuardedBy("mLock") - void addExitInfoLocked(ApplicationExitInfo info) { + void getExitInfoLocked(final int filterPid, final int maxNum, + ArrayList<ApplicationExitInfo> results) { + getInfosLocked(mInfos, filterPid, maxNum, results); + } + + @GuardedBy("mLock") + void addInfoLocked(SparseArray<ApplicationExitInfo> map, ApplicationExitInfo info) { int size; - if ((size = mInfos.size()) >= mMaxCapacity) { + if ((size = map.size()) >= mMaxCapacity) { int oldestIndex = -1; long oldestTimeStamp = Long.MAX_VALUE; for (int i = 0; i < size; i++) { - ApplicationExitInfo r = mInfos.valueAt(i); + ApplicationExitInfo r = map.valueAt(i); if (r.getTimestamp() < oldestTimeStamp) { oldestTimeStamp = r.getTimestamp(); oldestIndex = i; } } if (oldestIndex >= 0) { - final File traceFile = mInfos.valueAt(oldestIndex).getTraceFile(); + final File traceFile = map.valueAt(oldestIndex).getTraceFile(); if (traceFile != null) { traceFile.delete(); } - mInfos.removeAt(oldestIndex); + map.removeAt(oldestIndex); } } // Claim the state information if there is any @@ -1367,7 +1406,17 @@ public final class AppExitInfoTracker { mActiveAppStateSummary, uid, pid)); info.setTraceFile(findAndRemoveFromSparse2dArray(mActiveAppTraces, uid, pid)); info.setAppTraceRetriever(mAppTraceRetriever); - mInfos.append(pid, info); + map.append(pid, info); + } + + @GuardedBy("mLock") + void addExitInfoLocked(ApplicationExitInfo info) { + addInfoLocked(mInfos, info); + } + + @GuardedBy("mLock") + void addRecoverableCrashLocked(ApplicationExitInfo info) { + addInfoLocked(mRecoverableCrashes, info); } @GuardedBy("mLock") @@ -1382,9 +1431,9 @@ public final class AppExitInfoTracker { } @GuardedBy("mLock") - void destroyLocked() { - for (int i = mInfos.size() - 1; i >= 0; i--) { - ApplicationExitInfo ai = mInfos.valueAt(i); + void destroyLocked(SparseArray<ApplicationExitInfo> map) { + for (int i = map.size() - 1; i >= 0; i--) { + ApplicationExitInfo ai = map.valueAt(i); final File traceFile = ai.getTraceFile(); if (traceFile != null) { traceFile.delete(); @@ -1395,24 +1444,37 @@ public final class AppExitInfoTracker { } @GuardedBy("mLock") + void destroyLocked() { + destroyLocked(mInfos); + destroyLocked(mRecoverableCrashes); + } + + @GuardedBy("mLock") void forEachRecordLocked(final BiFunction<Integer, ApplicationExitInfo, Integer> callback) { - if (callback != null) { - for (int i = mInfos.size() - 1; i >= 0; i--) { - switch (callback.apply(mInfos.keyAt(i), mInfos.valueAt(i))) { - case FOREACH_ACTION_REMOVE_ITEM: - final File traceFile = mInfos.valueAt(i).getTraceFile(); - if (traceFile != null) { - traceFile.delete(); - } - mInfos.removeAt(i); - break; - case FOREACH_ACTION_STOP_ITERATION: - i = 0; - break; - case FOREACH_ACTION_NONE: - default: - break; - } + if (callback == null) return; + for (int i = mInfos.size() - 1; i >= 0; i--) { + switch (callback.apply(mInfos.keyAt(i), mInfos.valueAt(i))) { + case FOREACH_ACTION_STOP_ITERATION: return; + case FOREACH_ACTION_REMOVE_ITEM: + final File traceFile = mInfos.valueAt(i).getTraceFile(); + if (traceFile != null) { + traceFile.delete(); + } + mInfos.removeAt(i); + break; + } + } + for (int i = mRecoverableCrashes.size() - 1; i >= 0; i--) { + switch (callback.apply( + mRecoverableCrashes.keyAt(i), mRecoverableCrashes.valueAt(i))) { + case FOREACH_ACTION_STOP_ITERATION: return; + case FOREACH_ACTION_REMOVE_ITEM: + final File traceFile = mRecoverableCrashes.valueAt(i).getTraceFile(); + if (traceFile != null) { + traceFile.delete(); + } + mRecoverableCrashes.removeAt(i); + break; } } } @@ -1423,6 +1485,9 @@ public final class AppExitInfoTracker { for (int i = mInfos.size() - 1; i >= 0; i--) { list.add(mInfos.valueAt(i)); } + for (int i = mRecoverableCrashes.size() - 1; i >= 0; i--) { + list.add(mRecoverableCrashes.valueAt(i)); + } Collections.sort(list, (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp())); int size = list.size(); for (int i = 0; i < size; i++) { @@ -1434,10 +1499,13 @@ public final class AppExitInfoTracker { void writeToProto(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); proto.write(AppsExitInfoProto.Package.User.UID, mUid); - int size = mInfos.size(); - for (int i = 0; i < size; i++) { + for (int i = 0; i < mInfos.size(); i++) { mInfos.valueAt(i).writeToProto(proto, AppsExitInfoProto.Package.User.APP_EXIT_INFO); } + for (int i = 0; i < mRecoverableCrashes.size(); i++) { + mRecoverableCrashes.valueAt(i).writeToProto( + proto, AppsExitInfoProto.Package.User.APP_RECOVERABLE_CRASH); + } proto.end(token); } @@ -1448,14 +1516,23 @@ public final class AppExitInfoTracker { next != ProtoInputStream.NO_MORE_FIELDS; next = proto.nextField()) { switch (next) { - case (int) AppsExitInfoProto.Package.User.UID: + case (int) AppsExitInfoProto.Package.User.UID: { mUid = proto.readInt(AppsExitInfoProto.Package.User.UID); break; - case (int) AppsExitInfoProto.Package.User.APP_EXIT_INFO: + } + case (int) AppsExitInfoProto.Package.User.APP_EXIT_INFO: { ApplicationExitInfo info = new ApplicationExitInfo(); info.readFromProto(proto, AppsExitInfoProto.Package.User.APP_EXIT_INFO); mInfos.put(info.getPid(), info); break; + } + case (int) AppsExitInfoProto.Package.User.APP_RECOVERABLE_CRASH: { + ApplicationExitInfo info = new ApplicationExitInfo(); + info.readFromProto( + proto, AppsExitInfoProto.Package.User.APP_RECOVERABLE_CRASH); + mRecoverableCrashes.put(info.getPid(), info); + break; + } } } proto.end(token); @@ -1472,6 +1549,11 @@ public final class AppExitInfoTracker { list.add(mInfos.valueAt(i)); } } + for (int i = mRecoverableCrashes.size() - 1; i >= 0; i--) { + if (filterPid == 0 || filterPid == mRecoverableCrashes.keyAt(i)) { + list.add(mRecoverableCrashes.valueAt(i)); + } + } return list; } } @@ -1610,6 +1692,7 @@ public final class AppExitInfoTracker { static final int MSG_PROC_DIED = 4103; static final int MSG_APP_KILL = 4104; static final int MSG_STATSD_LOG = 4105; + static final int MSG_APP_RECOVERABLE_CRASH = 4106; KillHandler(Looper looper) { super(looper, null, true); @@ -1648,6 +1731,14 @@ public final class AppExitInfoTracker { } } break; + case MSG_APP_RECOVERABLE_CRASH: { + ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj; + synchronized (mLock) { + handleNoteAppRecoverableCrashLocked(raw); + } + recycleRawRecord(raw); + } + break; default: super.handleMessage(msg); } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index ed297d0867a1..c0b3a90d923b 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -37,6 +37,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.hardware.Sensor; +import android.hardware.SensorManager; import android.hardware.power.stats.PowerEntity; import android.hardware.power.stats.State; import android.hardware.power.stats.StateResidency; @@ -108,8 +110,8 @@ import com.android.server.power.stats.BatteryExternalStatsWorker; import com.android.server.power.stats.BatteryStatsImpl; import com.android.server.power.stats.BatteryUsageStatsProvider; import com.android.server.power.stats.BatteryUsageStatsStore; -import com.android.server.power.stats.CpuWakeupStats; import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes; +import com.android.server.power.stats.wakeups.CpuWakeupStats; import java.io.File; import java.io.FileDescriptor; @@ -149,7 +151,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub private final PowerProfile mPowerProfile; final BatteryStatsImpl mStats; - @GuardedBy("mWakeupStats") final CpuWakeupStats mCpuWakeupStats; private final BatteryUsageStatsStore mBatteryUsageStatsStore; private final BatteryStatsImpl.UserInfoProvider mUserManagerUserInfoProvider; @@ -515,13 +516,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub @Override public void noteCpuWakingActivity(int subsystem, long elapsedMillis, int... uids) { Objects.requireNonNull(uids); - mCpuWakeupStats.noteWakingActivity(subsystem, elapsedMillis, uids); + mHandler.post(() -> mCpuWakeupStats.noteWakingActivity(subsystem, elapsedMillis, uids)); } - @Override public void noteWakingSoundTrigger(long elapsedMillis, int uid) { - // TODO(b/267717665): Pipe to noteCpuWakingActivity once SoundTrigger starts using this. - Slog.w(TAG, "Sound trigger event dispatched to uid " + uid); + noteCpuWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER, elapsedMillis, uid); } } @@ -1263,6 +1262,26 @@ public final class BatteryStatsService extends IBatteryStats.Stub } @Override + public void noteWakeupSensorEvent(long elapsedNanos, int uid, int sensorHandle) { + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID) { + throw new SecurityException("Calling uid " + callingUid + " is not system uid"); + } + + final SensorManager sm = mContext.getSystemService(SensorManager.class); + final Sensor sensor = sm.getSensorByHandle(sensorHandle); + if (sensor == null) { + Slog.w(TAG, "Unknown sensor handle " + sensorHandle + + " received in noteWakeupSensorEvent"); + return; + } + Slog.i(TAG, "Sensor " + sensor + " wakeup event at " + elapsedNanos + " sent to uid " + + uid); + // TODO (b/275436924): Remove log and pipe to CpuWakeupStats for wakeup attribution + // This method should return as quickly as possible. Use mHandler#post to do longer work. + } + + @Override @EnforcePermission(UPDATE_DEVICE_STATS) public void noteStopSensor(final int uid, final int sensor) { super.noteStopSensor_enforcePermission(); diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index dbb351b23c85..0767218ec065 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -18,9 +18,9 @@ package com.android.server.am; import static com.android.internal.util.Preconditions.checkState; import static com.android.server.am.BroadcastRecord.deliveryStateToString; -import static com.android.server.am.BroadcastRecord.isDeliveryStateTerminal; import static com.android.server.am.BroadcastRecord.isReceiverEquals; +import android.annotation.CheckResult; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -188,6 +188,12 @@ class BroadcastProcessQueue { private @Reason int mRunnableAtReason = REASON_EMPTY; private boolean mRunnableAtInvalidated; + /** + * Last state applied by {@link #updateDeferredStates}, used to quickly + * determine if a state transition is occurring. + */ + private boolean mLastDeferredStates; + private boolean mUidCached; private boolean mProcessInstrumented; private boolean mProcessPersistent; @@ -236,7 +242,15 @@ class BroadcastProcessQueue { */ @Nullable public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, - int recordIndex, boolean wouldBeSkipped) { + int recordIndex, boolean wouldBeSkipped, + @NonNull BroadcastConsumer deferredStatesApplyConsumer) { + // When updateDeferredStates() has already applied a deferred state to + // all pending items, apply to this new broadcast too + if (mLastDeferredStates && record.deferUntilActive + && (record.getDeliveryState(recordIndex) == BroadcastRecord.DELIVERY_PENDING)) { + deferredStatesApplyConsumer.accept(record, recordIndex); + } + if (record.isReplacePending()) { final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex, wouldBeSkipped); @@ -341,7 +355,12 @@ class BroadcastProcessQueue { * Predicates that choose to remove a broadcast <em>must</em> finish * delivery of the matched broadcast, to ensure that situations like ordered * broadcasts are handled consistently. + * + * @return if this operation may have changed internal state, indicating + * that the caller is responsible for invoking + * {@link BroadcastQueueModernImpl#updateRunnableList} */ + @CheckResult public boolean forEachMatchingBroadcast(@NonNull BroadcastPredicate predicate, @NonNull BroadcastConsumer consumer, boolean andRemove) { boolean didSomething = false; @@ -354,6 +373,7 @@ class BroadcastProcessQueue { return didSomething; } + @CheckResult private boolean forEachMatchingBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue, @NonNull BroadcastPredicate predicate, @NonNull BroadcastConsumer consumer, boolean andRemove) { @@ -370,6 +390,10 @@ class BroadcastProcessQueue { args.recycle(); it.remove(); onBroadcastDequeued(record, recordIndex, recordWouldBeSkipped); + } else { + // Even if we're leaving broadcast in queue, it may have + // been mutated in such a way to change our runnable time + invalidateRunnableAt(); } didSomething = true; } @@ -381,32 +405,44 @@ class BroadcastProcessQueue { /** * Update the actively running "warm" process for this process. + * + * @return if this operation may have changed internal state, indicating + * that the caller is responsible for invoking + * {@link BroadcastQueueModernImpl#updateRunnableList} */ - public void setProcessAndUidCached(@Nullable ProcessRecord app, boolean uidCached) { + @CheckResult + public boolean setProcessAndUidCached(@Nullable ProcessRecord app, boolean uidCached) { this.app = app; - if (app != null) { - setUidCached(uidCached); - setProcessInstrumented(app.getActiveInstrumentation() != null); - setProcessPersistent(app.isPersistent()); - } else { - setUidCached(uidCached); - setProcessInstrumented(false); - setProcessPersistent(false); - } // Since we may have just changed our PID, invalidate cached strings mCachedToString = null; mCachedToShortString = null; + + boolean didSomething = false; + if (app != null) { + didSomething |= setUidCached(uidCached); + didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null); + didSomething |= setProcessPersistent(app.isPersistent()); + } else { + didSomething |= setUidCached(uidCached); + didSomething |= setProcessInstrumented(false); + didSomething |= setProcessPersistent(false); + } + return didSomething; } /** * Update if this process is in the "cached" state, typically signaling that * broadcast dispatch should be paused or delayed. */ - private void setUidCached(boolean uidCached) { + @CheckResult + private boolean setUidCached(boolean uidCached) { if (mUidCached != uidCached) { mUidCached = uidCached; invalidateRunnableAt(); + return true; + } else { + return false; } } @@ -415,10 +451,14 @@ class BroadcastProcessQueue { * signaling that broadcast dispatch should bypass all pauses or delays, to * avoid holding up test suites. */ - private void setProcessInstrumented(boolean instrumented) { + @CheckResult + private boolean setProcessInstrumented(boolean instrumented) { if (mProcessInstrumented != instrumented) { mProcessInstrumented = instrumented; invalidateRunnableAt(); + return true; + } else { + return false; } } @@ -426,10 +466,14 @@ class BroadcastProcessQueue { * Update if this process is in the "persistent" state, which signals broadcast dispatch should * bypass all pauses or delays to prevent the system from becoming out of sync with itself. */ - private void setProcessPersistent(boolean persistent) { + @CheckResult + private boolean setProcessPersistent(boolean persistent) { if (mProcessPersistent != persistent) { mProcessPersistent = persistent; invalidateRunnableAt(); + return true; + } else { + return false; } } @@ -441,17 +485,17 @@ class BroadcastProcessQueue { } public int getPreferredSchedulingGroupLocked() { - if (mCountForeground > mCountForegroundDeferred) { + if (!isActive()) { + return ProcessList.SCHED_GROUP_UNDEFINED; + } else if (mCountForeground > mCountForegroundDeferred) { // We have a foreground broadcast somewhere down the queue, so // boost priority until we drain them all return ProcessList.SCHED_GROUP_DEFAULT; } else if ((mActive != null) && mActive.isForeground()) { // We have a foreground broadcast right now, so boost priority return ProcessList.SCHED_GROUP_DEFAULT; - } else if (!isIdle()) { - return ProcessList.SCHED_GROUP_BACKGROUND; } else { - return ProcessList.SCHED_GROUP_UNDEFINED; + return ProcessList.SCHED_GROUP_BACKGROUND; } } @@ -649,8 +693,20 @@ class BroadcastProcessQueue { return mActive != null; } - void forceDelayBroadcastDelivery(long delayedDurationMs) { - mForcedDelayedDurationMs = delayedDurationMs; + /** + * @return if this operation may have changed internal state, indicating + * that the caller is responsible for invoking + * {@link BroadcastQueueModernImpl#updateRunnableList} + */ + @CheckResult + boolean forceDelayBroadcastDelivery(long delayedDurationMs) { + if (mForcedDelayedDurationMs != delayedDurationMs) { + mForcedDelayedDurationMs = delayedDurationMs; + invalidateRunnableAt(); + return true; + } else { + return false; + } } /** @@ -709,7 +765,7 @@ class BroadcastProcessQueue { || consecutiveHighPriorityCount >= maxHighPriorityDispatchLimit); final boolean isLPQueueEligible = shouldConsiderLPQueue && nextLPRecord.enqueueTime <= nextHPRecord.enqueueTime - && !blockedOnOrderedDispatch(nextLPRecord, nextLPRecordIndex); + && !nextLPRecord.isBlocked(nextLPRecordIndex); return isLPQueueEligible ? lowPriorityQueue : highPriorityQueue; } @@ -722,10 +778,21 @@ class BroadcastProcessQueue { * broadcasts would be prioritized for dispatching, even if there are urgent broadcasts * waiting. This is typically used in case there are callers waiting for "barrier" to be * reached. + * + * @return if this operation may have changed internal state, indicating + * that the caller is responsible for invoking + * {@link BroadcastQueueModernImpl#updateRunnableList} */ + @CheckResult @VisibleForTesting - void setPrioritizeEarliest(boolean prioritizeEarliest) { - mPrioritizeEarliest = prioritizeEarliest; + boolean setPrioritizeEarliest(boolean prioritizeEarliest) { + if (mPrioritizeEarliest != prioritizeEarliest) { + mPrioritizeEarliest = prioritizeEarliest; + invalidateRunnableAt(); + return true; + } else { + return false; + } } /** @@ -912,39 +979,20 @@ class BroadcastProcessQueue { } } - private boolean blockedOnOrderedDispatch(BroadcastRecord r, int index) { - final int blockedUntilTerminalCount = r.blockedUntilTerminalCount[index]; - - int existingDeferredCount = 0; - if (r.deferUntilActive) { - for (int i = 0; i < index; i++) { - if (r.deferredUntilActive[i]) existingDeferredCount++; - } - } - - // We might be blocked waiting for other receivers to finish, - // typically for an ordered broadcast or priority traunches - if ((r.terminalCount + existingDeferredCount) < blockedUntilTerminalCount - && !isDeliveryStateTerminal(r.getDeliveryState(index))) { - return true; - } - return false; - } - /** - * Update {@link #getRunnableAt()} if it's currently invalidated. + * Update {@link #getRunnableAt()}, when needed. */ - private void updateRunnableAt() { - final SomeArgs next = peekNextBroadcast(); + void updateRunnableAt() { + if (!mRunnableAtInvalidated) return; mRunnableAtInvalidated = false; + + final SomeArgs next = peekNextBroadcast(); if (next != null) { final BroadcastRecord r = (BroadcastRecord) next.arg1; final int index = next.argi1; final long runnableAt = r.enqueueTime; - // If we're specifically queued behind other ordered dispatch activity, - // we aren't runnable yet - if (blockedOnOrderedDispatch(r, index)) { + if (r.isBlocked(index)) { mRunnableAt = Long.MAX_VALUE; mRunnableAtReason = REASON_BLOCKED; return; @@ -1047,10 +1095,44 @@ class BroadcastProcessQueue { } /** + * Update {@link BroadcastRecord.DELIVERY_DEFERRED} states of all our + * pending broadcasts, when needed. + */ + void updateDeferredStates(@NonNull BroadcastConsumer applyConsumer, + @NonNull BroadcastConsumer clearConsumer) { + // When all we have pending is deferred broadcasts, and we're cached, + // then we want everything to be marked deferred + final boolean wantDeferredStates = (mCountDeferred > 0) + && (mCountDeferred == mCountEnqueued) && mUidCached; + + if (mLastDeferredStates != wantDeferredStates) { + mLastDeferredStates = wantDeferredStates; + if (wantDeferredStates) { + forEachMatchingBroadcast((r, i) -> { + return r.deferUntilActive + && (r.getDeliveryState(i) == BroadcastRecord.DELIVERY_PENDING); + }, applyConsumer, false); + } else { + forEachMatchingBroadcast((r, i) -> { + return r.deferUntilActive + && (r.getDeliveryState(i) == BroadcastRecord.DELIVERY_DEFERRED); + }, clearConsumer, false); + } + } + } + + /** * Check overall health, confirming things are in a reasonable state and * that we're not wedged. */ public void assertHealthLocked() { + // If we're not actively running, we should be sorted into the runnable + // list, and if we're invalidated then someone likely forgot to invoke + // updateRunnableList() to re-sort us into place + if (!isActive()) { + checkState(!mRunnableAtInvalidated, "mRunnableAtInvalidated"); + } + assertHealthLocked(mPending); assertHealthLocked(mPendingUrgent); assertHealthLocked(mPendingOffload); @@ -1153,19 +1235,30 @@ class BroadcastProcessQueue { return mCachedToShortString; } + public String describeStateLocked() { + return describeStateLocked(SystemClock.uptimeMillis()); + } + + public String describeStateLocked(@UptimeMillisLong long now) { + final StringBuilder sb = new StringBuilder(); + if (isRunnable()) { + sb.append("runnable at "); + TimeUtils.formatDuration(getRunnableAt(), now, sb); + } else { + sb.append("not runnable"); + } + sb.append(" because "); + sb.append(reasonToString(mRunnableAtReason)); + return sb.toString(); + } + @NeverCompile public void dumpLocked(@UptimeMillisLong long now, @NonNull IndentingPrintWriter pw) { if ((mActive == null) && isEmpty()) return; pw.print(toShortString()); - if (isRunnable()) { - pw.print(" runnable at "); - TimeUtils.formatDuration(getRunnableAt(), now, pw); - } else { - pw.print(" not runnable"); - } - pw.print(" because "); - pw.print(reasonToString(mRunnableAtReason)); + pw.print(" "); + pw.print(describeStateLocked(now)); pw.println(); pw.increaseIndent(); @@ -1262,12 +1355,12 @@ class BroadcastProcessQueue { pw.print(info.activityInfo.name); } pw.println(); - final int blockedUntilTerminalCount = record.blockedUntilTerminalCount[recordIndex]; - if (blockedUntilTerminalCount != -1) { + final int blockedUntilBeyondCount = record.blockedUntilBeyondCount[recordIndex]; + if (blockedUntilBeyondCount != -1) { pw.print(" blocked until "); - pw.print(blockedUntilTerminalCount); + pw.print(blockedUntilBeyondCount); pw.print(", currently at "); - pw.print(record.terminalCount); + pw.print(record.beyondCount); pw.print(" of "); pw.println(record.receivers.size()); } diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java index bd36c3ff6f98..5a4d315767ca 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java @@ -17,6 +17,7 @@ package com.android.server.am; import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; import static android.text.TextUtils.formatSimple; @@ -37,7 +38,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_START_RECEIVER; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index a4bdf61e628f..8735f8a37b8b 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; @@ -38,7 +39,6 @@ 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_START_RECEIVER; import android.annotation.NonNull; import android.annotation.Nullable; @@ -327,6 +327,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue { return; } + // To place ourselves correctly in the runnable list, we may need to + // update internals that may have been invalidated; we wait until now at + // the last possible moment to avoid duplicated work + queue.updateDeferredStates(mBroadcastConsumerDeferApply, mBroadcastConsumerDeferClear); + queue.updateRunnableAt(); + final boolean wantQueue = queue.isRunnable(); final boolean inQueue = (queue == mRunnableHead) || (queue.runnableAtPrev != null) || (queue.runnableAtNext != null); @@ -352,8 +358,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // If app isn't running, and there's nothing in the queue, clean up if (queue.isEmpty() && !queue.isActive() && !queue.isProcessWarm()) { removeProcessQueue(queue.processName, queue.uid); - } else { - updateQueueDeferred(queue); } } @@ -619,14 +623,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } enqueuedBroadcast = true; final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast( - r, i, wouldBeSkipped); + r, i, wouldBeSkipped, mBroadcastConsumerDeferApply); if (replacedBroadcast != null) { replacedBroadcasts.add(replacedBroadcast); } - if (r.isDeferUntilActive() && queue.isDeferredUntilActive()) { - setDeliveryState(queue, null, r, i, receiver, BroadcastRecord.DELIVERY_DEFERRED, - "deferred at enqueue time"); - } updateRunnableList(queue); enqueueUpdateRunningList(); } @@ -1008,6 +1008,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } final BroadcastRecord r = queue.getActive(); + final int index = queue.getActiveIndex(); if (r.ordered) { r.resultCode = resultCode; r.resultData = resultData; @@ -1015,18 +1016,24 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (!r.isNoAbort()) { r.resultAbort = resultAbort; } + } - // When the caller aborted an ordered broadcast, we mark all - // remaining receivers as skipped - if (r.resultAbort) { - for (int i = r.terminalCount + 1; i < r.receivers.size(); i++) { - setDeliveryState(null, null, r, i, r.receivers.get(i), - BroadcastRecord.DELIVERY_SKIPPED, "resultAbort"); - } + // To ensure that "beyond" high-water marks are updated in a monotonic + // way, we finish this receiver before possibly skipping any remaining + // aborted receivers + final boolean res = finishReceiverActiveLocked(queue, + BroadcastRecord.DELIVERY_DELIVERED, "remote app"); + + // When the caller aborted an ordered broadcast, we mark all + // remaining receivers as skipped + if (r.resultAbort) { + for (int i = index + 1; i < r.receivers.size(); i++) { + setDeliveryState(null, null, r, i, r.receivers.get(i), + BroadcastRecord.DELIVERY_SKIPPED, "resultAbort"); } } - return finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app"); + return res; } /** @@ -1108,21 +1115,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue { @NonNull Object receiver, @DeliveryState int newDeliveryState, @NonNull String reason) { final int cookie = traceBegin("setDeliveryState"); + + // Remember the old state and apply the new state final int oldDeliveryState = getDeliveryState(r, index); - boolean checkFinished = false; - - // Only apply state when we haven't already reached a terminal state; - // this is how we ignore racing timeout messages - if (!isDeliveryStateTerminal(oldDeliveryState)) { - r.setDeliveryState(index, newDeliveryState, reason); - if (oldDeliveryState == BroadcastRecord.DELIVERY_DEFERRED) { - r.deferredCount--; - } else if (newDeliveryState == BroadcastRecord.DELIVERY_DEFERRED) { - // If we're deferring a broadcast, maybe that's enough to unblock the final callback - r.deferredCount++; - checkFinished = true; - } - } + final boolean beyondCountChanged = r.setDeliveryState(index, newDeliveryState, reason); // Emit any relevant tracing results when we're changing the delivery // state as part of running from a queue @@ -1147,15 +1143,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue { + deliveryStateToString(newDeliveryState) + " because " + reason); } - r.terminalCount++; notifyFinishReceiver(queue, app, r, index, receiver); - checkFinished = true; } - // When entire ordered broadcast finished, deliver final result - if (checkFinished) { - final boolean recordFinished = - ((r.terminalCount + r.deferredCount) == r.receivers.size()); - if (recordFinished) { + + // When we've reached a new high-water mark, we might be in a position + // to unblock other receivers or the final resultTo + if (beyondCountChanged) { + if (r.beyondCount == r.receivers.size()) { scheduleResultTo(r); } @@ -1255,14 +1249,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.resultExtras = null; }; - private final BroadcastConsumer mBroadcastConsumerDefer = (r, i) -> { + private final BroadcastConsumer mBroadcastConsumerDeferApply = (r, i) -> { setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_DEFERRED, - "mBroadcastConsumerDefer"); + "mBroadcastConsumerDeferApply"); }; - private final BroadcastConsumer mBroadcastConsumerUndoDefer = (r, i) -> { + private final BroadcastConsumer mBroadcastConsumerDeferClear = (r, i) -> { setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_PENDING, - "mBroadcastConsumerUndoDefer"); + "mBroadcastConsumerDeferClear"); }; /** @@ -1278,7 +1272,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { final long now = SystemClock.uptimeMillis(); if (now > mLastTestFailureTime + DateUtils.SECOND_IN_MILLIS) { mLastTestFailureTime = now; - pw.println("Test " + label + " failed due to " + leaf.toShortString()); + pw.println("Test " + label + " failed due to " + leaf.toShortString() + " " + + leaf.describeStateLocked()); pw.flush(); } return false; @@ -1315,34 +1310,25 @@ class BroadcastQueueModernImpl extends BroadcastQueue { return didSomething; } - private void forEachMatchingQueue( + private boolean forEachMatchingQueue( @NonNull Predicate<BroadcastProcessQueue> queuePredicate, @NonNull Consumer<BroadcastProcessQueue> queueConsumer) { + boolean didSomething = false; for (int i = mProcessQueues.size() - 1; i >= 0; i--) { BroadcastProcessQueue leaf = mProcessQueues.valueAt(i); while (leaf != null) { if (queuePredicate.test(leaf)) { queueConsumer.accept(leaf); updateRunnableList(leaf); + didSomething = true; } leaf = leaf.processNameNext; } } - } - - private void updateQueueDeferred( - @NonNull BroadcastProcessQueue leaf) { - if (leaf.isDeferredUntilActive()) { - leaf.forEachMatchingBroadcast((r, i) -> { - return r.deferUntilActive && (r.getDeliveryState(i) - == BroadcastRecord.DELIVERY_PENDING); - }, mBroadcastConsumerDefer, false); - } else if (leaf.hasDeferredBroadcasts()) { - leaf.forEachMatchingBroadcast((r, i) -> { - return r.deferUntilActive && (r.getDeliveryState(i) - == BroadcastRecord.DELIVERY_DEFERRED); - }, mBroadcastConsumerUndoDefer, false); + if (didSomething) { + enqueueUpdateRunningList(); } + return didSomething; } @Override @@ -1365,8 +1351,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // Update internal state by refreshing values previously // read from any known running process setQueueProcess(leaf, leaf.app); - updateQueueDeferred(leaf); - updateRunnableList(leaf); leaf = leaf.processNameNext; } enqueueUpdateRunningList(); @@ -1535,19 +1519,31 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } } + @SuppressWarnings("CheckResult") private void updateWarmProcess(@NonNull BroadcastProcessQueue queue) { if (!queue.isProcessWarm()) { - setQueueProcess(queue, mService.getProcessRecordLocked(queue.processName, queue.uid)); + // This is a bit awkward; we're in the middle of traversing the + // runnable queue, so we can't reorder that list if the runnable + // time changes here. However, if this process was just found to be + // warm via this operation, we're going to immediately promote it to + // be running, and any side effect of this operation will then apply + // after it's finished and is returned to the runnable list. + queue.setProcessAndUidCached( + mService.getProcessRecordLocked(queue.processName, queue.uid), + mUidCached.get(queue.uid, false)); } } /** * Update the {@link ProcessRecord} associated with the given - * {@link BroadcastProcessQueue}. + * {@link BroadcastProcessQueue}. Also updates any runnable status that + * might have changed as a side-effect. */ private void setQueueProcess(@NonNull BroadcastProcessQueue queue, @Nullable ProcessRecord app) { - queue.setProcessAndUidCached(app, mUidCached.get(queue.uid, false)); + if (queue.setProcessAndUidCached(app, mUidCached.get(queue.uid, false))) { + updateRunnableList(queue); + } } /** diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index c368290386a0..64fe39314f0e 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -24,6 +24,7 @@ import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROA import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_NONE; import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY; +import android.annotation.CheckResult; import android.annotation.CurrentTimeMillisLong; import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; @@ -101,8 +102,7 @@ final class BroadcastRecord extends Binder { final @NonNull List<Object> receivers; // contains BroadcastFilter and ResolveInfo final @DeliveryState int[] delivery; // delivery state of each receiver final @NonNull String[] deliveryReasons; // reasons for delivery state of each receiver - final boolean[] deferredUntilActive; // whether each receiver is infinitely deferred - final int[] blockedUntilTerminalCount; // blocked until count of each receiver + final int[] blockedUntilBeyondCount; // blocked until count of each receiver @Nullable ProcessRecord resultToApp; // who receives final result if non-null @Nullable IIntentReceiver resultTo; // who receives final result if non-null boolean deferred; @@ -134,6 +134,7 @@ final class BroadcastRecord extends Binder { int manifestSkipCount; // number of manifest receivers skipped. int terminalCount; // number of receivers in terminal state. int deferredCount; // number of receivers in deferred state. + int beyondCount; // high-water number of receivers we've moved beyond. @Nullable BroadcastQueue queue; // the outbound queue handling this broadcast // Determines the privileges the app's process has in regard to background starts. @@ -219,6 +220,23 @@ final class BroadcastRecord extends Binder { } } + /** + * Return if the given delivery state is "beyond", which means that we've + * moved beyond this receiver, and future receivers are now unblocked. + */ + static boolean isDeliveryStateBeyond(@DeliveryState int deliveryState) { + switch (deliveryState) { + case DELIVERY_DELIVERED: + case DELIVERY_SKIPPED: + case DELIVERY_TIMEOUT: + case DELIVERY_FAILURE: + case DELIVERY_DEFERRED: + return true; + default: + return false; + } + } + ProcessRecord curApp; // hosting application of current receiver. ComponentName curComponent; // the receiver class that is currently running. ActivityInfo curReceiver; // the manifest receiver that is currently running. @@ -356,7 +374,7 @@ final class BroadcastRecord extends Binder { TimeUtils.formatDuration(terminalTime[i] - scheduledTime[i], pw); pw.print(' '); } - pw.print("("); pw.print(blockedUntilTerminalCount[i]); pw.print(") "); + pw.print("("); pw.print(blockedUntilBeyondCount[i]); pw.print(") "); pw.print("#"); pw.print(i); pw.print(": "); if (o instanceof BroadcastFilter) { pw.println(o); @@ -411,8 +429,7 @@ final class BroadcastRecord extends Binder { urgent = calculateUrgent(_intent, _options); deferUntilActive = calculateDeferUntilActive(_callingUid, _options, _resultTo, _serialized, urgent); - deferredUntilActive = new boolean[deferUntilActive ? delivery.length : 0]; - blockedUntilTerminalCount = calculateBlockedUntilTerminalCount(receivers, _serialized); + blockedUntilBeyondCount = calculateBlockedUntilBeyondCount(receivers, _serialized); scheduledTime = new long[delivery.length]; terminalTime = new long[delivery.length]; resultToApp = _resultToApp; @@ -423,7 +440,7 @@ final class BroadcastRecord extends Binder { ordered = _serialized; sticky = _sticky; initialSticky = _initialSticky; - prioritized = isPrioritized(blockedUntilTerminalCount, _serialized); + prioritized = isPrioritized(blockedUntilBeyondCount, _serialized); userId = _userId; nextReceiver = 0; state = IDLE; @@ -467,8 +484,7 @@ final class BroadcastRecord extends Binder { delivery = from.delivery; deliveryReasons = from.deliveryReasons; deferUntilActive = from.deferUntilActive; - deferredUntilActive = from.deferredUntilActive; - blockedUntilTerminalCount = from.blockedUntilTerminalCount; + blockedUntilBeyondCount = from.blockedUntilBeyondCount; scheduledTime = from.scheduledTime; terminalTime = from.terminalTime; resultToApp = from.resultToApp; @@ -627,32 +643,72 @@ final class BroadcastRecord extends Binder { /** * Update the delivery state of the given {@link #receivers} index. * Automatically updates any time measurements related to state changes. + * + * @return if {@link #beyondCount} changed due to this state transition, + * indicating that other events may be unblocked. */ - void setDeliveryState(int index, @DeliveryState int deliveryState, + @CheckResult + boolean setDeliveryState(int index, @DeliveryState int newDeliveryState, @NonNull String reason) { - delivery[index] = deliveryState; - deliveryReasons[index] = reason; - if (deferUntilActive) deferredUntilActive[index] = false; - switch (deliveryState) { - case DELIVERY_DELIVERED: - case DELIVERY_SKIPPED: - case DELIVERY_TIMEOUT: - case DELIVERY_FAILURE: - terminalTime[index] = SystemClock.uptimeMillis(); + final int oldDeliveryState = delivery[index]; + if (isDeliveryStateTerminal(oldDeliveryState) + || newDeliveryState == oldDeliveryState) { + // We've already arrived in terminal or requested state, so leave + // any statistics and reasons intact from the first transition + return false; + } + + switch (oldDeliveryState) { + case DELIVERY_DEFERRED: + deferredCount--; break; + } + switch (newDeliveryState) { case DELIVERY_SCHEDULED: scheduledTime[index] = SystemClock.uptimeMillis(); break; case DELIVERY_DEFERRED: - if (deferUntilActive) deferredUntilActive[index] = true; + deferredCount++; + break; + case DELIVERY_DELIVERED: + case DELIVERY_SKIPPED: + case DELIVERY_TIMEOUT: + case DELIVERY_FAILURE: + terminalTime[index] = SystemClock.uptimeMillis(); + terminalCount++; break; } + + delivery[index] = newDeliveryState; + deliveryReasons[index] = reason; + + // If this state change might bring us to a new high-water mark, bring + // ourselves as high as we possibly can + final int oldBeyondCount = beyondCount; + if (index >= beyondCount) { + for (int i = beyondCount; i < delivery.length; i++) { + if (isDeliveryStateBeyond(getDeliveryState(i))) { + beyondCount = i + 1; + } else { + break; + } + } + } + return (beyondCount != oldBeyondCount); } @DeliveryState int getDeliveryState(int index) { return delivery[index]; } + /** + * @return if the given {@link #receivers} index should be considered + * blocked based on the current status of the overall broadcast. + */ + boolean isBlocked(int index) { + return (beyondCount < blockedUntilBeyondCount[index]); + } + boolean wasDeliveryAttempted(int index) { final int deliveryState = getDeliveryState(index); switch (deliveryState) { @@ -757,36 +813,36 @@ final class BroadcastRecord extends Binder { * has prioritized tranches of receivers. */ @VisibleForTesting - static boolean isPrioritized(@NonNull int[] blockedUntilTerminalCount, + static boolean isPrioritized(@NonNull int[] blockedUntilBeyondCount, boolean ordered) { - return !ordered && (blockedUntilTerminalCount.length > 0) - && (blockedUntilTerminalCount[0] != -1); + return !ordered && (blockedUntilBeyondCount.length > 0) + && (blockedUntilBeyondCount[0] != -1); } /** - * Calculate the {@link #terminalCount} that each receiver should be + * Calculate the {@link #beyondCount} that each receiver should be * considered blocked until. * <p> * For example, in an ordered broadcast, receiver {@code N} is blocked until - * receiver {@code N-1} reaches a terminal state. Similarly, in a - * prioritized broadcast, receiver {@code N} is blocked until all receivers - * of a higher priority reach a terminal state. + * receiver {@code N-1} reaches a terminal or deferred state. Similarly, in + * a prioritized broadcast, receiver {@code N} is blocked until all + * receivers of a higher priority reach a terminal or deferred state. * <p> - * When there are no terminal count constraints, the blocked value for each + * When there are no beyond count constraints, the blocked value for each * receiver is {@code -1}. */ @VisibleForTesting - static @NonNull int[] calculateBlockedUntilTerminalCount( + static @NonNull int[] calculateBlockedUntilBeyondCount( @NonNull List<Object> receivers, boolean ordered) { final int N = receivers.size(); - final int[] blockedUntilTerminalCount = new int[N]; + final int[] blockedUntilBeyondCount = new int[N]; int lastPriority = 0; int lastPriorityIndex = 0; for (int i = 0; i < N; i++) { if (ordered) { // When sending an ordered broadcast, we need to block this // receiver until all previous receivers have terminated - blockedUntilTerminalCount[i] = i; + blockedUntilBeyondCount[i] = i; } else { // When sending a prioritized broadcast, we only need to wait // for the previous tranche of receivers to be terminated @@ -794,18 +850,18 @@ final class BroadcastRecord extends Binder { if ((i == 0) || (thisPriority != lastPriority)) { lastPriority = thisPriority; lastPriorityIndex = i; - blockedUntilTerminalCount[i] = i; + blockedUntilBeyondCount[i] = i; } else { - blockedUntilTerminalCount[i] = lastPriorityIndex; + blockedUntilBeyondCount[i] = lastPriorityIndex; } } } // If the entire list is in the same priority tranche, mark as -1 to // indicate that none of them need to wait - if (N > 0 && blockedUntilTerminalCount[N - 1] == 0) { - Arrays.fill(blockedUntilTerminalCount, -1); + if (N > 0 && blockedUntilBeyondCount[N - 1] == 0) { + Arrays.fill(blockedUntilBeyondCount, -1); } - return blockedUntilTerminalCount; + return blockedUntilBeyondCount; } static int getReceiverUid(@NonNull Object receiver) { diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 78edbba2e569..1426cfd65286 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -18,6 +18,28 @@ package com.android.server.am; 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.OOM_ADJ_REASON_ACTIVITY; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ALLOWLIST; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BIND_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_COMPONENT_DISABLED; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_EXECUTING_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_GET_PROVIDER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_BEGIN; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_END; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_PROVIDER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_TASK; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RESTRICTION_CHANGE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHELL; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_STOP_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SYSTEM_INIT; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UID_IDLE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UNBIND_SERVICE; import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION; @@ -26,6 +48,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.annotation.IntDef; import android.app.ActivityManager; +import android.app.ActivityManagerInternal.OomAdjReason; import android.app.ActivityThread; import android.app.ApplicationExitInfo; import android.app.IApplicationThread; @@ -139,6 +162,26 @@ public final class CachedAppOptimizer { 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; + static final int UNFREEZE_REASON_SHORT_FGS_TIMEOUT = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_SHORT_FGS_TIMEOUT; + static final int UNFREEZE_REASON_SYSTEM_INIT = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_SYSTEM_INIT; + static final int UNFREEZE_REASON_BACKUP = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_BACKUP; + static final int UNFREEZE_REASON_SHELL = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_SHELL; + static final int UNFREEZE_REASON_REMOVE_TASK = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_REMOVE_TASK; + static final int UNFREEZE_REASON_UID_IDLE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_UID_IDLE; + static final int UNFREEZE_REASON_STOP_SERVICE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_STOP_SERVICE; + static final int UNFREEZE_REASON_EXECUTING_SERVICE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_EXECUTING_SERVICE; + static final int UNFREEZE_REASON_RESTRICTION_CHANGE = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_RESTRICTION_CHANGE; + static final int UNFREEZE_REASON_COMPONENT_DISABLED = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_COMPONENT_DISABLED; @IntDef(prefix = {"UNFREEZE_REASON_"}, value = { UNFREEZE_REASON_NONE, @@ -160,6 +203,16 @@ public final class CachedAppOptimizer { UNFREEZE_REASON_FILE_LOCK_CHECK_FAILURE, UNFREEZE_REASON_BINDER_TXNS, UNFREEZE_REASON_FEATURE_FLAGS, + UNFREEZE_REASON_SHORT_FGS_TIMEOUT, + UNFREEZE_REASON_SYSTEM_INIT, + UNFREEZE_REASON_BACKUP, + UNFREEZE_REASON_SHELL, + UNFREEZE_REASON_REMOVE_TASK, + UNFREEZE_REASON_UID_IDLE, + UNFREEZE_REASON_STOP_SERVICE, + UNFREEZE_REASON_EXECUTING_SERVICE, + UNFREEZE_REASON_RESTRICTION_CHANGE, + UNFREEZE_REASON_COMPONENT_DISABLED, }) @Retention(RetentionPolicy.SOURCE) public @interface UnfreezeReason {} @@ -178,6 +231,7 @@ public final class CachedAppOptimizer { private static final String ATRACE_FREEZER_TRACK = "Freezer"; private static final int FREEZE_BINDER_TIMEOUT_MS = 100; + private static final int FREEZE_DEADLOCK_TIMEOUT_MS = 1000; @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false; @@ -244,6 +298,7 @@ public final class CachedAppOptimizer { static final int REPORT_UNFREEZE_MSG = 4; static final int COMPACT_NATIVE_MSG = 5; static final int UID_FROZEN_STATE_CHANGED_MSG = 6; + static final int DEADLOCK_WATCHDOG_MSG = 7; // When free swap falls below this percentage threshold any full (file + anon) // compactions will be downgraded to file only compactions to reduce pressure @@ -287,7 +342,7 @@ public final class CachedAppOptimizer { private final ActivityManagerGlobalLock mProcLock; - private final Object mFreezerLock = new Object(); + public final Object mFreezerLock = new Object(); private final OnPropertiesChangedListener mOnFlagsChangedListener = new OnPropertiesChangedListener() { @@ -708,8 +763,9 @@ public final class CachedAppOptimizer { pw.println(" Apps frozen: " + size); for (int i = 0; i < size; i++) { ProcessRecord app = mFrozenProcesses.valueAt(i); - pw.println(" " + app.mOptRecord.getFreezeUnfreezeTime() - + ": " + app.getPid() + " " + app.processName); + pw.println(" " + app.mOptRecord.getFreezeUnfreezeTime() + ": " + app.getPid() + + " " + app.processName + + (app.mOptRecord.isFreezeSticky() ? " (sticky)" : "")); } if (!mPendingCompactionProcesses.isEmpty()) { @@ -1228,12 +1284,26 @@ public final class CachedAppOptimizer { @GuardedBy({"mAm", "mProcLock"}) void freezeAppAsyncLSP(ProcessRecord app) { + freezeAppAsyncInternalLSP(app, mFreezerDebounceTimeout, false); + } + + @GuardedBy({"mAm", "mProcLock"}) + void freezeAppAsyncInternalLSP(ProcessRecord app, long delayMillis, boolean force) { final ProcessCachedOptimizerRecord opt = app.mOptRecord; if (opt.isPendingFreeze()) { // Skip redundant DO_FREEZE message return; } + if (opt.isFreezeSticky() && !force) { + if (DEBUG_FREEZER) { + Slog.d(TAG_AM, + "Skip freezing because unfrozen state is sticky pid=" + app.getPid() + " " + + app.processName); + } + return; + } + if (mAm.mConstants.USE_MODERN_TRIM && app.mState.getSetAdj() >= ProcessList.CACHED_APP_MIN_ADJ) { final IApplicationThread thread = app.getThread(); @@ -1246,9 +1316,8 @@ public final class CachedAppOptimizer { } } mFreezeHandler.sendMessageDelayed( - mFreezeHandler.obtainMessage( - SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app), - mFreezerDebounceTimeout); + mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app), + delayMillis); opt.setPendingFreeze(true); if (DEBUG_FREEZER) { Slog.d(TAG_AM, "Async freezing " + app.getPid() + " " + app.processName); @@ -1256,9 +1325,19 @@ public final class CachedAppOptimizer { } @GuardedBy({"mAm", "mProcLock", "mFreezerLock"}) - void unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason) { + void unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) { final int pid = app.getPid(); final ProcessCachedOptimizerRecord opt = app.mOptRecord; + boolean sticky = opt.isFreezeSticky(); + if (sticky && !force) { + // Sticky freezes will not change their state unless forced out of it. + if (DEBUG_FREEZER) { + Slog.d(TAG_AM, + "Skip unfreezing because frozen state is sticky pid=" + pid + " " + + app.processName); + } + return; + } if (opt.isPendingFreeze()) { // Remove pending DO_FREEZE message mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app); @@ -1271,8 +1350,7 @@ public final class CachedAppOptimizer { UidRecord uidRec = app.getUidRecord(); if (uidRec != null && uidRec.isFrozen()) { uidRec.setFrozen(false); - mFreezeHandler.removeMessages(UID_FROZEN_STATE_CHANGED_MSG, app); - reportOneUidFrozenStateChanged(app.uid, false); + postUidFrozenMessage(uidRec.getUid(), false); } opt.setFreezerOverride(false); @@ -1327,7 +1405,7 @@ public final class CachedAppOptimizer { } try { - traceAppFreeze(app.processName, pid, false); + traceAppFreeze(app.processName, pid, reason); Process.setProcessFrozen(pid, app.uid, false); opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); @@ -1339,7 +1417,7 @@ public final class CachedAppOptimizer { } if (!opt.isFrozen()) { - Slog.d(TAG_AM, "sync unfroze " + pid + " " + app.processName); + Slog.d(TAG_AM, "sync unfroze " + pid + " " + app.processName + " for " + reason); mFreezeHandler.sendMessage( mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG, @@ -1352,7 +1430,7 @@ public final class CachedAppOptimizer { @GuardedBy({"mAm", "mProcLock"}) void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) { synchronized (mFreezerLock) { - unfreezeAppInternalLSP(app, reason); + unfreezeAppInternalLSP(app, reason, false); } } @@ -1363,13 +1441,13 @@ public final class CachedAppOptimizer { * The caller of this function should still trigger updateOomAdj for AMS to unfreeze the app. * @param pid pid of the process to be unfrozen */ - void unfreezeProcess(int pid, @OomAdjuster.OomAdjReason int reason) { + void unfreezeProcess(int pid, @OomAdjReason int reason) { synchronized (mFreezerLock) { ProcessRecord app = mFrozenProcesses.get(pid); if (app == null) { return; } - Slog.d(TAG_AM, "quick sync unfreeze " + pid); + Slog.d(TAG_AM, "quick sync unfreeze " + pid + " for " + reason); try { freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); } catch (RuntimeException e) { @@ -1378,7 +1456,7 @@ public final class CachedAppOptimizer { } try { - traceAppFreeze(app.processName, pid, false); + traceAppFreeze(app.processName, pid, reason); Process.setProcessFrozen(pid, app.uid, false); } catch (Exception e) { Slog.e(TAG_AM, "Unable to quick unfreeze " + pid); @@ -1386,9 +1464,15 @@ public final class CachedAppOptimizer { } } - private static void traceAppFreeze(String processName, int pid, boolean freeze) { + /** + * Trace app freeze status + * @param processName The name of the target process + * @param pid The pid of the target process + * @param reason UNFREEZE_REASON_XXX (>=0) for unfreezing and -1 for freezing + */ + private static void traceAppFreeze(String processName, int pid, int reason) { Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK, - (freeze ? "Freeze " : "Unfreeze ") + processName + ":" + pid); + (reason < 0 ? "Freeze " : "Unfreeze ") + processName + ":" + pid + " " + reason); } /** @@ -1407,8 +1491,7 @@ public final class CachedAppOptimizer { UidRecord uidRec = app.getUidRecord(); if (uidRec != null && uidRec.isFrozen()) { uidRec.setFrozen(false); - mFreezeHandler.removeMessages(UID_FROZEN_STATE_CHANGED_MSG, app); - reportOneUidFrozenStateChanged(app.uid, false); + postUidFrozenMessage(uidRec.getUid(), false); } mFrozenProcesses.delete(app.getPid()); @@ -1538,12 +1621,12 @@ public final class CachedAppOptimizer { public long mOrigAnonRss; public int mProcState; public int mOomAdj; - public @OomAdjuster.OomAdjReason int mOomAdjReason; + public @OomAdjReason int mOomAdjReason; SingleCompactionStats(long[] rss, CompactSource source, String processName, long deltaAnonRss, long zramConsumed, long anonMemFreed, long origAnonRss, long cpuTimeMillis, int procState, int oomAdj, - @OomAdjuster.OomAdjReason int oomAdjReason, int uid) { + @OomAdjReason int oomAdjReason, int uid) { mRssAfterCompaction = rss; mSourceType = source; mProcessName = processName; @@ -1937,6 +2020,15 @@ public final class CachedAppOptimizer { mAm.reportUidFrozenStateChanged(uids, frozenStates); } + private void postUidFrozenMessage(int uid, boolean frozen) { + final Integer uidObj = Integer.valueOf(uid); + mFreezeHandler.removeEqualMessages(UID_FROZEN_STATE_CHANGED_MSG, uidObj); + + final int op = frozen ? 1 : 0; + mFreezeHandler.sendMessage(mFreezeHandler.obtainMessage(UID_FROZEN_STATE_CHANGED_MSG, op, + 0, uidObj)); + } + private final class FreezeHandler extends Handler implements ProcLocksReader.ProcLocksReaderCallback { private FreezeHandler() { @@ -1947,29 +2039,15 @@ public final class CachedAppOptimizer { public void handleMessage(Message msg) { switch (msg.what) { case SET_FROZEN_PROCESS_MSG: - { ProcessRecord proc = (ProcessRecord) msg.obj; - int pid = proc.getPid(); - final String name = proc.processName; synchronized (mAm) { freezeProcess(proc); } - try { - // post-check to prevent deadlock - mProcLocksReader.handleBlockingFileLocks(this); - } catch (Exception e) { - Slog.e(TAG_AM, "Unable to check file locks for " - + name + "(" + pid + "): " + e); - synchronized (mAm) { - synchronized (mProcLock) { - unfreezeAppLSP(proc, UNFREEZE_REASON_FILE_LOCK_CHECK_FAILURE); - } - } - } if (proc.mOptRecord.isFrozen()) { onProcessFrozen(proc); + removeMessages(DEADLOCK_WATCHDOG_MSG); + sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS); } - } break; case REPORT_UNFREEZE_MSG: int pid = msg.arg1; @@ -1981,8 +2059,20 @@ public final class CachedAppOptimizer { reportUnfreeze(pid, frozenDuration, processName, reason); break; case UID_FROZEN_STATE_CHANGED_MSG: - ProcessRecord proc = (ProcessRecord) msg.obj; - reportOneUidFrozenStateChanged(proc.uid, true); + final boolean frozen = (msg.arg1 == 1); + final int uid = (int) msg.obj; + reportOneUidFrozenStateChanged(uid, frozen); + break; + case DEADLOCK_WATCHDOG_MSG: + try { + // post-check to prevent deadlock + if (DEBUG_FREEZER) { + Slog.d(TAG_AM, "Freezer deadlock watchdog"); + } + mProcLocksReader.handleBlockingFileLocks(this); + } catch (IOException e) { + Slog.w(TAG_AM, "Unable to check file locks"); + } break; default: return; @@ -2014,15 +2104,6 @@ public final class CachedAppOptimizer { synchronized (mProcLock) { pid = proc.getPid(); - if (proc.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ - || opt.shouldNotFreeze()) { - if (DEBUG_FREEZER) { - Slog.d(TAG_AM, "Skipping freeze for process " + pid - + " " + name + " curAdj = " + proc.mState.getCurAdj() - + ", shouldNotFreeze = " + opt.shouldNotFreeze()); - } - return; - } if (mFreezerOverride) { opt.setFreezerOverride(true); @@ -2065,7 +2146,7 @@ public final class CachedAppOptimizer { long unfreezeTime = opt.getFreezeUnfreezeTime(); try { - traceAppFreeze(proc.processName, pid, true); + traceAppFreeze(proc.processName, pid, -1); Process.setProcessFrozen(pid, proc.uid, true); opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); @@ -2082,8 +2163,8 @@ public final class CachedAppOptimizer { final UidRecord uidRec = proc.getUidRecord(); if (frozen && uidRec != null && uidRec.areAllProcessesFrozen()) { uidRec.setFrozen(true); - mFreezeHandler.sendMessage(mFreezeHandler.obtainMessage( - UID_FROZEN_STATE_CHANGED_MSG, proc)); + + postUidFrozenMessage(uidRec.getUid(), true); } } @@ -2129,7 +2210,7 @@ public final class CachedAppOptimizer { private void reportUnfreeze(int pid, int frozenDuration, String processName, @UnfreezeReason int reason) { - EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName); + EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName, reason); // See above for why we're not taking mPhenotypeFlagLock here if (mRandom.nextFloat() < mFreezerStatsdSampleRate) { @@ -2203,32 +2284,52 @@ public final class CachedAppOptimizer { } } - static int getUnfreezeReasonCodeFromOomAdjReason(@OomAdjuster.OomAdjReason int oomAdjReason) { + static int getUnfreezeReasonCodeFromOomAdjReason(@OomAdjReason int oomAdjReason) { switch (oomAdjReason) { - case OomAdjuster.OOM_ADJ_REASON_ACTIVITY: + case OOM_ADJ_REASON_ACTIVITY: return UNFREEZE_REASON_ACTIVITY; - case OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER: + case OOM_ADJ_REASON_FINISH_RECEIVER: return UNFREEZE_REASON_FINISH_RECEIVER; - case OomAdjuster.OOM_ADJ_REASON_START_RECEIVER: + case OOM_ADJ_REASON_START_RECEIVER: return UNFREEZE_REASON_START_RECEIVER; - case OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE: + case OOM_ADJ_REASON_BIND_SERVICE: return UNFREEZE_REASON_BIND_SERVICE; - case OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE: + case OOM_ADJ_REASON_UNBIND_SERVICE: return UNFREEZE_REASON_UNBIND_SERVICE; - case OomAdjuster.OOM_ADJ_REASON_START_SERVICE: + case OOM_ADJ_REASON_START_SERVICE: return UNFREEZE_REASON_START_SERVICE; - case OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER: + case OOM_ADJ_REASON_GET_PROVIDER: return UNFREEZE_REASON_GET_PROVIDER; - case OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER: + case OOM_ADJ_REASON_REMOVE_PROVIDER: return UNFREEZE_REASON_REMOVE_PROVIDER; - case OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY: + case OOM_ADJ_REASON_UI_VISIBILITY: return UNFREEZE_REASON_UI_VISIBILITY; - case OomAdjuster.OOM_ADJ_REASON_ALLOWLIST: + case OOM_ADJ_REASON_ALLOWLIST: return UNFREEZE_REASON_ALLOWLIST; - case OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN: + case OOM_ADJ_REASON_PROCESS_BEGIN: return UNFREEZE_REASON_PROCESS_BEGIN; - case OomAdjuster.OOM_ADJ_REASON_PROCESS_END: + case OOM_ADJ_REASON_PROCESS_END: return UNFREEZE_REASON_PROCESS_END; + case OOM_ADJ_REASON_SHORT_FGS_TIMEOUT: + return UNFREEZE_REASON_SHORT_FGS_TIMEOUT; + case OOM_ADJ_REASON_SYSTEM_INIT: + return UNFREEZE_REASON_SYSTEM_INIT; + case OOM_ADJ_REASON_BACKUP: + return UNFREEZE_REASON_BACKUP; + case OOM_ADJ_REASON_SHELL: + return UNFREEZE_REASON_SHELL; + case OOM_ADJ_REASON_REMOVE_TASK: + return UNFREEZE_REASON_REMOVE_TASK; + case OOM_ADJ_REASON_UID_IDLE: + return UNFREEZE_REASON_UID_IDLE; + case OOM_ADJ_REASON_STOP_SERVICE: + return UNFREEZE_REASON_STOP_SERVICE; + case OOM_ADJ_REASON_EXECUTING_SERVICE: + return UNFREEZE_REASON_EXECUTING_SERVICE; + case OOM_ADJ_REASON_RESTRICTION_CHANGE: + return UNFREEZE_REASON_RESTRICTION_CHANGE; + case OOM_ADJ_REASON_COMPONENT_DISABLED: + return UNFREEZE_REASON_COMPONENT_DISABLED; default: return UNFREEZE_REASON_NONE; } diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index a1fcd424f8c1..d8cb094caa65 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -16,6 +16,8 @@ package com.android.server.am; import static android.Manifest.permission.GET_ANY_PROVIDER_TYPE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_GET_PROVIDER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_PROVIDER; import static android.content.ContentProvider.isAuthorityRedirectedForCloneProfile; import static android.os.Process.PROC_CHAR; import static android.os.Process.PROC_OUT_LONG; @@ -292,7 +294,7 @@ public class ContentProviderHelper { checkTime(startTime, "getContentProviderImpl: before updateOomAdj"); final int verifiedAdj = cpr.proc.mState.getVerifiedAdj(); boolean success = mService.updateOomAdjLocked(cpr.proc, - OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); + OOM_ADJ_REASON_GET_PROVIDER); // XXX things have changed so updateOomAdjLocked doesn't actually tell us // if the process has been successfully adjusted. So to reduce races with // it, we will check whether the process still exists. Note that this doesn't @@ -757,7 +759,7 @@ public class ContentProviderHelper { // update the app's oom adj value and each provider's usage stats if (providersPublished) { - mService.updateOomAdjLocked(r, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); + mService.updateOomAdjLocked(r, OOM_ADJ_REASON_GET_PROVIDER); for (int i = 0, size = providers.size(); i < size; i++) { ContentProviderHolder src = providers.get(i); if (src == null || src.info == null || src.provider == null) { @@ -835,8 +837,7 @@ public class ContentProviderHelper { ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId); if (localCpr.hasExternalProcessHandles()) { if (localCpr.removeExternalProcessHandleLocked(token)) { - mService.updateOomAdjLocked(localCpr.proc, - OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER); + mService.updateOomAdjLocked(localCpr.proc, OOM_ADJ_REASON_REMOVE_PROVIDER); } else { Slog.e(TAG, "Attempt to remove content provider " + localCpr + " with no external reference for token: " + token + "."); @@ -1506,8 +1507,7 @@ public class ContentProviderHelper { mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName); if (updateOomAdj) { - mService.updateOomAdjLocked(conn.provider.proc, - OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER); + mService.updateOomAdjLocked(conn.provider.proc, OOM_ADJ_REASON_REMOVE_PROVIDER); } } } diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java index 9ff2cd0649d4..727d4df96c47 100644 --- a/services/core/java/com/android/server/am/DropboxRateLimiter.java +++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java @@ -22,7 +22,7 @@ import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.GuardedBy; -import com.android.internal.expresslog.Counter; +import com.android.modules.expresslog.Counter; /** Rate limiter for adding errors into dropbox. */ public class DropboxRateLimiter { diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 81b242155bac..9e9db6aff699 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -121,10 +121,11 @@ option java_package com.android.server.am # Similarly, tags below are used by UserManagerService 30091 um_user_visibility_changed (userId|1|5),(visible|1) -# Foreground service start/stop events. +# Foreground service start/stop/denied/timed_out events. 30100 am_foreground_service_start (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3),(fgsType|1) 30101 am_foreground_service_denied (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3),(fgsType|1) 30102 am_foreground_service_stop (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3),(fgsType|1) +30103 am_foreground_service_timed_out (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3),(fgsType|1) # Intent Sender redirect for UserHandle.USER_CURRENT 30110 am_intent_sender_redirect_user (userId|1|5) diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index a98571b68067..365dcd9bd785 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -41,6 +41,29 @@ import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI; import static android.app.ActivityManager.PROCESS_STATE_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ALLOWLIST; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BIND_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_COMPONENT_DISABLED; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_EXECUTING_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_GET_PROVIDER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_NONE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_BEGIN; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_END; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_PROVIDER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_TASK; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RESTRICTION_CHANGE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHELL; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_STOP_SERVICE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SYSTEM_INIT; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UID_IDLE; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UNBIND_SERVICE; import static android.content.Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; @@ -101,9 +124,9 @@ import static com.android.server.am.ProcessList.UNKNOWN_ADJ; import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import android.annotation.IntDef; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityManagerInternal.OomAdjReason; import android.app.ActivityThread; import android.app.AppProtoEnums; import android.app.ApplicationExitInfo; @@ -141,8 +164,6 @@ import com.android.server.wm.ActivityServiceConnectionsHolder; import com.android.server.wm.WindowProcessController; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; @@ -154,32 +175,6 @@ import java.util.List; public class OomAdjuster { static final String TAG = "OomAdjuster"; - static final int OOM_ADJ_REASON_NONE = 0; - static final int OOM_ADJ_REASON_ACTIVITY = 1; - static final int OOM_ADJ_REASON_FINISH_RECEIVER = 2; - static final int OOM_ADJ_REASON_START_RECEIVER = 3; - static final int OOM_ADJ_REASON_BIND_SERVICE = 4; - static final int OOM_ADJ_REASON_UNBIND_SERVICE = 5; - static final int OOM_ADJ_REASON_START_SERVICE = 6; - static final int OOM_ADJ_REASON_GET_PROVIDER = 7; - static final int OOM_ADJ_REASON_REMOVE_PROVIDER = 8; - static final int OOM_ADJ_REASON_UI_VISIBILITY = 9; - static final int OOM_ADJ_REASON_ALLOWLIST = 10; - static final int OOM_ADJ_REASON_PROCESS_BEGIN = 11; - static final int OOM_ADJ_REASON_PROCESS_END = 12; - static final int OOM_ADJ_REASON_SHORT_FGS_TIMEOUT = 13; - - @IntDef(prefix = {"OOM_ADJ_REASON_"}, - value = {OOM_ADJ_REASON_NONE, OOM_ADJ_REASON_ACTIVITY, OOM_ADJ_REASON_FINISH_RECEIVER, - OOM_ADJ_REASON_START_RECEIVER, OOM_ADJ_REASON_BIND_SERVICE, - OOM_ADJ_REASON_UNBIND_SERVICE, OOM_ADJ_REASON_START_SERVICE, - OOM_ADJ_REASON_GET_PROVIDER, OOM_ADJ_REASON_REMOVE_PROVIDER, - OOM_ADJ_REASON_UI_VISIBILITY, OOM_ADJ_REASON_ALLOWLIST, - OOM_ADJ_REASON_PROCESS_BEGIN, OOM_ADJ_REASON_PROCESS_END, - OOM_ADJ_REASON_SHORT_FGS_TIMEOUT}) - @Retention(RetentionPolicy.SOURCE) - public @interface OomAdjReason {} - public static final int oomAdjReasonToProto(@OomAdjReason int oomReason) { switch (oomReason) { case OOM_ADJ_REASON_NONE: @@ -210,6 +205,24 @@ public class OomAdjuster { return AppProtoEnums.OOM_ADJ_REASON_PROCESS_END; case OOM_ADJ_REASON_SHORT_FGS_TIMEOUT: return AppProtoEnums.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT; + case OOM_ADJ_REASON_SYSTEM_INIT: + return AppProtoEnums.OOM_ADJ_REASON_SYSTEM_INIT; + case OOM_ADJ_REASON_BACKUP: + return AppProtoEnums.OOM_ADJ_REASON_BACKUP; + case OOM_ADJ_REASON_SHELL: + return AppProtoEnums.OOM_ADJ_REASON_SHELL; + case OOM_ADJ_REASON_REMOVE_TASK: + return AppProtoEnums.OOM_ADJ_REASON_REMOVE_TASK; + case OOM_ADJ_REASON_UID_IDLE: + return AppProtoEnums.OOM_ADJ_REASON_UID_IDLE; + case OOM_ADJ_REASON_STOP_SERVICE: + return AppProtoEnums.OOM_ADJ_REASON_STOP_SERVICE; + case OOM_ADJ_REASON_EXECUTING_SERVICE: + return AppProtoEnums.OOM_ADJ_REASON_EXECUTING_SERVICE; + case OOM_ADJ_REASON_RESTRICTION_CHANGE: + return AppProtoEnums.OOM_ADJ_REASON_RESTRICTION_CHANGE; + case OOM_ADJ_REASON_COMPONENT_DISABLED: + return AppProtoEnums.OOM_ADJ_REASON_COMPONENT_DISABLED; default: return AppProtoEnums.OOM_ADJ_REASON_UNKNOWN_TO_PROTO; } @@ -246,6 +259,24 @@ public class OomAdjuster { return OOM_ADJ_REASON_METHOD + "_processEnd"; case OOM_ADJ_REASON_SHORT_FGS_TIMEOUT: return OOM_ADJ_REASON_METHOD + "_shortFgs"; + case OOM_ADJ_REASON_SYSTEM_INIT: + return OOM_ADJ_REASON_METHOD + "_systemInit"; + case OOM_ADJ_REASON_BACKUP: + return OOM_ADJ_REASON_METHOD + "_backup"; + case OOM_ADJ_REASON_SHELL: + return OOM_ADJ_REASON_METHOD + "_shell"; + case OOM_ADJ_REASON_REMOVE_TASK: + return OOM_ADJ_REASON_METHOD + "_removeTask"; + case OOM_ADJ_REASON_UID_IDLE: + return OOM_ADJ_REASON_METHOD + "_uidIdle"; + case OOM_ADJ_REASON_STOP_SERVICE: + return OOM_ADJ_REASON_METHOD + "_stopService"; + case OOM_ADJ_REASON_EXECUTING_SERVICE: + return OOM_ADJ_REASON_METHOD + "_executingService"; + case OOM_ADJ_REASON_RESTRICTION_CHANGE: + return OOM_ADJ_REASON_METHOD + "_restrictionChange"; + case OOM_ADJ_REASON_COMPONENT_DISABLED: + return OOM_ADJ_REASON_METHOD + "_componentDisabled"; default: return "_unknown"; } @@ -874,8 +905,7 @@ public class OomAdjuster { } @GuardedBy("mService") - private void performUpdateOomAdjPendingTargetsLocked( - @OomAdjuster.OomAdjReason int oomAdjReason) { + private void performUpdateOomAdjPendingTargetsLocked(@OomAdjReason int oomAdjReason) { final ProcessRecord topApp = mService.getTopApp(); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason)); @@ -3453,7 +3483,7 @@ public class OomAdjuster { } @GuardedBy("mService") - void unfreezeTemporarily(ProcessRecord app, @OomAdjuster.OomAdjReason int reason) { + void unfreezeTemporarily(ProcessRecord app, @OomAdjReason int reason) { if (!mCachedAppOptimizer.useFreezer()) { return; } diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java index 24cc5337b86f..e8c8f6dd5462 100644 --- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java +++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java @@ -16,6 +16,8 @@ package com.android.server.am; +import android.app.ActivityManagerInternal.OomAdjReason; + import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -51,7 +53,7 @@ final class ProcessCachedOptimizerRecord { /** * Last oom adjust change reason for this app. */ - @GuardedBy("mProcLock") private @OomAdjuster.OomAdjReason int mLastOomAdjChangeReason; + @GuardedBy("mProcLock") private @OomAdjReason int mLastOomAdjChangeReason; /** * The most recent compaction action performed for this app. @@ -73,6 +75,15 @@ final class ProcessCachedOptimizerRecord { private boolean mFrozen; /** + * If set to true it will make the (un)freeze decision sticky which means that the freezer + * decision will remain the same unless a freeze is forced via {@link #mForceFreezeOps}. + * This property is usually set to true when external user wants to maintain a (un)frozen state + * after being applied. + */ + @GuardedBy("mProcLock") + private boolean mFreezeSticky; + + /** * Set to false after the process has been frozen. * Set to true after we have collected PSS for the frozen process. */ @@ -139,12 +150,12 @@ final class ProcessCachedOptimizerRecord { } @GuardedBy("mProcLock") - void setLastOomAdjChangeReason(@OomAdjuster.OomAdjReason int reason) { + void setLastOomAdjChangeReason(@OomAdjReason int reason) { mLastOomAdjChangeReason = reason; } @GuardedBy("mProcLock") - @OomAdjuster.OomAdjReason + @OomAdjReason int getLastOomAdjChangeReason() { return mLastOomAdjChangeReason; } @@ -193,6 +204,15 @@ final class ProcessCachedOptimizerRecord { void setFrozen(boolean frozen) { mFrozen = frozen; } + @GuardedBy("mProcLock") + void setFreezeSticky(boolean sticky) { + mFreezeSticky = sticky; + } + + @GuardedBy("mProcLock") + boolean isFreezeSticky() { + return mFreezeSticky; + } boolean skipPSSCollectionBecauseFrozen() { boolean collected = mHasCollectedFrozenPSS; diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index 70a696c72a9d..ca41f429a0de 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -51,7 +51,7 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.CompositeRWLock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.expresslog.Counter; +import com.android.modules.expresslog.Counter; import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.TimeoutRecord; import com.android.internal.os.anr.AnrLatencyTracker; diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index b1322ef510d5..312f98ad6e09 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -19,6 +19,8 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_END; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RESTRICTION_CHANGE; import static android.app.ActivityThread.PROC_START_SEQ_IDENT; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode; @@ -2875,7 +2877,7 @@ public final class ProcessList { reasonCode, subReason, reason, !doFreeze /* async */); } killAppZygotesLocked(packageName, appId, userId, false /* force */); - mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); + mService.updateOomAdjLocked(OOM_ADJ_REASON_PROCESS_END); if (doFreeze) { freezePackageCgroup(packageUID, false); } @@ -5140,7 +5142,7 @@ public final class ProcessList { } }); /* Will be a no-op if nothing pending */ - mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_RESTRICTION_CHANGE); } } @@ -5203,6 +5205,17 @@ public final class ProcessList { } /** + * Called by ActivityManagerService when a recoverable native crash occurs. + */ + @GuardedBy("mService") + void noteAppRecoverableCrash(final ProcessRecord app) { + if (DEBUG_PROCESSES) { + Slog.i(TAG, "note: " + app + " has a recoverable native crash"); + } + mAppExitInfoTracker.scheduleNoteAppRecoverableCrash(app); + } + + /** * Called by ActivityManagerService when it decides to kill an application process. */ @GuardedBy("mService") diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index afae623cd217..438a08c44ef4 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -16,6 +16,8 @@ package com.android.server.am; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY; + import static com.android.internal.util.Preconditions.checkArgument; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -45,6 +47,7 @@ import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.server.ServerProtoEnums; +import android.system.OsConstants; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; @@ -577,7 +580,9 @@ class ProcessRecord implements WindowProcessListener { processName = _processName; sdkSandboxClientAppPackage = _sdkSandboxClientAppPackage; if (isSdkSandbox) { - sdkSandboxClientAppVolumeUuid = getClientInfoForSdkSandbox().volumeUuid; + final ApplicationInfo clientInfo = getClientInfoForSdkSandbox(); + sdkSandboxClientAppVolumeUuid = clientInfo != null + ? clientInfo.volumeUuid : null; } else { sdkSandboxClientAppVolumeUuid = null; } @@ -1182,8 +1187,8 @@ class ProcessRecord implements WindowProcessListener { EventLog.writeEvent(EventLogTags.AM_KILL, userId, mPid, processName, mState.getSetAdj(), reason); Process.killProcessQuiet(mPid); - if (asyncKPG) ProcessList.killProcessGroup(uid, mPid); - else Process.killProcessGroup(uid, mPid); + if (!asyncKPG) Process.sendSignalToProcessGroup(uid, mPid, OsConstants.SIGKILL); + ProcessList.killProcessGroup(uid, mPid); } else { mPendingStart = false; } @@ -1450,7 +1455,7 @@ class ProcessRecord implements WindowProcessListener { } mService.updateLruProcessLocked(this, activityChange, null /* client */); if (updateOomAdj) { - mService.updateOomAdjLocked(this, OomAdjuster.OOM_ADJ_REASON_ACTIVITY); + mService.updateOomAdjLocked(this, OOM_ADJ_REASON_ACTIVITY); } } } diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java index 71d5d39525b4..ab71acd5f21d 100644 --- a/services/core/java/com/android/server/am/ProcessStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessStateRecord.java @@ -18,6 +18,7 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_ACTIVITY; @@ -613,7 +614,7 @@ final class ProcessStateRecord { void forceProcessStateUpTo(int newState) { if (mRepProcState > newState) { synchronized (mProcLock) { - mRepProcState = newState; + setReportedProcState(newState); setCurProcState(newState); setCurRawProcState(newState); } @@ -766,7 +767,7 @@ final class ProcessStateRecord { Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation + " for pid=" + mApp.getPid()); } - mService.updateOomAdjLocked(mApp, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY); + mService.updateOomAdjLocked(mApp, OOM_ADJ_REASON_UI_VISIBILITY); } @GuardedBy({"mService", "mProcLock"}) diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java index 072eba5d1205..20c695fc8b76 100644 --- a/services/core/java/com/android/server/am/ProviderMap.java +++ b/services/core/java/com/android/server/am/ProviderMap.java @@ -351,21 +351,26 @@ public final class ProviderMap { protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args, int opti, boolean dumpAll) { - ArrayList<ContentProviderRecord> providers = getProvidersForName(name); + try { + mAm.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false); + ArrayList<ContentProviderRecord> providers = getProvidersForName(name); - if (providers.size() <= 0) { - return false; - } + if (providers.size() <= 0) { + return false; + } - boolean needSep = false; - for (int i=0; i<providers.size(); i++) { - if (needSep) { - pw.println(); + boolean needSep = false; + for (int i=0; i<providers.size(); i++) { + if (needSep) { + pw.println(); + } + needSep = true; + dumpProvider("", fd, pw, providers.get(i), args, dumpAll); } - needSep = true; - dumpProvider("", fd, pw, providers.get(i), args, dumpAll); + return true; + } finally { + mAm.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true); } - return true; } /** diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index edf0dbd65ef2..a875860f016f 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -174,6 +174,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // allow while-in-use permissions in foreground service or not. // while-in-use permissions in FGS started from background might be restricted. boolean mAllowWhileInUsePermissionInFgs; + @PowerExemptionManager.ReasonCode + int mAllowWhileInUsePermissionInFgsReason; // A copy of mAllowWhileInUsePermissionInFgs's value when the service is entering FGS state. boolean mAllowWhileInUsePermissionInFgsAtEntering; /** Allow scheduling user-initiated jobs from the background. */ @@ -609,6 +611,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs="); pw.println(mAllowWhileInUsePermissionInFgs); + pw.print(prefix); pw.print("mAllowWhileInUsePermissionInFgsReason="); + pw.println(mAllowWhileInUsePermissionInFgsReason); pw.print(prefix); pw.print("allowUiJobScheduling="); pw.println(mAllowUiJobScheduling); pw.print(prefix); pw.print("recentCallingPackage="); pw.println(mRecentCallingPackage); diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 60a7f9371837..8c227f5488d3 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -83,6 +83,7 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_CAMERA_NATIVE, DeviceConfig.NAMESPACE_CONFIGURATION, DeviceConfig.NAMESPACE_CONNECTIVITY, + DeviceConfig.NAMESPACE_EDGETPU_NATIVE, DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT, DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS, DeviceConfig.NAMESPACE_LMKD_NATIVE, @@ -99,7 +100,6 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, DeviceConfig.NAMESPACE_SURFACE_FLINGER_NATIVE_BOOT, DeviceConfig.NAMESPACE_SWCODEC_NATIVE, - DeviceConfig.NAMESPACE_TETHERING, DeviceConfig.NAMESPACE_VENDOR_SYSTEM_NATIVE, DeviceConfig.NAMESPACE_VENDOR_SYSTEM_NATIVE_BOOT, DeviceConfig.NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE, diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 81ba4b813de1..a110169ac8c2 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -34,6 +34,7 @@ import static android.app.AppOpsManager.MODE_ERRORED; import static android.app.AppOpsManager.MODE_FOREGROUND; import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_CAMERA; +import static android.app.AppOpsManager.OP_CAMERA_SANDBOXED; import static android.app.AppOpsManager.OP_FLAGS_ALL; import static android.app.AppOpsManager.OP_FLAG_SELF; import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED; @@ -42,6 +43,7 @@ import static android.app.AppOpsManager.OP_PLAY_AUDIO; import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD; +import static android.app.AppOpsManager.OP_RECORD_AUDIO_SANDBOXED; import static android.app.AppOpsManager.OP_VIBRATE; import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED; import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED; @@ -3027,17 +3029,29 @@ public class AppOpsService extends IAppOpsService.Stub { packageName); } - // As a special case for OP_RECORD_AUDIO_HOTWORD, which we use only for attribution - // purposes and not as a check, also make sure that the caller is allowed to access - // the data gated by OP_RECORD_AUDIO. + // As a special case for OP_RECORD_AUDIO_HOTWORD, OP_RECEIVE_AMBIENT_TRIGGER_AUDIO and + // OP_RECORD_AUDIO_SANDBOXED which we use only for attribution purposes and not as a check, + // also make sure that the caller is allowed to access the data gated by OP_RECORD_AUDIO. // // TODO: Revert this change before Android 12. - if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO) { - int result = checkOperation(OP_RECORD_AUDIO, uid, packageName); + int result = MODE_DEFAULT; + if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO + || code == OP_RECORD_AUDIO_SANDBOXED) { + result = checkOperation(OP_RECORD_AUDIO, uid, packageName); + // Check result if (result != AppOpsManager.MODE_ALLOWED) { return new SyncNotedAppOp(result, code, attributionTag, packageName); } } + // As a special case for OP_CAMERA_SANDBOXED. + if (code == OP_CAMERA_SANDBOXED) { + result = checkOperation(OP_CAMERA, uid, packageName); + // Check result + if (result != AppOpsManager.MODE_ALLOWED) { + return new SyncNotedAppOp(result, code, attributionTag, packageName); + } + } + return startOperationUnchecked(clientId, code, uid, packageName, attributionTag, Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags, diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 12681565f84c..462942e4cb27 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -87,14 +87,14 @@ import java.util.concurrent.atomic.AtomicBoolean; private final @NonNull Context mContext; /** ID for Communication strategy retrieved form audio policy manager */ - private int mCommunicationStrategyId = -1; + /*package*/ int mCommunicationStrategyId = -1; /** ID for Accessibility strategy retrieved form audio policy manager */ private int mAccessibilityStrategyId = -1; /** Active communication device reported by audio policy manager */ - private AudioDeviceInfo mActiveCommunicationDevice; + /*package*/ AudioDeviceInfo mActiveCommunicationDevice; /** Last preferred device set for communication strategy */ private AudioDeviceAttributes mPreferredCommunicationDevice; @@ -204,6 +204,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private void init() { setupMessaging(mContext); + initAudioHalBluetoothState(); initRoutingStrategyIds(); mPreferredCommunicationDevice = null; updateActiveCommunicationDevice(); @@ -749,6 +750,19 @@ import java.util.concurrent.atomic.AtomicBoolean; mIsLeOutput = false; } + BtDeviceInfo(@NonNull BtDeviceInfo src, int state) { + mDevice = src.mDevice; + mState = state; + mProfile = src.mProfile; + mSupprNoisy = src.mSupprNoisy; + mVolume = src.mVolume; + mIsLeOutput = src.mIsLeOutput; + mEventSource = src.mEventSource; + mAudioSystemDevice = src.mAudioSystemDevice; + mMusicDevice = src.mMusicDevice; + mCodec = src.mCodec; + } + // redefine equality op so we can match messages intended for this device @Override public boolean equals(Object o) { @@ -815,7 +829,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * @param info struct with the (dis)connection information */ /*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) { - if (data.mInfo.getProfile() == BluetoothProfile.A2DP && data.mPreviousDevice != null + if (data.mPreviousDevice != null && data.mPreviousDevice.equals(data.mNewDevice)) { final String name = TextUtils.emptyIfNull(data.mNewDevice.getName()); new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR @@ -824,7 +838,8 @@ import java.util.concurrent.atomic.AtomicBoolean; .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile()) .record(); synchronized (mDeviceStateLock) { - postBluetoothA2dpDeviceConfigChange(data.mNewDevice); + postBluetoothDeviceConfigChange(createBtDeviceInfo(data, data.mNewDevice, + BluetoothProfile.STATE_CONNECTED)); } } else { synchronized (mDeviceStateLock) { @@ -845,10 +860,100 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - /** - * Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn(). - */ + // Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn(). + @GuardedBy("mDeviceStateLock") private boolean mBluetoothScoOn; + // value of BT_SCO parameter currently applied to audio HAL. + @GuardedBy("mDeviceStateLock") + private boolean mBluetoothScoOnApplied; + + // A2DP suspend state requested by AudioManager.setA2dpSuspended() API. + @GuardedBy("mDeviceStateLock") + private boolean mBluetoothA2dpSuspendedExt; + // A2DP suspend state requested by AudioDeviceInventory. + @GuardedBy("mDeviceStateLock") + private boolean mBluetoothA2dpSuspendedInt; + // value of BT_A2dpSuspendedSCO parameter currently applied to audio HAL. + @GuardedBy("mDeviceStateLock") + private boolean mBluetoothA2dpSuspendedApplied; + + // LE Audio suspend state requested by AudioManager.setLeAudioSuspended() API. + @GuardedBy("mDeviceStateLock") + private boolean mBluetoothLeSuspendedExt; + // LE Audio suspend state requested by AudioDeviceInventory. + @GuardedBy("mDeviceStateLock") + private boolean mBluetoothLeSuspendedInt; + // value of LeAudioSuspended parameter currently applied to audio HAL. + @GuardedBy("mDeviceStateLock") + private boolean mBluetoothLeSuspendedApplied; + + private void initAudioHalBluetoothState() { + mBluetoothScoOnApplied = false; + AudioSystem.setParameters("BT_SCO=off"); + mBluetoothA2dpSuspendedApplied = false; + AudioSystem.setParameters("A2dpSuspended=false"); + mBluetoothLeSuspendedApplied = false; + AudioSystem.setParameters("LeAudioSuspended=false"); + } + + @GuardedBy("mDeviceStateLock") + private void updateAudioHalBluetoothState() { + if (mBluetoothScoOn != mBluetoothScoOnApplied) { + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothScoOn: " + + mBluetoothScoOn + ", mBluetoothScoOnApplied: " + mBluetoothScoOnApplied); + } + if (mBluetoothScoOn) { + if (!mBluetoothA2dpSuspendedApplied) { + AudioSystem.setParameters("A2dpSuspended=true"); + mBluetoothA2dpSuspendedApplied = true; + } + if (!mBluetoothLeSuspendedApplied) { + AudioSystem.setParameters("LeAudioSuspended=true"); + mBluetoothLeSuspendedApplied = true; + } + AudioSystem.setParameters("BT_SCO=on"); + } else { + AudioSystem.setParameters("BT_SCO=off"); + } + mBluetoothScoOnApplied = mBluetoothScoOn; + } + if (!mBluetoothScoOnApplied) { + if ((mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt) + != mBluetoothA2dpSuspendedApplied) { + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothA2dpSuspendedExt: " + + mBluetoothA2dpSuspendedExt + + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt + + ", mBluetoothA2dpSuspendedApplied: " + + mBluetoothA2dpSuspendedApplied); + } + mBluetoothA2dpSuspendedApplied = + mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt; + if (mBluetoothA2dpSuspendedApplied) { + AudioSystem.setParameters("A2dpSuspended=true"); + } else { + AudioSystem.setParameters("A2dpSuspended=false"); + } + } + if ((mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt) + != mBluetoothLeSuspendedApplied) { + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothLeSuspendedExt: " + + mBluetoothLeSuspendedExt + + ", mBluetoothLeSuspendedInt: " + mBluetoothLeSuspendedInt + + ", mBluetoothLeSuspendedApplied: " + mBluetoothLeSuspendedApplied); + } + mBluetoothLeSuspendedApplied = + mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt; + if (mBluetoothLeSuspendedApplied) { + AudioSystem.setParameters("LeAudioSuspended=true"); + } else { + AudioSystem.setParameters("LeAudioSuspended=false"); + } + } + } + } /*package*/ void setBluetoothScoOn(boolean on, String eventSource) { if (AudioService.DEBUG_COMM_RTE) { @@ -856,10 +961,67 @@ import java.util.concurrent.atomic.AtomicBoolean; } synchronized (mDeviceStateLock) { mBluetoothScoOn = on; + updateAudioHalBluetoothState(); postUpdateCommunicationRouteClient(eventSource); } } + /*package*/ void setA2dpSuspended(boolean enable, boolean internal, String eventSource) { + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "setA2dpSuspended source: " + eventSource + ", enable: " + + enable + ", internal: " + internal + + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt + + ", mBluetoothA2dpSuspendedExt: " + mBluetoothA2dpSuspendedExt); + } + synchronized (mDeviceStateLock) { + if (internal) { + mBluetoothA2dpSuspendedInt = enable; + } else { + mBluetoothA2dpSuspendedExt = enable; + } + updateAudioHalBluetoothState(); + } + } + + /*package*/ void clearA2dpSuspended() { + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "clearA2dpSuspended"); + } + synchronized (mDeviceStateLock) { + mBluetoothA2dpSuspendedInt = false; + mBluetoothA2dpSuspendedExt = false; + updateAudioHalBluetoothState(); + } + } + + /*package*/ void setLeAudioSuspended(boolean enable, boolean internal, String eventSource) { + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "setLeAudioSuspended source: " + eventSource + ", enable: " + + enable + ", internal: " + internal + + ", mBluetoothLeSuspendedInt: " + mBluetoothA2dpSuspendedInt + + ", mBluetoothLeSuspendedExt: " + mBluetoothA2dpSuspendedExt); + } + synchronized (mDeviceStateLock) { + if (internal) { + mBluetoothLeSuspendedInt = enable; + } else { + mBluetoothLeSuspendedExt = enable; + } + updateAudioHalBluetoothState(); + } + } + + /*package*/ void clearLeAudioSuspended() { + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "clearLeAudioSuspended"); + } + synchronized (mDeviceStateLock) { + mBluetoothLeSuspendedInt = false; + mBluetoothLeSuspendedExt = false; + updateAudioHalBluetoothState(); + } + } + /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { synchronized (mDeviceStateLock) { return mDeviceInventory.startWatchingRoutes(observer); @@ -902,8 +1064,8 @@ import java.util.concurrent.atomic.AtomicBoolean; new AudioModeInfo(mode, pid, uid)); } - /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) { - sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device); + /*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) { + sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info); } /*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode, @@ -1160,6 +1322,10 @@ import java.util.concurrent.atomic.AtomicBoolean; sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state); } + /*package*/ void postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) { + sendLMsgNoDelay(MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED, SENDMSG_QUEUE, btDevice); + } + /*package*/ static final class CommunicationDeviceInfo { final @NonNull IBinder mCb; // Identifies the requesting client for death handler final int mPid; // Requester process ID @@ -1235,9 +1401,11 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect) { + /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, + boolean connect, @Nullable BluetoothDevice btDevice) { synchronized (mDeviceStateLock) { - return mDeviceInventory.handleDeviceConnection(attributes, connect, false /*for test*/); + return mDeviceInventory.handleDeviceConnection( + attributes, connect, false /*for test*/, btDevice); } } @@ -1478,13 +1646,10 @@ import java.util.concurrent.atomic.AtomicBoolean; (String) msg.obj, msg.arg1); } break; - case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: - final BluetoothDevice btDevice = (BluetoothDevice) msg.obj; + case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: synchronized (mDeviceStateLock) { - final int a2dpCodec = mBtHelper.getA2dpCodec(btDevice); - mDeviceInventory.onBluetoothA2dpDeviceConfigChange( - new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec), - BtHelper.EVENT_DEVICE_CONFIG_CHANGE); + mDeviceInventory.onBluetoothDeviceConfigChange( + (BtDeviceInfo) msg.obj, BtHelper.EVENT_DEVICE_CONFIG_CHANGE); } break; case MSG_BROADCAST_AUDIO_BECOMING_NOISY: @@ -1642,6 +1807,10 @@ import java.util.concurrent.atomic.AtomicBoolean; final int capturePreset = msg.arg1; mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset); } break; + case MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED: { + final BluetoothDevice btDevice = (BluetoothDevice) msg.obj; + BtHelper.onNotifyPreferredAudioProfileApplied(btDevice); + } break; default: Log.wtf(TAG, "Invalid message " + msg.what); } @@ -1677,7 +1846,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_IL_BTA2DP_TIMEOUT = 10; // process change of A2DP device configuration, obj is BluetoothDevice - private static final int MSG_L_A2DP_DEVICE_CONFIG_CHANGE = 11; + private static final int MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE = 11; private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12; private static final int MSG_REPORT_NEW_ROUTES = 13; @@ -1717,13 +1886,15 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_IL_SAVE_REMOVE_NDEF_DEVICE_FOR_STRATEGY = 48; private static final int MSG_IL_BTLEAUDIO_TIMEOUT = 49; + private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 50; + private static boolean isMessageHandledUnderWakelock(int msgId) { switch(msgId) { case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: case MSG_L_SET_BT_ACTIVE_DEVICE: case MSG_IL_BTA2DP_TIMEOUT: case MSG_IL_BTLEAUDIO_TIMEOUT: - case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: + case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: case MSG_TOGGLE_HDMI: case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: @@ -1815,7 +1986,7 @@ import java.util.concurrent.atomic.AtomicBoolean; case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: case MSG_IL_BTA2DP_TIMEOUT: case MSG_IL_BTLEAUDIO_TIMEOUT: - case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: + case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: if (sLastDeviceConnectMsgTime >= time) { // add a little delay to make sure messages are ordered as expected time = sLastDeviceConnectMsgTime + 30; @@ -1835,7 +2006,7 @@ import java.util.concurrent.atomic.AtomicBoolean; static { MESSAGES_MUTE_MUSIC = new HashSet<>(); MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE); - MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE); + MESSAGES_MUTE_MUSIC.add(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT); MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE); } @@ -1856,7 +2027,7 @@ import java.util.concurrent.atomic.AtomicBoolean; // Do not mute on bluetooth event if music is playing on a wired headset. if ((message == MSG_L_SET_BT_ACTIVE_DEVICE || message == MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT - || message == MSG_L_A2DP_DEVICE_CONFIG_CHANGE) + || message == MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE) && AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) && hasIntersection(mDeviceInventory.DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET, mAudioService.getDeviceSetForStream(AudioSystem.STREAM_MUSIC))) { @@ -1992,27 +2163,22 @@ import java.util.concurrent.atomic.AtomicBoolean; "updateCommunicationRoute, preferredCommunicationDevice: " + preferredCommunicationDevice + " eventSource: " + eventSource))); - if (preferredCommunicationDevice == null - || preferredCommunicationDevice.getType() != AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { - AudioSystem.setParameters("BT_SCO=off"); - } else { - AudioSystem.setParameters("BT_SCO=on"); - } if (preferredCommunicationDevice == null) { AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice(); if (defaultDevice != null) { - setPreferredDevicesForStrategySync( + mDeviceInventory.setPreferredDevicesForStrategy( mCommunicationStrategyId, Arrays.asList(defaultDevice)); - setPreferredDevicesForStrategySync( + mDeviceInventory.setPreferredDevicesForStrategy( mAccessibilityStrategyId, Arrays.asList(defaultDevice)); } else { - removePreferredDevicesForStrategySync(mCommunicationStrategyId); - removePreferredDevicesForStrategySync(mAccessibilityStrategyId); + mDeviceInventory.removePreferredDevicesForStrategy(mCommunicationStrategyId); + mDeviceInventory.removePreferredDevicesForStrategy(mAccessibilityStrategyId); } + mDeviceInventory.applyConnectedDevicesRoles(); } else { - setPreferredDevicesForStrategySync( + mDeviceInventory.setPreferredDevicesForStrategy( mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice)); - setPreferredDevicesForStrategySync( + mDeviceInventory.setPreferredDevicesForStrategy( mAccessibilityStrategyId, Arrays.asList(preferredCommunicationDevice)); } onUpdatePhoneStrategyDevice(preferredCommunicationDevice); diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 43063afb4ce7..1eb39f7352af 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -34,26 +34,36 @@ import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.IStrategyNonDefaultDevicesDispatcher; import android.media.IStrategyPreferredDevicesDispatcher; import android.media.MediaMetrics; +import android.media.MediaRecorder.AudioSource; +import android.media.audiopolicy.AudioProductStrategy; import android.media.permission.ClearCallingIdentityContext; import android.media.permission.SafeCloseable; import android.os.Binder; +import android.os.Bundle; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; +import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.utils.EventLogger; +import com.google.android.collect.Sets; + import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -175,18 +185,26 @@ public class AudioDeviceInventory { final RemoteCallbackList<ICapturePresetDevicesRoleDispatcher> mDevRoleCapturePresetDispatchers = new RemoteCallbackList<ICapturePresetDevicesRoleDispatcher>(); + final List<AudioProductStrategy> mStrategies; + /*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) { - mDeviceBroker = broker; - mAudioSystem = AudioSystemAdapter.getDefaultAdapter(); + this(broker, AudioSystemAdapter.getDefaultAdapter()); } //----------------------------------------------------------- /** for mocking only, allows to inject AudioSystem adapter */ /*package*/ AudioDeviceInventory(@NonNull AudioSystemAdapter audioSystem) { - mDeviceBroker = null; - mAudioSystem = audioSystem; + this(null, audioSystem); } + private AudioDeviceInventory(@Nullable AudioDeviceBroker broker, + @Nullable AudioSystemAdapter audioSystem) { + mDeviceBroker = broker; + mAudioSystem = audioSystem; + mStrategies = AudioProductStrategy.getAudioProductStrategies(); + mBluetoothDualModeEnabled = SystemProperties.getBoolean( + "persist.bluetooth.enable_dual_mode_audio", false); + } /*package*/ void setDeviceBroker(@NonNull AudioDeviceBroker broker) { mDeviceBroker = broker; } @@ -203,8 +221,13 @@ public class AudioDeviceInventory { int mDeviceCodecFormat; final UUID mSensorUuid; + /** Disabled operating modes for this device. Use a negative logic so that by default + * an empty list means all modes are allowed. + * See BluetoothAdapter.AUDIO_MODE_DUPLEX and BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY */ + @NonNull ArraySet<String> mDisabledModes = new ArraySet(0); + DeviceInfo(int deviceType, String deviceName, String deviceAddress, - int deviceCodecFormat, UUID sensorUuid) { + int deviceCodecFormat, @Nullable UUID sensorUuid) { mDeviceType = deviceType; mDeviceName = deviceName == null ? "" : deviceName; mDeviceAddress = deviceAddress == null ? "" : deviceAddress; @@ -212,11 +235,31 @@ public class AudioDeviceInventory { mSensorUuid = sensorUuid; } + void setModeDisabled(String mode) { + mDisabledModes.add(mode); + } + void setModeEnabled(String mode) { + mDisabledModes.remove(mode); + } + boolean isModeEnabled(String mode) { + return !mDisabledModes.contains(mode); + } + boolean isOutputOnlyModeEnabled() { + return isModeEnabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY); + } + boolean isDuplexModeEnabled() { + return isModeEnabled(BluetoothAdapter.AUDIO_MODE_DUPLEX); + } + DeviceInfo(int deviceType, String deviceName, String deviceAddress, int deviceCodecFormat) { this(deviceType, deviceName, deviceAddress, deviceCodecFormat, null); } + DeviceInfo(int deviceType, String deviceName, String deviceAddress) { + this(deviceType, deviceName, deviceAddress, AudioSystem.AUDIO_FORMAT_DEFAULT); + } + @Override public String toString() { return "[DeviceInfo: type:0x" + Integer.toHexString(mDeviceType) @@ -224,7 +267,8 @@ public class AudioDeviceInventory { + ") name:" + mDeviceName + " addr:" + mDeviceAddress + " codec: " + Integer.toHexString(mDeviceCodecFormat) - + " sensorUuid: " + Objects.toString(mSensorUuid) + "]"; + + " sensorUuid: " + Objects.toString(mSensorUuid) + + " disabled modes: " + mDisabledModes + "]"; } @NonNull String getKey() { @@ -276,9 +320,18 @@ public class AudioDeviceInventory { pw.println(" " + prefix + " type:0x" + Integer.toHexString(keyType) + " (" + AudioSystem.getDeviceName(keyType) + ") addr:" + valueAddress); }); + pw.println("\n" + prefix + "Preferred devices for capture preset:"); mPreferredDevicesForCapturePreset.forEach((capturePreset, devices) -> { pw.println(" " + prefix + "capturePreset:" + capturePreset + " devices:" + devices); }); + pw.println("\n" + prefix + "Applied devices roles for strategies:"); + mAppliedStrategyRoles.forEach((key, devices) -> { + pw.println(" " + prefix + "strategy: " + key.first + + " role:" + key.second + " devices:" + devices); }); + pw.println("\n" + prefix + "Applied devices roles for presets:"); + mAppliedPresetRoles.forEach((key, devices) -> { + pw.println(" " + prefix + "preset: " + key.first + + " role:" + key.second + " devices:" + devices); }); } //------------------------------------------------------------ @@ -299,15 +352,16 @@ public class AudioDeviceInventory { AudioSystem.DEVICE_STATE_AVAILABLE, di.mDeviceCodecFormat); } + mAppliedStrategyRoles.clear(); + applyConnectedDevicesRoles_l(); } synchronized (mPreferredDevices) { mPreferredDevices.forEach((strategy, devices) -> { - mAudioSystem.setDevicesRoleForStrategy( - strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); }); + setPreferredDevicesForStrategy(strategy, devices); }); } synchronized (mNonDefaultDevices) { mNonDefaultDevices.forEach((strategy, devices) -> { - mAudioSystem.setDevicesRoleForStrategy( + addDevicesRoleForStrategy( strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices); }); } synchronized (mPreferredDevicesForCapturePreset) { @@ -380,8 +434,7 @@ public class AudioDeviceInventory { btInfo.mVolume * 10, btInfo.mAudioSystemDevice, "onSetBtActiveDevice"); } - makeA2dpDeviceAvailable(address, BtHelper.getName(btInfo.mDevice), - "onSetBtActiveDevice", btInfo.mCodec); + makeA2dpDeviceAvailable(btInfo, "onSetBtActiveDevice"); } break; case BluetoothProfile.HEARING_AID: @@ -397,10 +450,7 @@ public class AudioDeviceInventory { if (switchToUnavailable) { makeLeAudioDeviceUnavailableNow(address, btInfo.mAudioSystemDevice); } else if (switchToAvailable) { - makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice), - streamType, btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10, - btInfo.mAudioSystemDevice, - "onSetBtActiveDevice"); + makeLeAudioDeviceAvailable(btInfo, streamType, "onSetBtActiveDevice"); } break; default: throw new IllegalArgumentException("Invalid profile " @@ -411,30 +461,30 @@ public class AudioDeviceInventory { @GuardedBy("AudioDeviceBroker.mDeviceStateLock") - /*package*/ void onBluetoothA2dpDeviceConfigChange( - @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) { + /*package*/ void onBluetoothDeviceConfigChange( + @NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int event) { MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId - + "onBluetoothA2dpDeviceConfigChange") - .set(MediaMetrics.Property.EVENT, BtHelper.a2dpDeviceEventToString(event)); + + "onBluetoothDeviceConfigChange") + .set(MediaMetrics.Property.EVENT, BtHelper.deviceEventToString(event)); - final BluetoothDevice btDevice = btInfo.getBtDevice(); + final BluetoothDevice btDevice = btInfo.mDevice; if (btDevice == null) { mmi.set(MediaMetrics.Property.EARLY_RETURN, "btDevice null").record(); return; } if (AudioService.DEBUG_DEVICES) { - Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice); + Log.d(TAG, "onBluetoothDeviceConfigChange btDevice=" + btDevice); } - int a2dpVolume = btInfo.getVolume(); - @AudioSystem.AudioFormatNativeEnumForBtCodec final int a2dpCodec = btInfo.getCodec(); + int volume = btInfo.mVolume; + @AudioSystem.AudioFormatNativeEnumForBtCodec final int audioCodec = btInfo.mCodec; String address = btDevice.getAddress(); if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( - "onBluetoothA2dpDeviceConfigChange addr=" + address - + " event=" + BtHelper.a2dpDeviceEventToString(event))); + "onBluetoothDeviceConfigChange addr=" + address + + " event=" + BtHelper.deviceEventToString(event))); synchronized (mDevicesLock) { if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) { @@ -449,53 +499,54 @@ public class AudioDeviceInventory { AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address); final DeviceInfo di = mConnectedDevices.get(key); if (di == null) { - Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpDeviceConfigChange"); + Log.e(TAG, "invalid null DeviceInfo in onBluetoothDeviceConfigChange"); mmi.set(MediaMetrics.Property.EARLY_RETURN, "null DeviceInfo").record(); return; } mmi.set(MediaMetrics.Property.ADDRESS, address) .set(MediaMetrics.Property.ENCODING, - AudioSystem.audioFormatToString(a2dpCodec)) - .set(MediaMetrics.Property.INDEX, a2dpVolume) + AudioSystem.audioFormatToString(audioCodec)) + .set(MediaMetrics.Property.INDEX, volume) .set(MediaMetrics.Property.NAME, di.mDeviceName); - if (event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) { - // Device is connected - if (a2dpVolume != -1) { - mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC, - // convert index to internal representation in VolumeStreamState - a2dpVolume * 10, - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, - "onBluetoothA2dpDeviceConfigChange"); - } - } else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) { - if (di.mDeviceCodecFormat != a2dpCodec) { - di.mDeviceCodecFormat = a2dpCodec; - mConnectedDevices.replace(key, di); - } - } - final int res = mAudioSystem.handleDeviceConfigChange( - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, - BtHelper.getName(btDevice), a2dpCodec); - if (res != AudioSystem.AUDIO_STATUS_OK) { - AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( - "APM handleDeviceConfigChange failed for A2DP device addr=" + address - + " codec=" + AudioSystem.audioFormatToString(a2dpCodec)) - .printLog(TAG)); + if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) { + boolean a2dpCodecChange = false; + if (btInfo.mProfile == BluetoothProfile.A2DP) { + if (di.mDeviceCodecFormat != audioCodec) { + di.mDeviceCodecFormat = audioCodec; + mConnectedDevices.replace(key, di); + a2dpCodecChange = true; + } + final int res = mAudioSystem.handleDeviceConfigChange( + btInfo.mAudioSystemDevice, address, + BtHelper.getName(btDevice), audioCodec); + + if (res != AudioSystem.AUDIO_STATUS_OK) { + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( + "APM handleDeviceConfigChange failed for A2DP device addr=" + + address + " codec=" + + AudioSystem.audioFormatToString(audioCodec)) + .printLog(TAG)); + + // force A2DP device disconnection in case of error so that AudioService + // state is consistent with audio policy manager state + setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btInfo, + BluetoothProfile.STATE_DISCONNECTED)); + } else { + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( + "APM handleDeviceConfigChange success for A2DP device addr=" + + address + + " codec=" + AudioSystem.audioFormatToString(audioCodec)) + .printLog(TAG)); - int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC); - // force A2DP device disconnection in case of error so that AudioService state is - // consistent with audio policy manager state - setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btDevice, - BluetoothProfile.A2DP, BluetoothProfile.STATE_DISCONNECTED, - musicDevice, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); - } else { - AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( - "APM handleDeviceConfigChange success for A2DP device addr=" + address - + " codec=" + AudioSystem.audioFormatToString(a2dpCodec)) - .printLog(TAG)); + } + } + if (!a2dpCodecChange) { + updateBluetoothPreferredModes_l(); + mDeviceBroker.postNotifyPreferredAudioProfileApplied(btDevice); + } } } mmi.record(); @@ -578,7 +629,7 @@ public class AudioDeviceInventory { } if (!handleDeviceConnection(wdcs.mAttributes, - wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) { + wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest, null)) { // change of connection state failed, bailout mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed") .record(); @@ -712,23 +763,35 @@ public class AudioDeviceInventory { /*package*/ int setPreferredDevicesForStrategySync(int strategy, @NonNull List<AudioDeviceAttributes> devices) { - int status = AudioSystem.ERROR; + final int status = setPreferredDevicesForStrategy(strategy, devices); + if (status == AudioSystem.SUCCESS) { + mDeviceBroker.postSaveSetPreferredDevicesForStrategy(strategy, devices); + } + return status; + } + /*package*/ int setPreferredDevicesForStrategy(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { + int status = AudioSystem.ERROR; try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( - "setPreferredDevicesForStrategySync, strategy: " + strategy + "setPreferredDevicesForStrategy, strategy: " + strategy + " devices: " + devices)).printLog(TAG)); - status = mAudioSystem.setDevicesRoleForStrategy( + status = setDevicesRoleForStrategy( strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); } + return status; + } + /*package*/ int removePreferredDevicesForStrategySync(int strategy) { + final int status = removePreferredDevicesForStrategy(strategy); if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveSetPreferredDevicesForStrategy(strategy, devices); + mDeviceBroker.postSaveRemovePreferredDevicesForStrategy(strategy); } return status; } - /*package*/ int removePreferredDevicesForStrategySync(int strategy) { + /*package*/ int removePreferredDevicesForStrategy(int strategy) { int status = AudioSystem.ERROR; try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { @@ -736,13 +799,9 @@ public class AudioDeviceInventory { "removePreferredDevicesForStrategySync, strategy: " + strategy)).printLog(TAG)); - status = mAudioSystem.clearDevicesRoleForStrategy( + status = clearDevicesRoleForStrategy( strategy, AudioSystem.DEVICE_ROLE_PREFERRED); } - - if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveRemovePreferredDevicesForStrategy(strategy); - } return status; } @@ -757,7 +816,7 @@ public class AudioDeviceInventory { AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "setDeviceAsNonDefaultForStrategySync, strategy: " + strategy + " device: " + device)).printLog(TAG)); - status = mAudioSystem.setDevicesRoleForStrategy( + status = addDevicesRoleForStrategy( strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices); } @@ -779,7 +838,7 @@ public class AudioDeviceInventory { "removeDeviceAsNonDefaultForStrategySync, strategy: " + strategy + " devices: " + device)).printLog(TAG)); - status = mAudioSystem.removeDevicesRoleForStrategy( + status = removeDevicesRoleForStrategy( strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices); } @@ -812,33 +871,70 @@ public class AudioDeviceInventory { /*package*/ int setPreferredDevicesForCapturePresetSync( int capturePreset, @NonNull List<AudioDeviceAttributes> devices) { - int status = AudioSystem.ERROR; + final int status = setPreferredDevicesForCapturePreset(capturePreset, devices); + if (status == AudioSystem.SUCCESS) { + mDeviceBroker.postSaveSetPreferredDevicesForCapturePreset(capturePreset, devices); + } + return status; + } + private int setPreferredDevicesForCapturePreset( + int capturePreset, @NonNull List<AudioDeviceAttributes> devices) { + int status = AudioSystem.ERROR; try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { - status = mAudioSystem.setDevicesRoleForCapturePreset( + status = setDevicesRoleForCapturePreset( capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices); } + return status; + } + /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) { + final int status = clearPreferredDevicesForCapturePreset(capturePreset); if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveSetPreferredDevicesForCapturePreset(capturePreset, devices); + mDeviceBroker.postSaveClearPreferredDevicesForCapturePreset(capturePreset); } return status; } - /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) { + private int clearPreferredDevicesForCapturePreset(int capturePreset) { int status = AudioSystem.ERROR; try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { - status = mAudioSystem.clearDevicesRoleForCapturePreset( + status = clearDevicesRoleForCapturePreset( capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED); } - - if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveClearPreferredDevicesForCapturePreset(capturePreset); - } return status; } + private int addDevicesRoleForCapturePreset(int capturePreset, int role, + @NonNull List<AudioDeviceAttributes> devices) { + return addDevicesRole(mAppliedPresetRoles, (p, r, d) -> { + return mAudioSystem.addDevicesRoleForCapturePreset(p, r, d); + }, capturePreset, role, devices); + } + + private int removeDevicesRoleForCapturePreset(int capturePreset, int role, + @NonNull List<AudioDeviceAttributes> devices) { + return removeDevicesRole(mAppliedPresetRoles, (p, r, d) -> { + return mAudioSystem.removeDevicesRoleForCapturePreset(p, r, d); + }, capturePreset, role, devices); + } + + private int setDevicesRoleForCapturePreset(int capturePreset, int role, + @NonNull List<AudioDeviceAttributes> devices) { + return setDevicesRole(mAppliedPresetRoles, (p, r, d) -> { + return mAudioSystem.addDevicesRoleForCapturePreset(p, r, d); + }, (p, r, d) -> { + return mAudioSystem.clearDevicesRoleForCapturePreset(p, r); + }, capturePreset, role, devices); + } + + private int clearDevicesRoleForCapturePreset(int capturePreset, int role) { + return clearDevicesRole(mAppliedPresetRoles, (p, r, d) -> { + return mAudioSystem.clearDevicesRoleForCapturePreset(p, r); + }, capturePreset, role); + } + /*package*/ void registerCapturePresetDevicesRoleDispatcher( @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) { mDevRoleCapturePresetDispatchers.register(dispatcher); @@ -849,7 +945,208 @@ public class AudioDeviceInventory { mDevRoleCapturePresetDispatchers.unregister(dispatcher); } - //----------------------------------------------------------------------- + private int addDevicesRoleForStrategy(int strategy, int role, + @NonNull List<AudioDeviceAttributes> devices) { + return addDevicesRole(mAppliedStrategyRoles, (s, r, d) -> { + return mAudioSystem.setDevicesRoleForStrategy(s, r, d); + }, strategy, role, devices); + } + + private int removeDevicesRoleForStrategy(int strategy, int role, + @NonNull List<AudioDeviceAttributes> devices) { + return removeDevicesRole(mAppliedStrategyRoles, (s, r, d) -> { + return mAudioSystem.removeDevicesRoleForStrategy(s, r, d); + }, strategy, role, devices); + } + + private int setDevicesRoleForStrategy(int strategy, int role, + @NonNull List<AudioDeviceAttributes> devices) { + return setDevicesRole(mAppliedStrategyRoles, (s, r, d) -> { + return mAudioSystem.setDevicesRoleForStrategy(s, r, d); + }, (s, r, d) -> { + return mAudioSystem.clearDevicesRoleForStrategy(s, r); + }, strategy, role, devices); + } + + private int clearDevicesRoleForStrategy(int strategy, int role) { + return clearDevicesRole(mAppliedStrategyRoles, (s, r, d) -> { + return mAudioSystem.clearDevicesRoleForStrategy(s, r); + }, strategy, role); + } + + //------------------------------------------------------------ + // Cache for applied roles for strategies and devices. The cache avoids reapplying the + // same list of devices for a given role and strategy and the corresponding systematic + // redundant work in audio policy manager and audio flinger. + // The key is the pair <Strategy , Role> and the value is the current list of devices. + + private final ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> + mAppliedStrategyRoles = new ArrayMap<>(); + + // Cache for applied roles for capture presets and devices. The cache avoids reapplying the + // same list of devices for a given role and capture preset and the corresponding systematic + // redundant work in audio policy manager and audio flinger. + // The key is the pair <Preset , Role> and the value is the current list of devices. + private final ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> + mAppliedPresetRoles = new ArrayMap<>(); + + interface AudioSystemInterface { + int deviceRoleAction(int usecase, int role, @Nullable List<AudioDeviceAttributes> devices); + } + + private int addDevicesRole( + ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap, + AudioSystemInterface asi, + int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) { + synchronized (rolesMap) { + Pair<Integer, Integer> key = new Pair<>(useCase, role); + List<AudioDeviceAttributes> roleDevices = new ArrayList<>(); + List<AudioDeviceAttributes> appliedDevices = new ArrayList<>(); + + if (rolesMap.containsKey(key)) { + roleDevices = rolesMap.get(key); + for (AudioDeviceAttributes device : devices) { + if (!roleDevices.contains(device)) { + appliedDevices.add(device); + } + } + } else { + appliedDevices.addAll(devices); + } + if (appliedDevices.isEmpty()) { + return AudioSystem.SUCCESS; + } + final int status = asi.deviceRoleAction(useCase, role, appliedDevices); + if (status == AudioSystem.SUCCESS) { + roleDevices.addAll(appliedDevices); + rolesMap.put(key, roleDevices); + } + return status; + } + } + + private int removeDevicesRole( + ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap, + AudioSystemInterface asi, + int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) { + synchronized (rolesMap) { + Pair<Integer, Integer> key = new Pair<>(useCase, role); + if (!rolesMap.containsKey(key)) { + return AudioSystem.SUCCESS; + } + List<AudioDeviceAttributes> roleDevices = rolesMap.get(key); + List<AudioDeviceAttributes> appliedDevices = new ArrayList<>(); + for (AudioDeviceAttributes device : devices) { + if (roleDevices.contains(device)) { + appliedDevices.add(device); + } + } + if (appliedDevices.isEmpty()) { + return AudioSystem.SUCCESS; + } + final int status = asi.deviceRoleAction(useCase, role, appliedDevices); + if (status == AudioSystem.SUCCESS) { + roleDevices.removeAll(appliedDevices); + if (roleDevices.isEmpty()) { + rolesMap.remove(key); + } else { + rolesMap.put(key, roleDevices); + } + } + return status; + } + } + + private int setDevicesRole( + ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap, + AudioSystemInterface addOp, + AudioSystemInterface clearOp, + int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) { + synchronized (rolesMap) { + Pair<Integer, Integer> key = new Pair<>(useCase, role); + List<AudioDeviceAttributes> roleDevices = new ArrayList<>(); + List<AudioDeviceAttributes> appliedDevices = new ArrayList<>(); + + if (rolesMap.containsKey(key)) { + roleDevices = rolesMap.get(key); + boolean equal = false; + if (roleDevices.size() == devices.size()) { + roleDevices.retainAll(devices); + equal = roleDevices.size() == devices.size(); + } + if (!equal) { + clearOp.deviceRoleAction(useCase, role, null); + roleDevices.clear(); + appliedDevices.addAll(devices); + } + } else { + appliedDevices.addAll(devices); + } + if (appliedDevices.isEmpty()) { + return AudioSystem.SUCCESS; + } + final int status = addOp.deviceRoleAction(useCase, role, appliedDevices); + if (status == AudioSystem.SUCCESS) { + roleDevices.addAll(appliedDevices); + rolesMap.put(key, roleDevices); + } + return status; + } + } + + private int clearDevicesRole( + ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap, + AudioSystemInterface asi, int useCase, int role) { + synchronized (rolesMap) { + Pair<Integer, Integer> key = new Pair<>(useCase, role); + if (!rolesMap.containsKey(key)) { + return AudioSystem.SUCCESS; + } + final int status = asi.deviceRoleAction(useCase, role, null); + if (status == AudioSystem.SUCCESS) { + rolesMap.remove(key); + } + return status; + } + } + + @GuardedBy("mDevicesLock") + private void purgeDevicesRoles_l() { + purgeRoles(mAppliedStrategyRoles, (s, r, d) -> { + return mAudioSystem.removeDevicesRoleForStrategy(s, r, d); }); + purgeRoles(mAppliedPresetRoles, (p, r, d) -> { + return mAudioSystem.removeDevicesRoleForCapturePreset(p, r, d); }); + } + + @GuardedBy("mDevicesLock") + private void purgeRoles( + ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap, + AudioSystemInterface asi) { + synchronized (rolesMap) { + Iterator<Map.Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>>> itRole = + rolesMap.entrySet().iterator(); + while (itRole.hasNext()) { + Map.Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>> entry = + itRole.next(); + Pair<Integer, Integer> keyRole = entry.getKey(); + Iterator<AudioDeviceAttributes> itDev = rolesMap.get(keyRole).iterator(); + while (itDev.hasNext()) { + AudioDeviceAttributes ada = itDev.next(); + final String devKey = DeviceInfo.makeDeviceListKey(ada.getInternalType(), + ada.getAddress()); + if (mConnectedDevices.get(devKey) == null) { + asi.deviceRoleAction(keyRole.first, keyRole.second, Arrays.asList(ada)); + itDev.remove(); + } + } + if (rolesMap.get(keyRole).isEmpty()) { + itRole.remove(); + } + } + } + } + +//----------------------------------------------------------------------- /** * Check if a device is in the list of connected devices @@ -871,10 +1168,11 @@ public class AudioDeviceInventory { * @param connect true if connection * @param isForTesting if true, not calling AudioSystem for the connection as this is * just for testing + * @param btDevice the corresponding Bluetooth device when relevant. * @return false if an error was reported by AudioSystem */ /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect, - boolean isForTesting) { + boolean isForTesting, @Nullable BluetoothDevice btDevice) { int device = attributes.getInternalType(); String address = attributes.getAddress(); String deviceName = attributes.getName(); @@ -889,6 +1187,7 @@ public class AudioDeviceInventory { .set(MediaMetrics.Property.MODE, connect ? MediaMetrics.Value.CONNECT : MediaMetrics.Value.DISCONNECT) .set(MediaMetrics.Property.NAME, deviceName); + boolean status = false; synchronized (mDevicesLock) { final String deviceKey = DeviceInfo.makeDeviceListKey(device, address); if (AudioService.DEBUG_DEVICES) { @@ -916,24 +1215,33 @@ public class AudioDeviceInventory { .record(); return false; } - mConnectedDevices.put(deviceKey, new DeviceInfo( - device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT)); + mConnectedDevices.put(deviceKey, new DeviceInfo(device, deviceName, address)); mDeviceBroker.postAccessoryPlugMediaUnmute(device); - mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record(); - return true; + status = true; } else if (!connect && isConnected) { mAudioSystem.setDeviceConnectionState(attributes, AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT); // always remove even if disconnection failed mConnectedDevices.remove(deviceKey); + status = true; + } + if (status) { + if (AudioSystem.isBluetoothScoDevice(device)) { + updateBluetoothPreferredModes_l(); + if (connect) { + mDeviceBroker.postNotifyPreferredAudioProfileApplied(btDevice); + } else { + purgeDevicesRoles_l(); + } + } mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record(); - return true; + } else { + Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey + + ", deviceSpec=" + di + ", connect=" + connect); + mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record(); } - Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey - + ", deviceSpec=" + di + ", connect=" + connect); } - mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record(); - return false; + return status; } @@ -1142,15 +1450,20 @@ public class AudioDeviceInventory { // Internal utilities @GuardedBy("mDevicesLock") - private void makeA2dpDeviceAvailable(String address, String name, String eventSource, - int a2dpCodec) { + private void makeA2dpDeviceAvailable(AudioDeviceBroker.BtDeviceInfo btInfo, + String eventSource) { + final String address = btInfo.mDevice.getAddress(); + final String name = BtHelper.getName(btInfo.mDevice); + final int a2dpCodec = btInfo.mCodec; + // enable A2DP before notifying A2DP connection to avoid unnecessary processing in // audio policy manager mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource); // at this point there could be another A2DP device already connected in APM, but it // doesn't matter as this new one will overwrite the previous one - final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes( - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name), + AudioDeviceAttributes ada = new AudioDeviceAttributes( + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name); + final int res = mAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec); // TODO: log in MediaMetrics once distinction between connection failure and @@ -1167,13 +1480,12 @@ public class AudioDeviceInventory { } // Reset A2DP suspend state each time a new sink is connected - mAudioSystem.setParameters("A2dpSuspended=false"); + mDeviceBroker.clearA2dpSuspended(); // The convention for head tracking sensors associated with A2DP devices is to // use a UUID derived from the MAC address as follows: // time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address - UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes( - new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address)); + UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada); final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name, address, a2dpCodec, sensorUuid); final String diKey = di.getKey(); @@ -1184,6 +1496,206 @@ public class AudioDeviceInventory { mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/); + + updateBluetoothPreferredModes_l(); + mDeviceBroker.postNotifyPreferredAudioProfileApplied(btInfo.mDevice); + } + + static final int[] CAPTURE_PRESETS = new int[] {AudioSource.MIC, AudioSource.CAMCORDER, + AudioSource.VOICE_RECOGNITION, AudioSource.VOICE_COMMUNICATION, + AudioSource.UNPROCESSED, AudioSource.VOICE_PERFORMANCE, AudioSource.HOTWORD}; + + // reflects system property persist.bluetooth.enable_dual_mode_audio + final boolean mBluetoothDualModeEnabled; + /** + * Goes over all connected Bluetooth devices and set the audio policy device role to DISABLED + * or not according to their own and other devices modes. + * The top priority is given to LE devices, then SCO ,then A2DP. + */ + @GuardedBy("mDevicesLock") + private void applyConnectedDevicesRoles_l() { + if (!mBluetoothDualModeEnabled) { + return; + } + DeviceInfo leOutDevice = + getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_BLE_SET); + DeviceInfo leInDevice = + getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_BLE_SET); + DeviceInfo a2dpDevice = + getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_A2DP_SET); + DeviceInfo scoOutDevice = + getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_SCO_SET); + DeviceInfo scoInDevice = + getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_SCO_SET); + boolean disableA2dp = (leOutDevice != null && leOutDevice.isOutputOnlyModeEnabled()); + boolean disableSco = (leOutDevice != null && leOutDevice.isDuplexModeEnabled()) + || (leInDevice != null && leInDevice.isDuplexModeEnabled()); + AudioDeviceAttributes communicationDevice = + mDeviceBroker.mActiveCommunicationDevice == null + ? null : ((mDeviceBroker.isInCommunication() + && mDeviceBroker.mActiveCommunicationDevice != null) + ? new AudioDeviceAttributes(mDeviceBroker.mActiveCommunicationDevice) + : null); + + if (AudioService.DEBUG_DEVICES) { + Log.i(TAG, "applyConnectedDevicesRoles_l\n - leOutDevice: " + leOutDevice + + "\n - leInDevice: " + leInDevice + + "\n - a2dpDevice: " + a2dpDevice + + "\n - scoOutDevice: " + scoOutDevice + + "\n - scoInDevice: " + scoInDevice + + "\n - disableA2dp: " + disableA2dp + + ", disableSco: " + disableSco); + } + + for (DeviceInfo di : mConnectedDevices.values()) { + if (!AudioSystem.isBluetoothDevice(di.mDeviceType)) { + continue; + } + AudioDeviceAttributes ada = + new AudioDeviceAttributes(di.mDeviceType, di.mDeviceAddress, di.mDeviceName); + if (AudioService.DEBUG_DEVICES) { + Log.i(TAG, " + checking Device: " + ada); + } + if (ada.equalTypeAddress(communicationDevice)) { + continue; + } + + if (AudioSystem.isBluetoothOutDevice(di.mDeviceType)) { + for (AudioProductStrategy strategy : mStrategies) { + boolean disable = false; + if (strategy.getId() == mDeviceBroker.mCommunicationStrategyId) { + if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) { + disable = disableSco || !di.isDuplexModeEnabled(); + } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) { + disable = !di.isDuplexModeEnabled(); + } + } else { + if (AudioSystem.isBluetoothA2dpOutDevice(di.mDeviceType)) { + disable = disableA2dp || !di.isOutputOnlyModeEnabled(); + } else if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) { + disable = disableSco || !di.isOutputOnlyModeEnabled(); + } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) { + disable = !di.isOutputOnlyModeEnabled(); + } + } + if (AudioService.DEBUG_DEVICES) { + Log.i(TAG, " - strategy: " + strategy.getId() + + ", disable: " + disable); + } + if (disable) { + addDevicesRoleForStrategy(strategy.getId(), + AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada)); + } else { + removeDevicesRoleForStrategy(strategy.getId(), + AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada)); + } + } + } + if (AudioSystem.isBluetoothInDevice(di.mDeviceType)) { + for (int capturePreset : CAPTURE_PRESETS) { + boolean disable = false; + if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) { + disable = disableSco || !di.isDuplexModeEnabled(); + } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) { + disable = !di.isDuplexModeEnabled(); + } + if (AudioService.DEBUG_DEVICES) { + Log.i(TAG, " - capturePreset: " + capturePreset + + ", disable: " + disable); + } + if (disable) { + addDevicesRoleForCapturePreset(capturePreset, + AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada)); + } else { + removeDevicesRoleForCapturePreset(capturePreset, + AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada)); + } + } + } + } + } + + /* package */ void applyConnectedDevicesRoles() { + synchronized (mDevicesLock) { + applyConnectedDevicesRoles_l(); + } + } + + @GuardedBy("mDevicesLock") + int checkProfileIsConnected(int profile) { + switch (profile) { + case BluetoothProfile.HEADSET: + if (getFirstConnectedDeviceOfTypes( + AudioSystem.DEVICE_OUT_ALL_SCO_SET) != null + || getFirstConnectedDeviceOfTypes( + AudioSystem.DEVICE_IN_ALL_SCO_SET) != null) { + return profile; + } + break; + case BluetoothProfile.A2DP: + if (getFirstConnectedDeviceOfTypes( + AudioSystem.DEVICE_OUT_ALL_A2DP_SET) != null) { + return profile; + } + break; + case BluetoothProfile.LE_AUDIO: + case BluetoothProfile.LE_AUDIO_BROADCAST: + if (getFirstConnectedDeviceOfTypes( + AudioSystem.DEVICE_OUT_ALL_BLE_SET) != null + || getFirstConnectedDeviceOfTypes( + AudioSystem.DEVICE_IN_ALL_BLE_SET) != null) { + return profile; + } + break; + default: + break; + } + return 0; + } + + @GuardedBy("mDevicesLock") + private void updateBluetoothPreferredModes_l() { + if (!mBluetoothDualModeEnabled) { + return; + } + HashSet<String> processedAddresses = new HashSet<>(0); + for (DeviceInfo di : mConnectedDevices.values()) { + if (!AudioSystem.isBluetoothDevice(di.mDeviceType) + || processedAddresses.contains(di.mDeviceAddress)) { + continue; + } + Bundle preferredProfiles = BtHelper.getPreferredAudioProfiles(di.mDeviceAddress); + if (AudioService.DEBUG_DEVICES) { + Log.i(TAG, "updateBluetoothPreferredModes_l processing device address: " + + di.mDeviceAddress + ", preferredProfiles: " + preferredProfiles); + } + for (DeviceInfo di2 : mConnectedDevices.values()) { + if (!AudioSystem.isBluetoothDevice(di2.mDeviceType) + || !di.mDeviceAddress.equals(di2.mDeviceAddress)) { + continue; + } + int profile = BtHelper.getProfileFromType(di2.mDeviceType); + if (profile == 0) { + continue; + } + int preferredProfile = checkProfileIsConnected( + preferredProfiles.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX)); + if (preferredProfile == profile || preferredProfile == 0) { + di2.setModeEnabled(BluetoothAdapter.AUDIO_MODE_DUPLEX); + } else { + di2.setModeDisabled(BluetoothAdapter.AUDIO_MODE_DUPLEX); + } + preferredProfile = checkProfileIsConnected( + preferredProfiles.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY)); + if (preferredProfile == profile || preferredProfile == 0) { + di2.setModeEnabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY); + } else { + di2.setModeDisabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY); + } + } + processedAddresses.add(di.mDeviceAddress); + } + applyConnectedDevicesRoles_l(); } @GuardedBy("mDevicesLock") @@ -1231,13 +1743,17 @@ public class AudioDeviceInventory { // Remove A2DP routes as well setCurrentAudioRouteNameIfPossible(null, true /*fromA2dp*/); mmi.record(); + + updateBluetoothPreferredModes_l(); + purgeDevicesRoles_l(); } @GuardedBy("mDevicesLock") private void makeA2dpDeviceUnavailableLater(String address, int delayMs) { // prevent any activity on the A2DP audio output to avoid unwanted // reconnection of the sink. - mAudioSystem.setParameters("A2dpSuspended=true"); + mDeviceBroker.setA2dpSuspended( + true /*enable*/, true /*internal*/, "makeA2dpDeviceUnavailableLater"); // retrieve DeviceInfo before removing device final String deviceKey = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address); @@ -1259,8 +1775,7 @@ public class AudioDeviceInventory { AudioSystem.AUDIO_FORMAT_DEFAULT); mConnectedDevices.put( DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address), - new DeviceInfo(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "", - address, AudioSystem.AUDIO_FORMAT_DEFAULT)); + new DeviceInfo(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "", address)); } @GuardedBy("mDevicesLock") @@ -1286,8 +1801,7 @@ public class AudioDeviceInventory { AudioSystem.AUDIO_FORMAT_DEFAULT); mConnectedDevices.put( DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address), - new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name, - address, AudioSystem.AUDIO_FORMAT_DEFAULT)); + new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name, address)); mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID); mDeviceBroker.postApplyVolumeOnDevice(streamType, AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable"); @@ -1325,29 +1839,56 @@ public class AudioDeviceInventory { * @return true if a DEVICE_OUT_HEARING_AID is connected, false otherwise. */ boolean isHearingAidConnected() { + return getFirstConnectedDeviceOfTypes( + Sets.newHashSet(AudioSystem.DEVICE_OUT_HEARING_AID)) != null; + } + + /** + * Returns a DeviceInfo for the fist connected device matching one of the supplied types + */ + private DeviceInfo getFirstConnectedDeviceOfTypes(Set<Integer> internalTypes) { + List<DeviceInfo> devices = getConnectedDevicesOfTypes(internalTypes); + return devices.isEmpty() ? null : devices.get(0); + } + + /** + * Returns a list of connected devices matching one one of the supplied types + */ + private List<DeviceInfo> getConnectedDevicesOfTypes(Set<Integer> internalTypes) { + ArrayList<DeviceInfo> devices = new ArrayList<>(); synchronized (mDevicesLock) { for (DeviceInfo di : mConnectedDevices.values()) { - if (di.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) { - return true; + if (internalTypes.contains(di.mDeviceType)) { + devices.add(di); } } - return false; } + return devices; + } + + /* package */ AudioDeviceAttributes getDeviceOfType(int type) { + DeviceInfo di = getFirstConnectedDeviceOfTypes(Sets.newHashSet(type)); + return di == null ? null : new AudioDeviceAttributes( + di.mDeviceType, di.mDeviceAddress, di.mDeviceName); } @GuardedBy("mDevicesLock") - private void makeLeAudioDeviceAvailable(String address, String name, int streamType, - int volumeIndex, int device, String eventSource) { + private void makeLeAudioDeviceAvailable( + AudioDeviceBroker.BtDeviceInfo btInfo, int streamType, String eventSource) { + final String address = btInfo.mDevice.getAddress(); + final String name = BtHelper.getName(btInfo.mDevice); + final int volumeIndex = btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10; + final int device = btInfo.mAudioSystemDevice; + if (device != AudioSystem.DEVICE_NONE) { /* Audio Policy sees Le Audio similar to A2DP. Let's make sure * AUDIO_POLICY_FORCE_NO_BT_A2DP is not set */ mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource); - final int res = AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes( - device, address, name), - AudioSystem.DEVICE_STATE_AVAILABLE, - AudioSystem.AUDIO_FORMAT_DEFAULT); + AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name); + final int res = AudioSystem.setDeviceConnectionState(ada, + AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT); if (res != AudioSystem.AUDIO_STATUS_OK) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "APM failed to make available LE Audio device addr=" + address @@ -1358,12 +1899,13 @@ public class AudioDeviceInventory { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "LE Audio device addr=" + address + " now available").printLog(TAG)); } - // Reset LEA suspend state each time a new sink is connected - mAudioSystem.setParameters("LeAudioSuspended=false"); + mDeviceBroker.clearLeAudioSuspended(); + UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada); mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address), - new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT)); + new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT, + sensorUuid)); mDeviceBroker.postAccessoryPlugMediaUnmute(device); setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false); } @@ -1379,6 +1921,9 @@ public class AudioDeviceInventory { final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType); mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType); mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable"); + + updateBluetoothPreferredModes_l(); + mDeviceBroker.postNotifyPreferredAudioProfileApplied(btInfo.mDevice); } @GuardedBy("mDevicesLock") @@ -1403,13 +1948,17 @@ public class AudioDeviceInventory { } setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/); + + updateBluetoothPreferredModes_l(); + purgeDevicesRoles_l(); } @GuardedBy("mDevicesLock") private void makeLeAudioDeviceUnavailableLater(String address, int device, int delayMs) { // prevent any activity on the LEA output to avoid unwanted // reconnection of the sink. - mAudioSystem.setParameters("LeAudioSuspended=true"); + mDeviceBroker.setLeAudioSuspended( + true /*enable*/, true /*internal*/, "makeLeAudioDeviceUnavailableLater"); // the device will be made unavailable later, so consider it disconnected right away mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address)); // send the delayed message to make the device unavailable later @@ -1737,18 +2286,6 @@ public class AudioDeviceInventory { } } - /* package */ AudioDeviceAttributes getDeviceOfType(int type) { - synchronized (mDevicesLock) { - for (DeviceInfo di : mConnectedDevices.values()) { - if (di.mDeviceType == type) { - return new AudioDeviceAttributes( - di.mDeviceType, di.mDeviceAddress, di.mDeviceName); - } - } - } - return null; - } - //---------------------------------------------------------- // For tests only @@ -1759,10 +2296,12 @@ public class AudioDeviceInventory { */ @VisibleForTesting public boolean isA2dpDeviceConnected(@NonNull BluetoothDevice device) { - final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, - device.getAddress()); - synchronized (mDevicesLock) { - return (mConnectedDevices.get(key) != null); + for (DeviceInfo di : getConnectedDevicesOfTypes( + Sets.newHashSet(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP))) { + if (di.mDeviceAddress.equals(device.getAddress())) { + return true; + } } + return false; } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index ac55f28a8ab0..a3163e010efa 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6376,6 +6376,26 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.setBluetoothScoOn(on, eventSource); } + /** @see AudioManager#setA2dpSuspended(boolean) */ + @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setA2dpSuspended(boolean enable) { + super.setA2dpSuspended_enforcePermission(); + final String eventSource = new StringBuilder("setA2dpSuspended(").append(enable) + .append(") from u/pid:").append(Binder.getCallingUid()).append("/") + .append(Binder.getCallingPid()).toString(); + mDeviceBroker.setA2dpSuspended(enable, false /*internal*/, eventSource); + } + + /** @see AudioManager#setA2dpSuspended(boolean) */ + @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK) + public void setLeAudioSuspended(boolean enable) { + super.setLeAudioSuspended_enforcePermission(); + final String eventSource = new StringBuilder("setLeAudioSuspended(").append(enable) + .append(") from u/pid:").append(Binder.getCallingUid()).append("/") + .append(Binder.getCallingPid()).toString(); + mDeviceBroker.setLeAudioSuspended(enable, false /*internal*/, eventSource); + } + /** @see AudioManager#isBluetoothScoOn() * Note that it doesn't report internal state, but state seen by apps (which may have * called setBluetoothScoOn() */ @@ -7053,13 +7073,16 @@ public class AudioService extends IAudioService.Stub return deviceSet.iterator().next(); } else { // Multiple device selection is either: + // - dock + one other device: give priority to dock in this case. // - speaker + one other device: give priority to speaker in this case. // - one A2DP device + another device: happens with duplicated output. In this case // retain the device on the A2DP output as the other must not correspond to an active // selection if not the speaker. // - HDMI-CEC system audio mode only output: give priority to available item in order. - if (deviceSet.contains(AudioSystem.DEVICE_OUT_SPEAKER)) { + if (deviceSet.contains(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET)) { + return AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET; + } else if (deviceSet.contains(AudioSystem.DEVICE_OUT_SPEAKER)) { return AudioSystem.DEVICE_OUT_SPEAKER; } else if (deviceSet.contains(AudioSystem.DEVICE_OUT_SPEAKER_SAFE)) { // Note: DEVICE_OUT_SPEAKER_SAFE not present in getDeviceSetForStreamDirect diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index 7af7ed5fff65..1142a8d64304 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -435,7 +435,7 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, } /** - * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, int[], String[])} + * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, List)} * @param capturePreset * @param role * @param devicesToRemove @@ -448,6 +448,19 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, } /** + * Same as {@link AudioSystem#addDevicesRoleForCapturePreset(int, int, List)} + * @param capturePreset the capture preset to configure + * @param role the role of the devices + * @param devices the list of devices to be added as role for the given capture preset + * @return {@link #SUCCESS} if successfully add + */ + public int addDevicesRoleForCapturePreset( + int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { + invalidateRoutingCache(); + return AudioSystem.addDevicesRoleForCapturePreset(capturePreset, role, devices); + } + + /** * Same as {@link AudioSystem#} * @param capturePreset * @param role diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 631d7f5a170d..e46c3cc4a285 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -33,6 +33,7 @@ import android.media.AudioManager; import android.media.AudioSystem; import android.media.BluetoothProfileConnectionInfo; import android.os.Binder; +import android.os.Bundle; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -150,60 +151,12 @@ public class BtHelper { } } - //---------------------------------------------------------------------- - /*package*/ static class BluetoothA2dpDeviceInfo { - private final @NonNull BluetoothDevice mBtDevice; - private final int mVolume; - private final @AudioSystem.AudioFormatNativeEnumForBtCodec int mCodec; - - BluetoothA2dpDeviceInfo(@NonNull BluetoothDevice btDevice) { - this(btDevice, -1, AudioSystem.AUDIO_FORMAT_DEFAULT); - } - - BluetoothA2dpDeviceInfo(@NonNull BluetoothDevice btDevice, int volume, int codec) { - mBtDevice = btDevice; - mVolume = volume; - mCodec = codec; - } - - public @NonNull BluetoothDevice getBtDevice() { - return mBtDevice; - } - - public int getVolume() { - return mVolume; - } - - public @AudioSystem.AudioFormatNativeEnumForBtCodec int getCodec() { - return mCodec; - } - - // redefine equality op so we can match messages intended for this device - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - if (this == o) { - return true; - } - if (o instanceof BluetoothA2dpDeviceInfo) { - return mBtDevice.equals(((BluetoothA2dpDeviceInfo) o).getBtDevice()); - } - return false; - } - - - } - // A2DP device events /*package*/ static final int EVENT_DEVICE_CONFIG_CHANGE = 0; - /*package*/ static final int EVENT_ACTIVE_DEVICE_CHANGE = 1; - /*package*/ static String a2dpDeviceEventToString(int event) { + /*package*/ static String deviceEventToString(int event) { switch (event) { case EVENT_DEVICE_CONFIG_CHANGE: return "DEVICE_CONFIG_CHANGE"; - case EVENT_ACTIVE_DEVICE_CHANGE: return "ACTIVE_DEVICE_CHANGE"; default: return new String("invalid event:" + event); } @@ -492,8 +445,8 @@ public class BtHelper { /*package*/ synchronized void resetBluetoothSco() { mScoAudioState = SCO_STATE_INACTIVE; broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - AudioSystem.setParameters("A2dpSuspended=false"); - AudioSystem.setParameters("LeAudioSuspended=false"); + mDeviceBroker.clearA2dpSuspended(); + mDeviceBroker.clearLeAudioSuspended(); mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco"); } @@ -620,11 +573,12 @@ public class BtHelper { return btHeadsetDeviceToAudioDevice(mBluetoothHeadsetDevice); } - private AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) { + private static AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) { if (btDevice == null) { return new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""); } String address = btDevice.getAddress(); + String name = getName(btDevice); if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } @@ -646,7 +600,7 @@ public class BtHelper { + " btClass: " + (btClass == null ? "Unknown" : btClass) + " nativeType: " + nativeType + " address: " + address); } - return new AudioDeviceAttributes(nativeType, address); + return new AudioDeviceAttributes(nativeType, address, name); } private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) { @@ -655,12 +609,9 @@ public class BtHelper { } int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; AudioDeviceAttributes audioDevice = btHeadsetDeviceToAudioDevice(btDevice); - String btDeviceName = getName(btDevice); boolean result = false; if (isActive) { - result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes( - audioDevice.getInternalType(), audioDevice.getAddress(), btDeviceName), - isActive); + result |= mDeviceBroker.handleDeviceConnection(audioDevice, isActive, btDevice); } else { int[] outDeviceTypes = { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, @@ -669,14 +620,14 @@ public class BtHelper { }; for (int outDeviceType : outDeviceTypes) { result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes( - outDeviceType, audioDevice.getAddress(), btDeviceName), - isActive); + outDeviceType, audioDevice.getAddress(), audioDevice.getName()), + isActive, btDevice); } } // handleDeviceConnection() && result to make sure the method get executed result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes( - inDevice, audioDevice.getAddress(), btDeviceName), - isActive) && result; + inDevice, audioDevice.getAddress(), audioDevice.getName()), + isActive, btDevice) && result; return result; } @@ -973,6 +924,30 @@ public class BtHelper { } } + /*package */ static int getProfileFromType(int deviceType) { + if (AudioSystem.isBluetoothA2dpOutDevice(deviceType)) { + return BluetoothProfile.A2DP; + } else if (AudioSystem.isBluetoothScoDevice(deviceType)) { + return BluetoothProfile.HEADSET; + } else if (AudioSystem.isBluetoothLeDevice(deviceType)) { + return BluetoothProfile.LE_AUDIO; + } + return 0; // 0 is not a valid profile + } + + /*package */ static Bundle getPreferredAudioProfiles(String address) { + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + return adapter.getPreferredAudioProfiles(adapter.getRemoteDevice(address)); + } + + /** + * Notifies Bluetooth framework that new preferred audio profiles for Bluetooth devices + * have been applied. + */ + public static void onNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) { + BluetoothAdapter.getDefaultAdapter().notifyActiveDeviceChangeApplied(btDevice); + } + /** * Returns the string equivalent for the btDeviceClass class. */ diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index 7c8e6df4acdc..5127d26e6e73 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -19,6 +19,8 @@ package com.android.server.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; +import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR; +import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR_BASE; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE; @@ -519,6 +521,9 @@ public final class AuthSession implements IBinder.DeathRecipient { try { mStatusBarService.onBiometricHelp(sensorIdToModality(sensorId), message); + final int aAcquiredInfo = acquiredInfo == FINGERPRINT_ACQUIRED_VENDOR + ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquiredInfo; + mClientReceiver.onAcquired(aAcquiredInfo, message); } catch (RemoteException e) { Slog.e(TAG, "Remote exception", e); } diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java index 937e3f8f8668..bac44809883f 100644 --- a/services/core/java/com/android/server/biometrics/BiometricSensor.java +++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java @@ -22,14 +22,20 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricConstants; +import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricSensorReceiver; +import android.hardware.biometrics.SensorPropertiesInternal; import android.os.IBinder; import android.os.RemoteException; +import android.text.TextUtils; +import android.util.IndentingPrintWriter; import android.util.Slog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.List; /** * Wraps IBiometricAuthenticator implementation and stores information about the authenticator, @@ -67,6 +73,7 @@ public abstract class BiometricSensor { public final int id; public final @Authenticators.Types int oemStrength; // strength as configured by the OEM public final int modality; + @NonNull public final List<ComponentInfoInternal> componentInfo; public final IBiometricAuthenticator impl; private @Authenticators.Types int mUpdatedStrength; // updated by BiometricStrengthController @@ -86,15 +93,16 @@ public abstract class BiometricSensor { */ abstract boolean confirmationSupported(); - BiometricSensor(@NonNull Context context, int id, int modality, - @Authenticators.Types int strength, IBiometricAuthenticator impl) { + BiometricSensor(@NonNull Context context, int modality, @NonNull SensorPropertiesInternal props, + IBiometricAuthenticator impl) { this.mContext = context; - this.id = id; + this.id = props.sensorId; this.modality = modality; - this.oemStrength = strength; + this.oemStrength = Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength); + this.componentInfo = Collections.unmodifiableList(props.componentInfo); this.impl = impl; - mUpdatedStrength = strength; + mUpdatedStrength = oemStrength; goToStateUnknown(); } @@ -178,8 +186,25 @@ public abstract class BiometricSensor { return "ID(" + id + ")" + ", oemStrength: " + oemStrength + ", updatedStrength: " + mUpdatedStrength - + ", modality " + modality + + ", modality: " + modality + ", state: " + mSensorState + ", cookie: " + mCookie; } + + protected void dump(@NonNull IndentingPrintWriter pw) { + pw.println(TextUtils.formatSimple("ID: %d", id)); + pw.increaseIndent(); + pw.println(TextUtils.formatSimple("oemStrength: %d", oemStrength)); + pw.println(TextUtils.formatSimple("updatedStrength: %d", mUpdatedStrength)); + pw.println(TextUtils.formatSimple("modality: %d", modality)); + pw.println("componentInfo:"); + for (ComponentInfoInternal info : componentInfo) { + pw.increaseIndent(); + info.dump(pw); + pw.decreaseIndent(); + } + pw.println(TextUtils.formatSimple("state: %d", mSensorState)); + pw.println(TextUtils.formatSimple("cookie: %d", mCookie)); + pw.decreaseIndent(); + } } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index ffa5d2055e92..f44d14bfa12c 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -62,6 +62,7 @@ import android.provider.Settings; import android.security.KeyStore; import android.text.TextUtils; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.Pair; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -638,13 +639,16 @@ public class BiometricService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override - public synchronized void registerAuthenticator(int id, int modality, - @Authenticators.Types int strength, + public synchronized void registerAuthenticator(int modality, + @NonNull SensorPropertiesInternal props, @NonNull IBiometricAuthenticator authenticator) { super.registerAuthenticator_enforcePermission(); - Slog.d(TAG, "Registering ID: " + id + @Authenticators.Types final int strength = + Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength); + + Slog.d(TAG, "Registering ID: " + props.sensorId + " Modality: " + modality + " Strength: " + strength); @@ -665,12 +669,12 @@ public class BiometricService extends SystemService { } for (BiometricSensor sensor : mSensors) { - if (sensor.id == id) { + if (sensor.id == props.sensorId) { throw new IllegalStateException("Cannot register duplicate authenticator"); } } - mSensors.add(new BiometricSensor(getContext(), id, modality, strength, authenticator) { + mSensors.add(new BiometricSensor(getContext(), modality, props, authenticator) { @Override boolean confirmationAlwaysRequired(int userId) { return mSettingObserver.getConfirmationAlwaysRequired(modality, userId); @@ -1360,13 +1364,17 @@ public class BiometricService extends SystemService { return null; } - private void dumpInternal(PrintWriter pw) { + private void dumpInternal(PrintWriter printWriter) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter); + pw.println("Legacy Settings: " + mSettingObserver.mUseLegacyFaceOnlySettings); pw.println(); pw.println("Sensors:"); for (BiometricSensor sensor : mSensors) { - pw.println(" " + sensor); + pw.increaseIndent(); + sensor.dump(pw); + pw.decreaseIndent(); } pw.println(); pw.println("CurrentSession: " + mAuthSession); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java index 0f0a81d24473..d43045b4450f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceServiceRegistry.java @@ -20,7 +20,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.IBiometricService; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; @@ -28,7 +27,6 @@ import android.hardware.face.IFaceService; import android.os.RemoteException; import android.util.Slog; -import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.BiometricServiceRegistry; import java.util.List; @@ -53,10 +51,8 @@ public class FaceServiceRegistry extends BiometricServiceRegistry<ServiceProvide @Override protected void registerService(@NonNull IBiometricService service, @NonNull FaceSensorPropertiesInternal props) { - @BiometricManager.Authenticators.Types final int strength = - Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength); try { - service.registerAuthenticator(props.sensorId, TYPE_FACE, strength, + service.registerAuthenticator(TYPE_FACE, props, new FaceAuthenticator(mService, props.sensorId)); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when registering sensorId: " + props.sensorId); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index 7ae31b2a114d..50d375c56f4a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -212,6 +212,8 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession, FaceAut // 1) Authenticated == true // 2) Error occurred // 3) Authenticated == false + // 4) onLockout + // 5) onLockoutTimed mCallback.onClientFinished(this, true /* success */); } @@ -304,11 +306,7 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession, FaceAut PerformanceTracker.getInstanceForSensorId(getSensorId()) .incrementTimedLockoutForUser(getTargetUserId()); - try { - getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - } + onError(error, 0 /* vendorCode */); } @Override @@ -323,10 +321,6 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession, FaceAut PerformanceTracker.getInstanceForSensorId(getSensorId()) .incrementPermanentLockoutForUser(getTargetUserId()); - try { - getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - } + onError(error, 0 /* vendorCode */); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index 1a53fec82d98..c5037b7012f2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -465,7 +465,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { BaseClientMonitor clientMonitor, boolean success) { mAuthSessionCoordinator.authEndedFor(userId, Utils.getCurrentStrength(sensorId), - sensorId, requestId, success); + sensorId, requestId, client.wasAuthSuccessful()); } }); }); 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 128ef0b2a802..6c26e2b0ce99 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 @@ -413,6 +413,11 @@ public class FingerprintService extends SystemService { Slog.e(TAG, "Remote exception in onAuthenticationAcquired()", e); } } + + @Override + public void onAuthenticationHelp(int acquireInfo, CharSequence helpString) { + onAuthenticationAcquired(acquireInfo); + } }; return biometricPrompt.authenticateForOperation( diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java index 33810b764f23..6d210eac542b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistry.java @@ -20,7 +20,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.IBiometricService; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; @@ -28,7 +27,6 @@ import android.hardware.fingerprint.IFingerprintService; import android.os.RemoteException; import android.util.Slog; -import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.BiometricServiceRegistry; import java.util.List; @@ -53,10 +51,8 @@ public class FingerprintServiceRegistry extends BiometricServiceRegistry<Service @Override protected void registerService(@NonNull IBiometricService service, @NonNull FingerprintSensorPropertiesInternal props) { - @BiometricManager.Authenticators.Types final int strength = - Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength); try { - service.registerAuthenticator(props.sensorId, TYPE_FINGERPRINT, strength, + service.registerAuthenticator(TYPE_FINGERPRINT, props, new FingerprintAuthenticator(mService, props.sensorId)); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when registering sensorId: " + props.sensorId); diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java index 35ea36c5d56f..f27761fd644c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java @@ -16,12 +16,10 @@ package com.android.server.biometrics.sensors.iris; -import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import android.annotation.NonNull; import android.content.Context; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.iris.IIrisService; @@ -33,7 +31,6 @@ import android.util.Slog; import com.android.server.ServiceThread; import com.android.server.SystemService; -import com.android.server.biometrics.Utils; import java.util.List; @@ -75,17 +72,12 @@ public class IrisService extends SystemService { ServiceManager.getService(Context.BIOMETRIC_SERVICE)); for (SensorPropertiesInternal hidlSensor : hidlSensors) { - final int sensorId = hidlSensor.sensorId; - final @BiometricManager.Authenticators.Types int strength = - Utils.propertyStrengthToAuthenticatorStrength( - hidlSensor.sensorStrength); - final IrisAuthenticator authenticator = new IrisAuthenticator(mServiceWrapper, - sensorId); try { - biometricService.registerAuthenticator(sensorId, TYPE_IRIS, strength, - authenticator); + biometricService.registerAuthenticator(TYPE_IRIS, hidlSensor, + new IrisAuthenticator(mServiceWrapper, hidlSensor.sensorId)); } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId); + Slog.e(TAG, "Remote exception when registering sensorId: " + + hidlSensor.sensorId); } } }); diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index b25206d3b621..0f17139e2678 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -969,15 +969,21 @@ public class Vpn { // Allow VpnManager app to temporarily run background services to handle this error. // If an app requires anything beyond this grace period, they MUST either declare // themselves as a foreground service, or schedule a job/workitem. - DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal(); - idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName, - VPN_MANAGER_EVENT_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN, - "VpnManager event"); + final long token = Binder.clearCallingIdentity(); try { - return mUserIdContext.startService(intent) != null; - } catch (RuntimeException e) { - Log.e(TAG, "Service of VpnManager app " + intent + " failed to start", e); - return false; + final DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal(); + idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName, + VPN_MANAGER_EVENT_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN, + "VpnManager event"); + + try { + return mUserIdContext.startService(intent) != null; + } catch (RuntimeException e) { + Log.e(TAG, "Service of VpnManager app " + intent + " failed to start", e); + return false; + } + } finally { + Binder.restoreCallingIdentity(token); } } @@ -3391,6 +3397,7 @@ public class Vpn { * consistency of the Ikev2VpnRunner fields. */ public void onDefaultNetworkChanged(@NonNull Network network) { + mEventChanges.log("[UnderlyingNW] Default network changed to " + network); Log.d(TAG, "onDefaultNetworkChanged: " + network); // If there is a new default network brought up, cancel the retry task to prevent @@ -3628,6 +3635,7 @@ public class Vpn { mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) .setTransportInfo(info) .build(); + mEventChanges.log("[VPNRunner] Update agent caps " + mNetworkCapabilities); doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities); } } @@ -3664,6 +3672,7 @@ public class Vpn { private void startIkeSession(@NonNull Network underlyingNetwork) { Log.d(TAG, "Start new IKE session on network " + underlyingNetwork); + mEventChanges.log("[IKE] Start IKE session over " + underlyingNetwork); try { // Clear mInterface to prevent Ikev2VpnRunner being cleared when @@ -3778,6 +3787,7 @@ public class Vpn { } public void onValidationStatus(int status) { + mEventChanges.log("[Validation] validation status " + status); if (status == NetworkAgent.VALIDATION_STATUS_VALID) { // No data stall now. Reset it. mExecutor.execute(() -> { @@ -3818,6 +3828,7 @@ public class Vpn { * consistency of the Ikev2VpnRunner fields. */ public void onDefaultNetworkLost(@NonNull Network network) { + mEventChanges.log("[UnderlyingNW] Network lost " + network); // If the default network is torn down, there is no need to call // startOrMigrateIkeSession() since it will always check if there is an active network // can be used or not. @@ -3936,6 +3947,8 @@ public class Vpn { * consistency of the Ikev2VpnRunner fields. */ public void onSessionLost(int token, @Nullable Exception exception) { + mEventChanges.log("[IKE] Session lost on network " + mActiveNetwork + + (null == exception ? "" : " reason " + exception.getMessage())); Log.d(TAG, "onSessionLost() called for token " + token); if (!isActiveToken(token)) { @@ -4092,6 +4105,7 @@ public class Vpn { * consistency of the Ikev2VpnRunner fields. */ private void disconnectVpnRunner() { + mEventChanges.log("[VPNRunner] Disconnect runner, underlying network" + mActiveNetwork); mActiveNetwork = null; mUnderlyingNetworkCapabilities = null; mUnderlyingLinkProperties = null; diff --git a/services/core/java/com/android/server/display/BrightnessThrottler.java b/services/core/java/com/android/server/display/BrightnessThrottler.java index 067a2d6d8b0d..cfdcd636904b 100644 --- a/services/core/java/com/android/server/display/BrightnessThrottler.java +++ b/services/core/java/com/android/server/display/BrightnessThrottler.java @@ -36,8 +36,8 @@ import android.provider.DeviceConfigInterface; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData; -import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel; +import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData; +import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel; import java.io.PrintWriter; import java.util.ArrayList; @@ -69,12 +69,12 @@ class BrightnessThrottler { // Maps the throttling ID to the data. Sourced from DisplayDeviceConfig. @NonNull - private HashMap<String, BrightnessThrottlingData> mDdcThrottlingDataMap; + private HashMap<String, ThermalBrightnessThrottlingData> mDdcThermalThrottlingDataMap; // Current throttling data being used. // Null if we do not support throttling. @Nullable - private BrightnessThrottlingData mThrottlingData; + private ThermalBrightnessThrottlingData mThermalThrottlingData; private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX; private @BrightnessInfo.BrightnessMaxReason int mBrightnessMaxReason = @@ -82,51 +82,53 @@ class BrightnessThrottler { private String mUniqueDisplayId; // The most recent string that has been set from DeviceConfig - private String mBrightnessThrottlingDataString; + private String mThermalBrightnessThrottlingDataString; // The brightness throttling configuration that should be used. - private String mBrightnessThrottlingDataId; + private String mThermalBrightnessThrottlingDataId; // This is a collection of brightness throttling data that has been written as overrides from // the DeviceConfig. This will always take priority over the display device config data. // We need to store the data for every display device, so we do not need to update this each // time the underlying display device changes. // This map is indexed by uniqueDisplayId, to provide maps for throttlingId -> throttlingData. - // HashMap< uniqueDisplayId, HashMap< throttlingDataId, BrightnessThrottlingData >> - private final HashMap<String, HashMap<String, BrightnessThrottlingData>> - mBrightnessThrottlingDataOverride = new HashMap<>(1); + // HashMap< uniqueDisplayId, HashMap< throttlingDataId, ThermalBrightnessThrottlingData >> + private final HashMap<String, HashMap<String, ThermalBrightnessThrottlingData>> + mThermalBrightnessThrottlingDataOverride = new HashMap<>(1); BrightnessThrottler(Handler handler, Runnable throttlingChangeCallback, String uniqueDisplayId, String throttlingDataId, - @NonNull HashMap<String, BrightnessThrottlingData> brightnessThrottlingDataMap) { + @NonNull HashMap<String, ThermalBrightnessThrottlingData> + thermalBrightnessThrottlingDataMap) { this(new Injector(), handler, handler, throttlingChangeCallback, - uniqueDisplayId, throttlingDataId, brightnessThrottlingDataMap); + uniqueDisplayId, throttlingDataId, thermalBrightnessThrottlingDataMap); } @VisibleForTesting BrightnessThrottler(Injector injector, Handler handler, Handler deviceConfigHandler, Runnable throttlingChangeCallback, String uniqueDisplayId, String throttlingDataId, - @NonNull HashMap<String, BrightnessThrottlingData> brightnessThrottlingDataMap) { + @NonNull HashMap<String, ThermalBrightnessThrottlingData> + thermalBrightnessThrottlingDataMap) { mInjector = injector; mHandler = handler; mDeviceConfigHandler = deviceConfigHandler; - mDdcThrottlingDataMap = brightnessThrottlingDataMap; + mDdcThermalThrottlingDataMap = thermalBrightnessThrottlingDataMap; mThrottlingChangeCallback = throttlingChangeCallback; mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler); mUniqueDisplayId = uniqueDisplayId; mDeviceConfig = injector.getDeviceConfig(); mDeviceConfigListener = new DeviceConfigListener(); - mBrightnessThrottlingDataId = throttlingDataId; - mDdcThrottlingDataMap = brightnessThrottlingDataMap; - loadBrightnessThrottlingDataFromDeviceConfig(); - loadBrightnessThrottlingDataFromDisplayDeviceConfig(mDdcThrottlingDataMap, - mBrightnessThrottlingDataId, mUniqueDisplayId); + mThermalBrightnessThrottlingDataId = throttlingDataId; + mDdcThermalThrottlingDataMap = thermalBrightnessThrottlingDataMap; + loadThermalBrightnessThrottlingDataFromDeviceConfig(); + loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig(mDdcThermalThrottlingDataMap, + mThermalBrightnessThrottlingDataId, mUniqueDisplayId); } boolean deviceSupportsThrottling() { - return mThrottlingData != null; + return mThermalThrottlingData != null; } float getBrightnessCap() { @@ -154,14 +156,14 @@ class BrightnessThrottler { mThrottlingStatus = THROTTLING_INVALID; } - void loadBrightnessThrottlingDataFromDisplayDeviceConfig( - HashMap<String, BrightnessThrottlingData> ddcThrottlingDataMap, + void loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( + HashMap<String, ThermalBrightnessThrottlingData> ddcThrottlingDataMap, String brightnessThrottlingDataId, String uniqueDisplayId) { - mDdcThrottlingDataMap = ddcThrottlingDataMap; - mBrightnessThrottlingDataId = brightnessThrottlingDataId; + mDdcThermalThrottlingDataMap = ddcThrottlingDataMap; + mThermalBrightnessThrottlingDataId = brightnessThrottlingDataId; mUniqueDisplayId = uniqueDisplayId; - resetThrottlingData(); + resetThermalThrottlingData(); } private float verifyAndConstrainBrightnessCap(float brightness) { @@ -183,11 +185,11 @@ class BrightnessThrottler { private void thermalStatusChanged(@Temperature.ThrottlingStatus int newStatus) { if (mThrottlingStatus != newStatus) { mThrottlingStatus = newStatus; - updateThrottling(); + updateThermalThrottling(); } } - private void updateThrottling() { + private void updateThermalThrottling() { if (!deviceSupportsThrottling()) { return; } @@ -195,9 +197,9 @@ class BrightnessThrottler { float brightnessCap = PowerManager.BRIGHTNESS_MAX; int brightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; - if (mThrottlingStatus != THROTTLING_INVALID && mThrottlingData != null) { + if (mThrottlingStatus != THROTTLING_INVALID && mThermalThrottlingData != null) { // Throttling levels are sorted by increasing severity - for (ThrottlingLevel level : mThrottlingData.throttlingLevels) { + for (ThrottlingLevel level : mThermalThrottlingData.throttlingLevels) { if (level.thermalStatus <= mThrottlingStatus) { brightnessCap = level.brightness; brightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL; @@ -230,21 +232,23 @@ class BrightnessThrottler { private void dumpLocal(PrintWriter pw) { pw.println("BrightnessThrottler:"); - pw.println(" mBrightnessThrottlingDataId=" + mBrightnessThrottlingDataId); - pw.println(" mThrottlingData=" + mThrottlingData); + pw.println(" mThermalBrightnessThrottlingDataId=" + mThermalBrightnessThrottlingDataId); + pw.println(" mThermalThrottlingData=" + mThermalThrottlingData); pw.println(" mUniqueDisplayId=" + mUniqueDisplayId); pw.println(" mThrottlingStatus=" + mThrottlingStatus); pw.println(" mBrightnessCap=" + mBrightnessCap); pw.println(" mBrightnessMaxReason=" + BrightnessInfo.briMaxReasonToString(mBrightnessMaxReason)); - pw.println(" mDdcThrottlingDataMap=" + mDdcThrottlingDataMap); - pw.println(" mBrightnessThrottlingDataOverride=" + mBrightnessThrottlingDataOverride); - pw.println(" mBrightnessThrottlingDataString=" + mBrightnessThrottlingDataString); + pw.println(" mDdcThermalThrottlingDataMap=" + mDdcThermalThrottlingDataMap); + pw.println(" mThermalBrightnessThrottlingDataOverride=" + + mThermalBrightnessThrottlingDataOverride); + pw.println(" mThermalBrightnessThrottlingDataString=" + + mThermalBrightnessThrottlingDataString); mSkinThermalStatusObserver.dump(pw); } - private String getBrightnessThrottlingDataString() { + private String getThermalBrightnessThrottlingDataString() { return mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA, /* defaultValue= */ null); @@ -260,7 +264,7 @@ class BrightnessThrottler { // displayId, number, <state, val> * number // displayId, <number, <state, val> * number>, throttlingId private boolean parseAndAddData(@NonNull String strArray, - @NonNull HashMap<String, HashMap<String, BrightnessThrottlingData>> + @NonNull HashMap<String, HashMap<String, ThermalBrightnessThrottlingData>> displayIdToThrottlingIdToBtd) { boolean validConfig = true; String[] items = strArray.split(","); @@ -282,11 +286,11 @@ class BrightnessThrottler { } String throttlingDataId = (i < items.length) ? items[i++] : DEFAULT_ID; - BrightnessThrottlingData throttlingLevelsData = - DisplayDeviceConfig.BrightnessThrottlingData.create(throttlingLevels); + ThermalBrightnessThrottlingData throttlingLevelsData = + DisplayDeviceConfig.ThermalBrightnessThrottlingData.create(throttlingLevels); // Add throttlingLevelsData to inner map where necessary. - HashMap<String, BrightnessThrottlingData> throttlingMapForDisplay = + HashMap<String, ThermalBrightnessThrottlingData> throttlingMapForDisplay = displayIdToThrottlingIdToBtd.get(uniqueDisplayId); if (throttlingMapForDisplay == null) { throttlingMapForDisplay = new HashMap<>(); @@ -311,14 +315,14 @@ class BrightnessThrottler { return validConfig; } - private void loadBrightnessThrottlingDataFromDeviceConfig() { - HashMap<String, HashMap<String, BrightnessThrottlingData>> tempThrottlingData = + private void loadThermalBrightnessThrottlingDataFromDeviceConfig() { + HashMap<String, HashMap<String, ThermalBrightnessThrottlingData>> tempThrottlingData = new HashMap<>(1); - mBrightnessThrottlingDataString = getBrightnessThrottlingDataString(); + mThermalBrightnessThrottlingDataString = getThermalBrightnessThrottlingDataString(); boolean validConfig = true; - mBrightnessThrottlingDataOverride.clear(); - if (mBrightnessThrottlingDataString != null) { - String[] throttlingDataSplits = mBrightnessThrottlingDataString.split(";"); + mThermalBrightnessThrottlingDataOverride.clear(); + if (mThermalBrightnessThrottlingDataString != null) { + String[] throttlingDataSplits = mThermalBrightnessThrottlingDataString.split(";"); for (String s : throttlingDataSplits) { if (!parseAndAddData(s, tempThrottlingData)) { validConfig = false; @@ -327,26 +331,27 @@ class BrightnessThrottler { } if (validConfig) { - mBrightnessThrottlingDataOverride.putAll(tempThrottlingData); + mThermalBrightnessThrottlingDataOverride.putAll(tempThrottlingData); tempThrottlingData.clear(); } } else { - Slog.w(TAG, "DeviceConfig BrightnessThrottlingData is null"); + Slog.w(TAG, "DeviceConfig ThermalBrightnessThrottlingData is null"); } } - private void resetThrottlingData() { + private void resetThermalThrottlingData() { stop(); mDeviceConfigListener.startListening(); // Get throttling data for this id, if it exists - mThrottlingData = getConfigFromId(mBrightnessThrottlingDataId); + mThermalThrottlingData = getConfigFromId(mThermalBrightnessThrottlingDataId); // Fallback to default id otherwise. - if (!DEFAULT_ID.equals(mBrightnessThrottlingDataId) && mThrottlingData == null) { - mThrottlingData = getConfigFromId(DEFAULT_ID); + if (!DEFAULT_ID.equals(mThermalBrightnessThrottlingDataId) + && mThermalThrottlingData == null) { + mThermalThrottlingData = getConfigFromId(DEFAULT_ID); Slog.d(TAG, "Falling back to default throttling Id"); } @@ -355,17 +360,17 @@ class BrightnessThrottler { } } - private BrightnessThrottlingData getConfigFromId(String id) { - BrightnessThrottlingData returnValue; + private ThermalBrightnessThrottlingData getConfigFromId(String id) { + ThermalBrightnessThrottlingData returnValue; // Fallback pattern for fetching correct throttling data for this display and id. // 1) throttling data from device config for this throttling data id - returnValue = mBrightnessThrottlingDataOverride.get(mUniqueDisplayId) == null + returnValue = mThermalBrightnessThrottlingDataOverride.get(mUniqueDisplayId) == null ? null - : mBrightnessThrottlingDataOverride.get(mUniqueDisplayId).get(id); + : mThermalBrightnessThrottlingDataOverride.get(mUniqueDisplayId).get(id); // 2) throttling data from ddc for this throttling data id returnValue = returnValue == null - ? mDdcThrottlingDataMap.get(id) + ? mDdcThermalThrottlingDataMap.get(id) : returnValue; return returnValue; @@ -391,8 +396,8 @@ class BrightnessThrottler { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { - loadBrightnessThrottlingDataFromDeviceConfig(); - resetThrottlingData(); + loadThermalBrightnessThrottlingDataFromDeviceConfig(); + resetThermalThrottlingData(); } } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index da021158eb65..a021174e3031 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -687,8 +687,8 @@ public class DisplayDeviceConfig { private int[] mHighDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS; private int[] mHighAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS; - private final HashMap<String, BrightnessThrottlingData> - mBrightnessThrottlingDataMapByThrottlingId = new HashMap<>(); + private final HashMap<String, ThermalBrightnessThrottlingData> + mThermalBrightnessThrottlingDataMapByThrottlingId = new HashMap<>(); private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>> mRefreshRateThrottlingMap = new HashMap<>(); @@ -1348,9 +1348,9 @@ public class DisplayDeviceConfig { /** * @return brightness throttling configuration data for this display, for each throttling id. */ - public HashMap<String, BrightnessThrottlingData> - getBrightnessThrottlingDataMapByThrottlingId() { - return mBrightnessThrottlingDataMapByThrottlingId; + public HashMap<String, ThermalBrightnessThrottlingData> + getThermalBrightnessThrottlingDataMapByThrottlingId() { + return mThermalBrightnessThrottlingDataMapByThrottlingId; } /** @@ -1358,7 +1358,7 @@ public class DisplayDeviceConfig { * @return refresh rate throttling configuration */ @Nullable - public SparseArray<SurfaceControl.RefreshRateRange> getRefreshRateThrottlingData( + public SparseArray<SurfaceControl.RefreshRateRange> getThermalRefreshRateThrottlingData( @Nullable String id) { String key = id == null ? DEFAULT_ID : id; return mRefreshRateThrottlingMap.get(key); @@ -1525,8 +1525,8 @@ public class DisplayDeviceConfig { + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled + ", mHbmData=" + mHbmData + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline - + ", mBrightnessThrottlingDataMapByThrottlingId=" - + mBrightnessThrottlingDataMapByThrottlingId + + ", mThermalBrightnessThrottlingDataMapByThrottlingId=" + + mThermalBrightnessThrottlingDataMapByThrottlingId + "\n" + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease @@ -1887,11 +1887,11 @@ public class DisplayDeviceConfig { Slog.i(TAG, "No thermal throttling config found"); return; } - loadBrightnessThrottlingMaps(throttlingConfig); - loadRefreshRateThermalThrottlingMap(throttlingConfig); + loadThermalBrightnessThrottlingMaps(throttlingConfig); + loadThermalRefreshRateThrottlingMap(throttlingConfig); } - private void loadBrightnessThrottlingMaps(ThermalThrottling throttlingConfig) { + private void loadThermalBrightnessThrottlingMaps(ThermalThrottling throttlingConfig) { final List<BrightnessThrottlingMap> maps = throttlingConfig.getBrightnessThrottlingMap(); if (maps == null || maps.isEmpty()) { Slog.i(TAG, "No brightness throttling map found"); @@ -1901,7 +1901,7 @@ public class DisplayDeviceConfig { for (BrightnessThrottlingMap map : maps) { final List<BrightnessThrottlingPoint> points = map.getBrightnessThrottlingPoint(); // At least 1 point is guaranteed by the display device config schema - List<BrightnessThrottlingData.ThrottlingLevel> throttlingLevels = + List<ThermalBrightnessThrottlingData.ThrottlingLevel> throttlingLevels = new ArrayList<>(points.size()); boolean badConfig = false; @@ -1912,24 +1912,24 @@ public class DisplayDeviceConfig { break; } - throttlingLevels.add(new BrightnessThrottlingData.ThrottlingLevel( + throttlingLevels.add(new ThermalBrightnessThrottlingData.ThrottlingLevel( convertThermalStatus(status), point.getBrightness().floatValue())); } if (!badConfig) { String id = map.getId() == null ? DEFAULT_ID : map.getId(); - if (mBrightnessThrottlingDataMapByThrottlingId.containsKey(id)) { + if (mThermalBrightnessThrottlingDataMapByThrottlingId.containsKey(id)) { throw new RuntimeException("Brightness throttling data with ID " + id + " already exists"); } - mBrightnessThrottlingDataMapByThrottlingId.put(id, - BrightnessThrottlingData.create(throttlingLevels)); + mThermalBrightnessThrottlingDataMapByThrottlingId.put(id, + ThermalBrightnessThrottlingData.create(throttlingLevels)); } } } - private void loadRefreshRateThermalThrottlingMap(ThermalThrottling throttlingConfig) { + private void loadThermalRefreshRateThrottlingMap(ThermalThrottling throttlingConfig) { List<RefreshRateThrottlingMap> maps = throttlingConfig.getRefreshRateThrottlingMap(); if (maps == null || maps.isEmpty()) { Slog.w(TAG, "RefreshRateThrottling: map not found"); @@ -3039,7 +3039,7 @@ public class DisplayDeviceConfig { /** * Container for brightness throttling data. */ - public static class BrightnessThrottlingData { + public static class ThermalBrightnessThrottlingData { public List<ThrottlingLevel> throttlingLevels; static class ThrottlingLevel { @@ -3080,7 +3080,8 @@ public class DisplayDeviceConfig { /** * Creates multiple temperature based throttling levels of brightness */ - public static BrightnessThrottlingData create(List<ThrottlingLevel> throttlingLevels) { + public static ThermalBrightnessThrottlingData create( + List<ThrottlingLevel> throttlingLevels) { if (throttlingLevels == null || throttlingLevels.size() == 0) { Slog.e(TAG, "BrightnessThrottlingData received null or empty throttling levels"); return null; @@ -3118,12 +3119,12 @@ public class DisplayDeviceConfig { } } - return new BrightnessThrottlingData(throttlingLevels); + return new ThermalBrightnessThrottlingData(throttlingLevels); } @Override public String toString() { - return "BrightnessThrottlingData{" + return "ThermalBrightnessThrottlingData{" + "throttlingLevels:" + throttlingLevels + "} "; } @@ -3134,12 +3135,12 @@ public class DisplayDeviceConfig { return true; } - if (!(obj instanceof BrightnessThrottlingData)) { + if (!(obj instanceof ThermalBrightnessThrottlingData)) { return false; } - BrightnessThrottlingData otherBrightnessThrottlingData = (BrightnessThrottlingData) obj; - return throttlingLevels.equals(otherBrightnessThrottlingData.throttlingLevels); + ThermalBrightnessThrottlingData otherData = (ThermalBrightnessThrottlingData) obj; + return throttlingLevels.equals(otherData.throttlingLevels); } @Override @@ -3148,7 +3149,7 @@ public class DisplayDeviceConfig { } @VisibleForTesting - BrightnessThrottlingData(List<ThrottlingLevel> inLevels) { + ThermalBrightnessThrottlingData(List<ThrottlingLevel> inLevels) { throttlingLevels = new ArrayList<>(inLevels.size()); for (ThrottlingLevel level : inLevels) { throttlingLevels.add(new ThrottlingLevel(level.thermalStatus, level.brightness)); diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 2322e03d6d37..5e3990ac7167 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -515,8 +515,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private boolean mIsEnabled; private boolean mIsInTransition; - // The id of the brightness throttling policy that should be used. - private String mBrightnessThrottlingDataId; + // The id of the thermal brightness throttling policy that should be used. + private String mThermalBrightnessThrottlingDataId; // DPCs following the brightness of this DPC. This is used in concurrent displays mode - there // is one lead display, the additional displays follow the brightness value of the lead display. @@ -556,7 +556,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mHandler = new DisplayControllerHandler(handler.getLooper()); mLastBrightnessEvent = new BrightnessEvent(mDisplayId); mTempBrightnessEvent = new BrightnessEvent(mDisplayId); - mBrightnessThrottlingDataId = logicalDisplay.getBrightnessThrottlingDataIdLocked(); + mThermalBrightnessThrottlingDataId = + logicalDisplay.getThermalBrightnessThrottlingDataIdLocked(); if (mDisplayId == Display.DEFAULT_DISPLAY) { mBatteryStats = BatteryStatsService.getService(); @@ -891,8 +892,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); final boolean isEnabled = mLogicalDisplay.isEnabledLocked(); final boolean isInTransition = mLogicalDisplay.isInTransitionLocked(); - final String brightnessThrottlingDataId = - mLogicalDisplay.getBrightnessThrottlingDataIdLocked(); + final String thermalBrightnessThrottlingDataId = + mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked(); mHandler.postAtTime(() -> { boolean changed = false; if (mDisplayDevice != device) { @@ -901,7 +902,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mUniqueDisplayId = uniqueId; mDisplayStatsId = mUniqueDisplayId.hashCode(); mDisplayDeviceConfig = config; - mBrightnessThrottlingDataId = brightnessThrottlingDataId; + mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId; loadFromDisplayDeviceConfig(token, info, hbmMetadata); loadNitBasedBrightnessSetting(); @@ -909,12 +910,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // last command that was sent to change it's state. Let's assume it is unknown so // that we trigger a change immediately. mPowerState.resetScreenState(); - } else if (!mBrightnessThrottlingDataId.equals(brightnessThrottlingDataId)) { + } else if ( + !mThermalBrightnessThrottlingDataId.equals(thermalBrightnessThrottlingDataId)) { changed = true; - mBrightnessThrottlingDataId = brightnessThrottlingDataId; - mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig( - config.getBrightnessThrottlingDataMapByThrottlingId(), - mBrightnessThrottlingDataId, + mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId; + mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( + config.getThermalBrightnessThrottlingDataMapByThrottlingId(), + mThermalBrightnessThrottlingDataId, mUniqueDisplayId); } if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) { @@ -983,9 +985,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call sdrBrightness, maxDesiredHdrSdrRatio); } }); - mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig( - mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId(), - mBrightnessThrottlingDataId, mUniqueDisplayId); + mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( + mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(), + mThermalBrightnessThrottlingDataId, mUniqueDisplayId); } private void sendUpdatePowerState() { @@ -2121,8 +2123,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call () -> { sendUpdatePowerState(); postBrightnessChangeRunnable(); - }, mUniqueDisplayId, mLogicalDisplay.getBrightnessThrottlingDataIdLocked(), - ddConfig.getBrightnessThrottlingDataMapByThrottlingId()); + }, mUniqueDisplayId, mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked(), + ddConfig.getThermalBrightnessThrottlingDataMapByThrottlingId()); } private void blockScreenOn() { diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index d2af88b1c6c9..23e606c028ac 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -400,8 +400,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private boolean mIsEnabled; private boolean mIsInTransition; - // The id of the brightness throttling policy that should be used. - private String mBrightnessThrottlingDataId; + // The id of the thermal brightness throttling policy that should be used. + private String mThermalBrightnessThrottlingDataId; // DPCs following the brightness of this DPC. This is used in concurrent displays mode - there // is one lead display, the additional displays follow the brightness value of the lead display. @@ -439,7 +439,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController); mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(context, mDisplayId); mTag = "DisplayPowerController2[" + mDisplayId + "]"; - mBrightnessThrottlingDataId = logicalDisplay.getBrightnessThrottlingDataIdLocked(); + mThermalBrightnessThrottlingDataId = + logicalDisplay.getThermalBrightnessThrottlingDataIdLocked(); mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); @@ -707,8 +708,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); final boolean isEnabled = mLogicalDisplay.isEnabledLocked(); final boolean isInTransition = mLogicalDisplay.isInTransitionLocked(); - final String brightnessThrottlingDataId = - mLogicalDisplay.getBrightnessThrottlingDataIdLocked(); + final String thermalBrightnessThrottlingDataId = + mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked(); mHandler.postAtTime(() -> { boolean changed = false; @@ -718,7 +719,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mUniqueDisplayId = uniqueId; mDisplayStatsId = mUniqueDisplayId.hashCode(); mDisplayDeviceConfig = config; - mBrightnessThrottlingDataId = brightnessThrottlingDataId; + mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId; loadFromDisplayDeviceConfig(token, info, hbmMetadata); mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config); @@ -726,12 +727,13 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // last command that was sent to change it's state. Let's assume it is unknown so // that we trigger a change immediately. mPowerState.resetScreenState(); - } else if (!mBrightnessThrottlingDataId.equals(brightnessThrottlingDataId)) { + } else if ( + !mThermalBrightnessThrottlingDataId.equals(thermalBrightnessThrottlingDataId)) { changed = true; - mBrightnessThrottlingDataId = brightnessThrottlingDataId; - mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig( - config.getBrightnessThrottlingDataMapByThrottlingId(), - mBrightnessThrottlingDataId, + mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId; + mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( + config.getThermalBrightnessThrottlingDataMapByThrottlingId(), + mThermalBrightnessThrottlingDataId, mUniqueDisplayId); } if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) { @@ -797,9 +799,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal sdrBrightness, maxDesiredHdrSdrRatio); } }); - mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig( - mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId(), - mBrightnessThrottlingDataId, mUniqueDisplayId); + mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( + mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(), + mThermalBrightnessThrottlingDataId, mUniqueDisplayId); } private void sendUpdatePowerState() { @@ -1762,8 +1764,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal () -> { sendUpdatePowerState(); postBrightnessChangeRunnable(); - }, mUniqueDisplayId, mLogicalDisplay.getBrightnessThrottlingDataIdLocked(), - ddConfig.getBrightnessThrottlingDataMapByThrottlingId()); + }, mUniqueDisplayId, mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked(), + ddConfig.getThermalBrightnessThrottlingDataMapByThrottlingId()); } private void blockScreenOn() { diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index dee4cdea65fe..dab00d8070d4 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -175,11 +175,11 @@ final class LogicalDisplay { private boolean mDirty = false; /** - * The ID of the brightness throttling data that should be used. This can change e.g. in - * concurrent displays mode in which a stricter brightness throttling policy might need to be - * used. + * The ID of the thermal brightness throttling data that should be used. This can change e.g. + * in concurrent displays mode in which a stricter brightness throttling policy might need to + * be used. */ - private String mBrightnessThrottlingDataId; + private String mThermalBrightnessThrottlingDataId; public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) { mDisplayId = displayId; @@ -189,7 +189,7 @@ final class LogicalDisplay { mTempFrameRateOverride = new SparseArray<>(); mIsEnabled = true; mIsInTransition = false; - mBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID; + mThermalBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID; } public void setDevicePositionLocked(int position) { @@ -349,7 +349,7 @@ final class LogicalDisplay { * * @param refreshRanges new refreshRateThermalThrottling ranges limited by layout or default */ - public void updateRefreshRateThermalThrottling( + public void updateThermalRefreshRateThrottling( @Nullable SparseArray<SurfaceControl.RefreshRateRange> refreshRanges) { if (refreshRanges == null) { refreshRanges = new SparseArray<>(); @@ -872,16 +872,16 @@ final class LogicalDisplay { /** * @return The ID of the brightness throttling data that this display should use. */ - public String getBrightnessThrottlingDataIdLocked() { - return mBrightnessThrottlingDataId; + public String getThermalBrightnessThrottlingDataIdLocked() { + return mThermalBrightnessThrottlingDataId; } /** * @param brightnessThrottlingDataId The ID of the brightness throttling data that this * display should use. */ - public void setBrightnessThrottlingDataIdLocked(String brightnessThrottlingDataId) { - mBrightnessThrottlingDataId = + public void setThermalBrightnessThrottlingDataIdLocked(String brightnessThrottlingDataId) { + mThermalBrightnessThrottlingDataId = brightnessThrottlingDataId; } @@ -950,7 +950,7 @@ final class LogicalDisplay { pw.println("mFrameRateOverrides=" + Arrays.toString(mFrameRateOverrides)); pw.println("mPendingFrameRateOverrideUids=" + mPendingFrameRateOverrideUids); pw.println("mDisplayGroupName=" + mDisplayGroupName); - pw.println("mBrightnessThrottlingDataId=" + mBrightnessThrottlingDataId); + pw.println("mThermalBrightnessThrottlingDataId=" + mThermalBrightnessThrottlingDataId); pw.println("mLeadDisplayId=" + mLeadDisplayId); } diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 424eedc876ec..254441c2aa13 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -1022,17 +1022,17 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { newDisplay.updateLayoutLimitedRefreshRateLocked( config.getRefreshRange(displayLayout.getRefreshRateZoneId()) ); - newDisplay.updateRefreshRateThermalThrottling( - config.getRefreshRateThrottlingData( + newDisplay.updateThermalRefreshRateThrottling( + config.getThermalRefreshRateThrottlingData( displayLayout.getRefreshRateThermalThrottlingMapId() ) ); setEnabledLocked(newDisplay, displayLayout.isEnabled()); - newDisplay.setBrightnessThrottlingDataIdLocked( - displayLayout.getBrightnessThrottlingMapId() == null + newDisplay.setThermalBrightnessThrottlingDataIdLocked( + displayLayout.getThermalBrightnessThrottlingMapId() == null ? DisplayDeviceConfig.DEFAULT_ID - : displayLayout.getBrightnessThrottlingMapId()); + : displayLayout.getThermalBrightnessThrottlingMapId()); newDisplay.setDisplayGroupNameLocked(displayLayout.getDisplayGroupName()); } diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java index ec70c8966736..6d6ed726161b 100644 --- a/services/core/java/com/android/server/display/PersistentDataStore.java +++ b/services/core/java/com/android/server/display/PersistentDataStore.java @@ -306,8 +306,11 @@ final class PersistentDataStore { } public boolean setBrightness(DisplayDevice displayDevice, float brightness) { + if (displayDevice == null || !displayDevice.hasStableUniqueId()) { + return false; + } final String displayDeviceUniqueId = displayDevice.getUniqueId(); - if (!displayDevice.hasStableUniqueId() || displayDeviceUniqueId == null) { + if (displayDeviceUniqueId == null) { return false; } final DisplayState state = getDisplayState(displayDeviceUniqueId, true); diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java index 634f31d6268c..b55d7d5d9d3c 100644 --- a/services/core/java/com/android/server/display/layout/Layout.java +++ b/services/core/java/com/android/server/display/layout/Layout.java @@ -234,11 +234,11 @@ public class Layout { // {@link DeviceStateToLayoutMap.POSITION_UNKNOWN} is unspecified. private final int mPosition; - // The ID of the brightness throttling map that should be used. This can change e.g. in - // concurrent displays mode in which a stricter brightness throttling policy might need to - // be used. + // The ID of the thermal brightness throttling map that should be used. This can change + // e.g. in concurrent displays mode in which a stricter brightness throttling policy might + // need to be used. @Nullable - private final String mBrightnessThrottlingMapId; + private final String mThermalBrightnessThrottlingMapId; // The ID of the lead display that this display will follow in a layout. -1 means no lead. private final int mLeadDisplayId; @@ -248,7 +248,7 @@ public class Layout { private final String mRefreshRateZoneId; @Nullable - private final String mRefreshRateThermalThrottlingMapId; + private final String mThermalRefreshRateThrottlingMapId; private Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled, @NonNull String displayGroupName, String brightnessThrottlingMapId, int position, @@ -259,9 +259,9 @@ public class Layout { mIsEnabled = isEnabled; mDisplayGroupName = displayGroupName; mPosition = position; - mBrightnessThrottlingMapId = brightnessThrottlingMapId; + mThermalBrightnessThrottlingMapId = brightnessThrottlingMapId; mRefreshRateZoneId = refreshRateZoneId; - mRefreshRateThermalThrottlingMapId = refreshRateThermalThrottlingMapId; + mThermalRefreshRateThrottlingMapId = refreshRateThermalThrottlingMapId; mLeadDisplayId = leadDisplayId; } @@ -273,10 +273,10 @@ public class Layout { + ", displayGroupName: " + mDisplayGroupName + ", addr: " + mAddress + ((mPosition == POSITION_UNKNOWN) ? "" : ", position: " + mPosition) - + ", brightnessThrottlingMapId: " + mBrightnessThrottlingMapId + + ", mThermalBrightnessThrottlingMapId: " + mThermalBrightnessThrottlingMapId + ", mRefreshRateZoneId: " + mRefreshRateZoneId + ", mLeadDisplayId: " + mLeadDisplayId - + ", mRefreshRateThermalThrottlingMapId: " + mRefreshRateThermalThrottlingMapId + + ", mThermalRefreshRateThrottlingMapId: " + mThermalRefreshRateThrottlingMapId + "}"; } @@ -293,12 +293,12 @@ public class Layout { && otherDisplay.mLogicalDisplayId == this.mLogicalDisplayId && this.mDisplayGroupName.equals(otherDisplay.mDisplayGroupName) && this.mAddress.equals(otherDisplay.mAddress) - && Objects.equals(mBrightnessThrottlingMapId, - otherDisplay.mBrightnessThrottlingMapId) + && Objects.equals(mThermalBrightnessThrottlingMapId, + otherDisplay.mThermalBrightnessThrottlingMapId) && Objects.equals(otherDisplay.mRefreshRateZoneId, this.mRefreshRateZoneId) && this.mLeadDisplayId == otherDisplay.mLeadDisplayId - && Objects.equals(mRefreshRateThermalThrottlingMapId, - otherDisplay.mRefreshRateThermalThrottlingMapId); + && Objects.equals(mThermalRefreshRateThrottlingMapId, + otherDisplay.mThermalRefreshRateThrottlingMapId); } @Override @@ -309,10 +309,10 @@ public class Layout { result = 31 * result + mLogicalDisplayId; result = 31 * result + mDisplayGroupName.hashCode(); result = 31 * result + mAddress.hashCode(); - result = 31 * result + mBrightnessThrottlingMapId.hashCode(); + result = 31 * result + mThermalBrightnessThrottlingMapId.hashCode(); result = 31 * result + Objects.hashCode(mRefreshRateZoneId); result = 31 * result + mLeadDisplayId; - result = 31 * result + Objects.hashCode(mRefreshRateThermalThrottlingMapId); + result = 31 * result + Objects.hashCode(mThermalRefreshRateThrottlingMapId); return result; } @@ -338,12 +338,12 @@ public class Layout { } /** - * Gets the id of the brightness throttling map that should be used. - * @return The ID of the brightness throttling map that this display should use, null if - * unspecified, will fall back to default. + * Gets the id of the thermal brightness throttling map that should be used. + * @return The ID of the thermal brightness throttling map that this display should use, + * null if unspecified, will fall back to default. */ - public String getBrightnessThrottlingMapId() { - return mBrightnessThrottlingMapId; + public String getThermalBrightnessThrottlingMapId() { + return mThermalBrightnessThrottlingMapId; } /** @@ -361,7 +361,7 @@ public class Layout { } public String getRefreshRateThermalThrottlingMapId() { - return mRefreshRateThermalThrottlingMapId; + return mThermalRefreshRateThrottlingMapId; } } } diff --git a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java index f93d9ee55d30..c04735d8f7e2 100644 --- a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java +++ b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java @@ -102,7 +102,7 @@ final class SkinThermalStatusObserver extends IThermalEventListener.Stub impleme //region DisplayManager.DisplayListener @Override public void onDisplayAdded(int displayId) { - updateRefreshRateThermalThrottling(displayId); + updateThermalRefreshRateThrottling(displayId); if (mLoggingEnabled) { Slog.d(TAG, "Display added:" + displayId); } @@ -122,7 +122,7 @@ final class SkinThermalStatusObserver extends IThermalEventListener.Stub impleme @Override public void onDisplayChanged(int displayId) { - updateRefreshRateThermalThrottling(displayId); + updateThermalRefreshRateThrottling(displayId); if (mLoggingEnabled) { Slog.d(TAG, "Display changed:" + displayId); } @@ -150,7 +150,7 @@ final class SkinThermalStatusObserver extends IThermalEventListener.Stub impleme } } - private void updateRefreshRateThermalThrottling(int displayId) { + private void updateThermalRefreshRateThrottling(int displayId) { DisplayInfo displayInfo = new DisplayInfo(); mInjector.getDisplayInfo(displayId, displayInfo); SparseArray<SurfaceControl.RefreshRateRange> throttlingMap = diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index 7802b9d24de9..0e26d4661017 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -124,7 +124,7 @@ public final class DreamManagerService extends SystemService { private final boolean mDreamsEnabledByDefaultConfig; private final boolean mDreamsActivatedOnChargeByDefault; private final boolean mDreamsActivatedOnDockByDefault; - private final boolean mKeepDreamingWhenUndockedDefault; + private final boolean mKeepDreamingWhenUnpluggingDefault; private final CopyOnWriteArrayList<DreamManagerInternal.DreamManagerStateListener> mDreamManagerStateListeners = new CopyOnWriteArrayList<>(); @@ -236,8 +236,8 @@ public final class DreamManagerService extends SystemService { mDreamsActivatedOnDockByDefault = mContext.getResources().getBoolean( com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault); mSettingsObserver = new SettingsObserver(mHandler); - mKeepDreamingWhenUndockedDefault = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_keepDreamingWhenUndocking); + mKeepDreamingWhenUnpluggingDefault = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_keepDreamingWhenUnplugging); } @Override @@ -311,7 +311,7 @@ public final class DreamManagerService extends SystemService { pw.println("mIsDocked=" + mIsDocked); pw.println("mIsCharging=" + mIsCharging); pw.println("mWhenToDream=" + mWhenToDream); - pw.println("mKeepDreamingWhenUndockedDefault=" + mKeepDreamingWhenUndockedDefault); + pw.println("mKeepDreamingWhenUnpluggingDefault=" + mKeepDreamingWhenUnpluggingDefault); pw.println("getDozeComponent()=" + getDozeComponent()); pw.println(); @@ -340,11 +340,11 @@ public final class DreamManagerService extends SystemService { } } - private void reportKeepDreamingWhenUndockedChanged(boolean keepDreaming) { + private void reportKeepDreamingWhenUnpluggingChanged(boolean keepDreaming) { mHandler.post(() -> { for (DreamManagerInternal.DreamManagerStateListener listener : mDreamManagerStateListeners) { - listener.onKeepDreamingWhenUndockedChanged(keepDreaming); + listener.onKeepDreamingWhenUnpluggingChanged(keepDreaming); } }); } @@ -600,8 +600,7 @@ public final class DreamManagerService extends SystemService { } mSystemDreamComponent = componentName; - reportKeepDreamingWhenUndockedChanged(shouldKeepDreamingWhenUndocked()); - + reportKeepDreamingWhenUnpluggingChanged(shouldKeepDreamingWhenUnplugging()); // Switch dream if currently dreaming and not dozing. if (isDreamingInternal() && !isDozingInternal()) { startDreamInternal(false /*doze*/, (mSystemDreamComponent == null ? "clear" : "set") @@ -610,8 +609,8 @@ public final class DreamManagerService extends SystemService { } } - private boolean shouldKeepDreamingWhenUndocked() { - return mKeepDreamingWhenUndockedDefault && mSystemDreamComponent == null; + private boolean shouldKeepDreamingWhenUnplugging() { + return mKeepDreamingWhenUnpluggingDefault && mSystemDreamComponent == null; } private ComponentName getDefaultDreamComponentForUser(int userId) { @@ -1057,7 +1056,7 @@ public final class DreamManagerService extends SystemService { public void registerDreamManagerStateListener(DreamManagerStateListener listener) { mDreamManagerStateListeners.add(listener); // Initialize the listener's state. - listener.onKeepDreamingWhenUndockedChanged(shouldKeepDreamingWhenUndocked()); + listener.onKeepDreamingWhenUnpluggingChanged(shouldKeepDreamingWhenUnplugging()); } @Override diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java index 2ac283370886..c039a836843c 100644 --- a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java @@ -334,8 +334,8 @@ public class FontManagerShellCommand extends ShellCommand { } private int installCert(ShellCommand shell) throws SystemFontException { - if (!(Build.IS_USERDEBUG || Build.IS_ENG)) { - throw new SecurityException("Only userdebug/eng device can add debug certificate"); + if (!Build.IS_DEBUGGABLE) { + throw new SecurityException("Only debuggable device can add debug certificate"); } if (Binder.getCallingUid() != Process.ROOT_UID) { throw new SecurityException("Only root can add debug certificate"); diff --git a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java index c05a03ee1d2d..c76ca2beda96 100644 --- a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java +++ b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java @@ -286,7 +286,6 @@ final class AdditionalSubtypeUtils { final InputMethodSubtype.InputMethodSubtypeBuilder builder = new InputMethodSubtype.InputMethodSubtypeBuilder() .setSubtypeNameResId(label) - .setSubtypeNameOverride(untranslatableName) .setPhysicalKeyboardHint( pkLanguageTag == null ? null : new ULocale(pkLanguageTag), pkLayoutType == null ? "" : pkLayoutType) @@ -302,6 +301,9 @@ final class AdditionalSubtypeUtils { if (subtypeId != InputMethodSubtype.SUBTYPE_ID_NONE) { builder.setSubtypeId(subtypeId); } + if (untranslatableName != null) { + builder.setSubtypeNameOverride(untranslatableName); + } tempSubtypesArray.add(builder.build()); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java index c212e8e3c82c..44ae454e7ef2 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java @@ -19,7 +19,6 @@ package com.android.server.inputmethod; import static com.android.server.inputmethod.InputMethodManagerService.DEBUG; import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_ID; -import android.annotation.Nullable; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; @@ -66,8 +65,8 @@ final class InputMethodMenuController { private boolean mShowImeWithHardKeyboard; @GuardedBy("ImfLock.class") - @Nullable - private InputMethodDialogWindowContext mDialogWindowContext; + private final InputMethodDialogWindowContext mDialogWindowContext = + new InputMethodDialogWindowContext(); InputMethodMenuController(InputMethodManagerService service) { mService = service; @@ -125,13 +124,11 @@ final class InputMethodMenuController { } } - if (mDialogWindowContext == null) { - mDialogWindowContext = new InputMethodDialogWindowContext(); - } final Context dialogWindowContext = mDialogWindowContext.get(displayId); mDialogBuilder = new AlertDialog.Builder(dialogWindowContext); mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu()); + // TODO(b/277061090): refactor UI components should not be created while holding a lock. final Context dialogContext = mDialogBuilder.getContext(); final TypedArray a = dialogContext.obtainStyledAttributes(null, com.android.internal.R.styleable.DialogPreference, @@ -199,10 +196,11 @@ final class InputMethodMenuController { attrs.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; attrs.setTitle("Select input method"); w.setAttributes(attrs); + // TODO(b/277062834) decouple/remove dependency on IMMS mService.updateSystemUiLocked(); mService.sendOnNavButtonFlagsChangedLocked(); - mSwitchingDialog.show(); } + mSwitchingDialog.show(); } private boolean isScreenLocked() { @@ -276,6 +274,7 @@ final class InputMethodMenuController { private final int mTextViewResourceId; private final List<ImeSubtypeListItem> mItemsList; public int mCheckedItem; + private ImeSubtypeListAdapter(Context context, int textViewResourceId, List<ImeSubtypeListItem> itemsList, int checkedItem) { super(context, textViewResourceId, itemsList); diff --git a/services/core/java/com/android/server/inputmethod/OWNERS b/services/core/java/com/android/server/inputmethod/OWNERS index 00cd700541c0..6e5eb5631112 100644 --- a/services/core/java/com/android/server/inputmethod/OWNERS +++ b/services/core/java/com/android/server/inputmethod/OWNERS @@ -1,8 +1,8 @@ set noparent -ogunwale@google.com +roosa@google.com yukawa@google.com tarandeep@google.com -lumark@google.com -roosa@google.com -wilsonwu@google.com + +ogunwale@google.com #{LAST_RESORT_SUGGESTION} +jjaggi@google.com #{LAST_RESORT_SUGGESTION} diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java index 43e346a5bfa3..2d4066144a7f 100644 --- a/services/core/java/com/android/server/locales/LocaleManagerService.java +++ b/services/core/java/com/android/server/locales/LocaleManagerService.java @@ -323,7 +323,7 @@ public class LocaleManagerService extends SystemService { */ void notifyInstallerOfAppWhoseLocaleChanged(String appPackageName, int userId, LocaleList locales) { - String installingPackageName = getInstallingPackageName(appPackageName); + String installingPackageName = getInstallingPackageName(appPackageName, userId); if (installingPackageName != null) { Intent intent = createBaseIntent(Intent.ACTION_APPLICATION_LOCALE_CHANGED, appPackageName, locales); @@ -464,7 +464,7 @@ public class LocaleManagerService extends SystemService { * Checks if the calling app is the installer of the app whose locale changed. */ private boolean isCallerInstaller(String appPackageName, int userId) { - String installingPackageName = getInstallingPackageName(appPackageName); + String installingPackageName = getInstallingPackageName(appPackageName, userId); if (installingPackageName != null) { // Get the uid of installer-on-record to compare with the calling uid. int installerUid = getPackageUid(installingPackageName, userId); @@ -513,10 +513,11 @@ public class LocaleManagerService extends SystemService { } @Nullable - String getInstallingPackageName(String packageName) { + String getInstallingPackageName(String packageName, int userId) { try { - return mContext.getPackageManager() - .getInstallSourceInfo(packageName).getInstallingPackageName(); + return mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ + 0).getPackageManager().getInstallSourceInfo( + packageName).getInstallingPackageName(); } catch (PackageManager.NameNotFoundException e) { Slog.w(TAG, "Package not found " + packageName); } diff --git a/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java b/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java index 215c653f1be7..373d3553e0eb 100644 --- a/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java +++ b/services/core/java/com/android/server/locales/SystemAppUpdateTracker.java @@ -152,9 +152,10 @@ public class SystemAppUpdateTracker { void onPackageUpdateFinished(String packageName, int uid) { try { if ((!mUpdatedApps.contains(packageName)) && isUpdatedSystemApp(packageName)) { + int userId = UserHandle.getUserId(uid); // If a system app is updated, verify that it has an installer-on-record. String installingPackageName = mLocaleManagerService.getInstallingPackageName( - packageName); + packageName, userId); if (installingPackageName == null) { // We want to broadcast the locales info to the installer. // If this app does not have an installer then do nothing. @@ -162,7 +163,6 @@ public class SystemAppUpdateTracker { } try { - int userId = UserHandle.getUserId(uid); // Fetch the app-specific locales. // If non-empty then send the info to the installer. LocaleList appLocales = mLocaleManagerService.getApplicationLocales( diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java index 653b71828c5b..5f783742bd26 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -519,17 +519,24 @@ public class ContextHubService extends IContextHubService.Stub { BroadcastReceiver btReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction()) - || BluetoothAdapter.ACTION_BLE_STATE_CHANGED.equals( - intent.getAction())) { + if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) { sendBtSettingUpdate(/* forceUpdate= */ false); } } }; IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); - filter.addAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED); mContext.registerReceiver(btReceiver, filter); + + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), + /* notifyForDescendants= */ false, + new ContentObserver(/* handler= */ null) { + @Override + public void onChange(boolean selfChange) { + sendBtSettingUpdate(/* forceUpdate= */ false); + } + }, UserHandle.USER_ALL); } /** diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 0da94ff6aa0f..ee4a6fea8ad4 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -1516,11 +1516,6 @@ public class LockSettingsService extends ILockSettings.Stub { && !getSeparateProfileChallengeEnabledInternal(userId); } - private boolean isProfileWithSeparatedLock(int userId) { - return isCredentialSharableWithParent(userId) - && getSeparateProfileChallengeEnabledInternal(userId); - } - /** * Send credentials for user {@code userId} to {@link RecoverableKeyStoreManager} during an * unlock operation. @@ -2784,9 +2779,19 @@ public class LockSettingsService extends ILockSettings.Stub { activateEscrowTokens(sp, userId); - if (isProfileWithSeparatedLock(userId)) { - setDeviceUnlockedForUser(userId); + if (isCredentialSharableWithParent(userId)) { + if (getSeparateProfileChallengeEnabledInternal(userId)) { + setDeviceUnlockedForUser(userId); + } else { + // Here only clear StrongAuthFlags for a profile that has a unified challenge. + // StrongAuth for a profile with a separate challenge is handled differently and + // is cleared after the user successfully confirms the separate challenge to enter + // the profile. StrongAuth for the full user (e.g. userId 0) is also handled + // separately by Keyguard. + mStrongAuth.reportUnlock(userId); + } } + mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); onSyntheticPasswordUnlocked(userId, sp); 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 f0e8ede5987d..94d5aabe24e5 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -357,12 +357,16 @@ public final class MediaProjectionManagerService extends SystemService } catch (NameNotFoundException e) { throw new IllegalArgumentException("No package matching :" + packageName); } - - projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion, - ai.isPrivilegedApp()); - if (isPermanentGrant) { - mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA, - projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED); + final long callingToken = Binder.clearCallingIdentity(); + try { + projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion, + ai.isPrivilegedApp()); + if (isPermanentGrant) { + mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA, + projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED); + } + } finally { + Binder.restoreCallingIdentity(callingToken); } return projection; } @@ -418,16 +422,9 @@ public final class MediaProjectionManagerService extends SystemService if (packageName == null || packageName.isEmpty()) { throw new IllegalArgumentException("package name must not be empty"); } - MediaProjection projection; final UserHandle callingUser = Binder.getCallingUserHandle(); - final long callingToken = Binder.clearCallingIdentity(); - try { - projection = createProjectionInternal(uid, packageName, type, isPermanentGrant, - callingUser, false); - } finally { - Binder.restoreCallingIdentity(callingToken); - } - return projection; + return createProjectionInternal(uid, packageName, type, isPermanentGrant, + callingUser, false); } @Override // Binder call diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java index d3dea0d96812..b8900d7acee5 100644 --- a/services/core/java/com/android/server/notification/BubbleExtractor.java +++ b/services/core/java/com/android/server/notification/BubbleExtractor.java @@ -16,7 +16,6 @@ package com.android.server.notification; import static android.app.Notification.FLAG_BUBBLE; -import static android.app.Notification.FLAG_FOREGROUND_SERVICE; import static android.app.NotificationChannel.ALLOW_BUBBLE_OFF; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; @@ -81,7 +80,7 @@ public class BubbleExtractor implements NotificationSignalExtractor { && !mActivityManager.isLowRamDevice() && record.isConversation() && record.getShortcutInfo() != null - && (record.getNotification().flags & FLAG_FOREGROUND_SERVICE) == 0; + && !record.getNotification().isFgsOrUij(); boolean userEnabledBubbles = mConfig.bubblesEnabled(record.getUser()); int appPreference = diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java index 273afcc9f769..dff02bf711cd 100644 --- a/services/core/java/com/android/server/notification/GroupHelper.java +++ b/services/core/java/com/android/server/notification/GroupHelper.java @@ -15,44 +15,53 @@ */ package com.android.server.notification; +import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY; +import static android.app.Notification.FLAG_AUTO_CANCEL; +import static android.app.Notification.FLAG_GROUP_SUMMARY; +import static android.app.Notification.FLAG_LOCAL_ONLY; +import static android.app.Notification.FLAG_NO_CLEAR; +import static android.app.Notification.FLAG_ONGOING_EVENT; + +import android.annotation.NonNull; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; /** * NotificationManagerService helper for auto-grouping notifications. */ public class GroupHelper { private static final String TAG = "GroupHelper"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); protected static final String AUTOGROUP_KEY = "ranker_group"; + // Flags that all autogroup summaries have + protected static final int BASE_FLAGS = + FLAG_AUTOGROUP_SUMMARY | FLAG_GROUP_SUMMARY | FLAG_LOCAL_ONLY; + // Flag that autogroup summaries inherits if all children have the flag + private static final int ALL_CHILDREN_FLAG = FLAG_AUTO_CANCEL; + // Flags that autogroup summaries inherits if any child has them + private static final int ANY_CHILDREN_FLAGS = FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; + private final Callback mCallback; private final int mAutoGroupAtCount; - // count the number of ongoing notifications per group - // userId|packageName -> (set of ongoing notifications that aren't in an app group) - final ArrayMap<String, ArraySet<String>> - mOngoingGroupCount = new ArrayMap<>(); - - // Map of user : <Map of package : notification keys>. Only contains notifications that are not - // grouped by the app (aka no group or sort key). - Map<Integer, Map<String, LinkedHashSet<String>>> mUngroupedNotifications = new HashMap<>(); + // Only contains notifications that are not explicitly grouped by the app (aka no group or + // sort key). + // userId|packageName -> (keys of notifications that aren't in an explicit app group -> flags) + @GuardedBy("mUngroupedNotifications") + private final ArrayMap<String, ArrayMap<String, Integer>> mUngroupedNotifications + = new ArrayMap<>(); public GroupHelper(int autoGroupAtCount, Callback callback) { mAutoGroupAtCount = autoGroupAtCount; - mCallback = callback; + mCallback = callback; } private String generatePackageKey(int userId, String pkg) { @@ -60,69 +69,30 @@ public class GroupHelper { } @VisibleForTesting - protected int getOngoingGroupCount(int userId, String pkg) { - String key = generatePackageKey(userId, pkg); - return mOngoingGroupCount.getOrDefault(key, new ArraySet<>(0)).size(); - } - - private void updateOngoingGroupCount(StatusBarNotification sbn, boolean add) { - if (sbn.getNotification().isGroupSummary()) { - return; - } - String key = generatePackageKey(sbn.getUserId(), sbn.getPackageName()); - ArraySet<String> notifications = mOngoingGroupCount.getOrDefault(key, new ArraySet<>(0)); - if (add) { - notifications.add(sbn.getKey()); - mOngoingGroupCount.put(key, notifications); - } else { - notifications.remove(sbn.getKey()); - // we don't need to put it back if it is default + @GuardedBy("mUngroupedNotifications") + protected int getAutogroupSummaryFlags(@NonNull final ArrayMap<String, Integer> children) { + boolean allChildrenHasFlag = children.size() > 0; + int anyChildFlagSet = 0; + for (int i = 0; i < children.size(); i++) { + if (!hasAnyFlag(children.valueAt(i), ALL_CHILDREN_FLAG)) { + allChildrenHasFlag = false; + } + if (hasAnyFlag(children.valueAt(i), ANY_CHILDREN_FLAGS)) { + anyChildFlagSet |= (children.valueAt(i) & ANY_CHILDREN_FLAGS); + } } - - boolean needsOngoingFlag = notifications.size() > 0; - mCallback.updateAutogroupSummary(sbn.getUserId(), sbn.getPackageName(), needsOngoingFlag); + return BASE_FLAGS | (allChildrenHasFlag ? ALL_CHILDREN_FLAG : 0) | anyChildFlagSet; } - public void onNotificationUpdated(StatusBarNotification childSbn) { - updateOngoingGroupCount(childSbn, childSbn.isOngoing() && !childSbn.isAppGroup()); + private boolean hasAnyFlag(int flags, int mask) { + return (flags & mask) != 0; } public void onNotificationPosted(StatusBarNotification sbn, boolean autogroupSummaryExists) { try { - updateOngoingGroupCount(sbn, sbn.isOngoing() && !sbn.isAppGroup()); - - List<String> notificationsToGroup = new ArrayList<>(); if (!sbn.isAppGroup()) { - // Not grouped by the app, add to the list of notifications for the app; - // send grouping update if app exceeds the autogrouping limit. - synchronized (mUngroupedNotifications) { - Map<String, LinkedHashSet<String>> ungroupedNotificationsByUser - = mUngroupedNotifications.get(sbn.getUserId()); - if (ungroupedNotificationsByUser == null) { - ungroupedNotificationsByUser = new HashMap<>(); - } - mUngroupedNotifications.put(sbn.getUserId(), ungroupedNotificationsByUser); - LinkedHashSet<String> notificationsForPackage - = ungroupedNotificationsByUser.get(sbn.getPackageName()); - if (notificationsForPackage == null) { - notificationsForPackage = new LinkedHashSet<>(); - } - - notificationsForPackage.add(sbn.getKey()); - ungroupedNotificationsByUser.put(sbn.getPackageName(), notificationsForPackage); - - if (notificationsForPackage.size() >= mAutoGroupAtCount - || autogroupSummaryExists) { - notificationsToGroup.addAll(notificationsForPackage); - } - } - if (notificationsToGroup.size() > 0) { - adjustAutogroupingSummary(sbn.getUserId(), sbn.getPackageName(), - notificationsToGroup.get(0), true); - adjustNotificationBundling(notificationsToGroup, true); - } + maybeGroup(sbn, autogroupSummaryExists); } else { - // Grouped, but not by us. Send updates to un-autogroup, if we grouped it. maybeUngroup(sbn, false, sbn.getUserId()); } @@ -133,7 +103,6 @@ public class GroupHelper { public void onNotificationRemoved(StatusBarNotification sbn) { try { - updateOngoingGroupCount(sbn, false); maybeUngroup(sbn, true, sbn.getUserId()); } catch (Exception e) { Slog.e(TAG, "Error processing canceled notification", e); @@ -141,70 +110,114 @@ public class GroupHelper { } /** - * Un-autogroups notifications that are now grouped by the app. + * A non-app grouped notification has been added or updated + * Evaluate if: + * (a) an existing autogroup summary needs updated flags + * (b) a new autogroup summary needs to be added with correct flags + * (c) other non-app grouped children need to be moved to the autogroup + * + * And stores the list of upgrouped notifications & their flags + */ + private void maybeGroup(StatusBarNotification sbn, boolean autogroupSummaryExists) { + int flags = 0; + List<String> notificationsToGroup = new ArrayList<>(); + synchronized (mUngroupedNotifications) { + String key = generatePackageKey(sbn.getUserId(), sbn.getPackageName()); + final ArrayMap<String, Integer> children = + mUngroupedNotifications.getOrDefault(key, new ArrayMap<>()); + + children.put(sbn.getKey(), sbn.getNotification().flags); + mUngroupedNotifications.put(key, children); + + if (children.size() >= mAutoGroupAtCount || autogroupSummaryExists) { + flags = getAutogroupSummaryFlags(children); + notificationsToGroup.addAll(children.keySet()); + } + } + if (notificationsToGroup.size() > 0) { + if (autogroupSummaryExists) { + mCallback.updateAutogroupSummary(sbn.getUserId(), sbn.getPackageName(), flags); + } else { + mCallback.addAutoGroupSummary( + sbn.getUserId(), sbn.getPackageName(), sbn.getKey(), flags); + } + for (String key : notificationsToGroup) { + mCallback.addAutoGroup(key); + } + } + } + + /** + * A notification was added that's app grouped, or a notification was removed. + * Evaluate whether: + * (a) an existing autogroup summary needs updated flags + * (b) if we need to remove our autogroup overlay for this notification + * (c) we need to remove the autogroup summary + * + * And updates the internal state of un-app-grouped notifications and their flags */ private void maybeUngroup(StatusBarNotification sbn, boolean notificationGone, int userId) { - List<String> notificationsToUnAutogroup = new ArrayList<>(); boolean removeSummary = false; + int summaryFlags = 0; + boolean updateSummaryFlags = false; + boolean removeAutogroupOverlay = false; synchronized (mUngroupedNotifications) { - Map<String, LinkedHashSet<String>> ungroupedNotificationsByUser - = mUngroupedNotifications.get(sbn.getUserId()); - if (ungroupedNotificationsByUser == null || ungroupedNotificationsByUser.size() == 0) { - return; - } - LinkedHashSet<String> notificationsForPackage - = ungroupedNotificationsByUser.get(sbn.getPackageName()); - if (notificationsForPackage == null || notificationsForPackage.size() == 0) { + String key = generatePackageKey(sbn.getUserId(), sbn.getPackageName()); + final ArrayMap<String, Integer> children = + mUngroupedNotifications.getOrDefault(key, new ArrayMap<>()); + if (children.size() == 0) { return; } - if (notificationsForPackage.remove(sbn.getKey())) { - if (!notificationGone) { - // Add the current notification to the ungrouping list if it still exists. - notificationsToUnAutogroup.add(sbn.getKey()); + + // if this notif was autogrouped and now isn't + if (children.containsKey(sbn.getKey())) { + // if this notification was contributing flags that aren't covered by other + // children to the summary, reevaluate flags for the summary + int flags = children.remove(sbn.getKey()); + // this + if (hasAnyFlag(flags, ANY_CHILDREN_FLAGS)) { + updateSummaryFlags = true; + summaryFlags = getAutogroupSummaryFlags(children); + } + // if this notification still exists and has an autogroup overlay, but is now + // grouped by the app, clear the overlay + if (!notificationGone && sbn.getOverrideGroupKey() != null) { + removeAutogroupOverlay = true; + } + + // If there are no more children left to autogroup, remove the summary + if (children.size() == 0) { + removeSummary = true; } - } - // If the status change of this notification has brought the number of loose - // notifications to zero, remove the summary and un-autogroup. - if (notificationsForPackage.size() == 0) { - ungroupedNotificationsByUser.remove(sbn.getPackageName()); - removeSummary = true; } } if (removeSummary) { - adjustAutogroupingSummary(userId, sbn.getPackageName(), null, false); - } - if (notificationsToUnAutogroup.size() > 0) { - adjustNotificationBundling(notificationsToUnAutogroup, false); - } - } - - private void adjustAutogroupingSummary(int userId, String packageName, String triggeringKey, - boolean summaryNeeded) { - if (summaryNeeded) { - mCallback.addAutoGroupSummary(userId, packageName, triggeringKey, - getOngoingGroupCount(userId, packageName) > 0); + mCallback.removeAutoGroupSummary(userId, sbn.getPackageName()); } else { - mCallback.removeAutoGroupSummary(userId, packageName); + if (updateSummaryFlags) { + mCallback.updateAutogroupSummary(userId, sbn.getPackageName(), summaryFlags); + } + } + if (removeAutogroupOverlay) { + mCallback.removeAutoGroup(sbn.getKey()); } } - private void adjustNotificationBundling(List<String> keys, boolean group) { - for (String key : keys) { - if (DEBUG) Log.i(TAG, "Sending grouping adjustment for: " + key + " group? " + group); - if (group) { - mCallback.addAutoGroup(key); - } else { - mCallback.removeAutoGroup(key); - } + @VisibleForTesting + int getNotGroupedByAppCount(int userId, String pkg) { + synchronized (mUngroupedNotifications) { + String key = generatePackageKey(userId, pkg); + final ArrayMap<String, Integer> children = + mUngroupedNotifications.getOrDefault(key, new ArrayMap<>()); + return children.size(); } } protected interface Callback { void addAutoGroup(String key); void removeAutoGroup(String key); - void addAutoGroupSummary(int userId, String pkg, String triggeringKey, - boolean needsOngoingFlag); + void addAutoGroupSummary(int userId, String pkg, String triggeringKey, int flags); void removeAutoGroupSummary(int user, String pkg); - void updateAutogroupSummary(int userId, String pkg, boolean needsOngoingFlag); + void updateAutogroupSummary(int userId, String pkg, int flags); } } diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java index 6f0903cf8685..446c4f7e335a 100644 --- a/services/core/java/com/android/server/notification/NotificationComparator.java +++ b/services/core/java/com/android/server/notification/NotificationComparator.java @@ -165,7 +165,7 @@ public class NotificationComparator if (isCallStyle(record)) { return true; } - if (!isOngoing(record)) { + if (!record.getNotification().isFgsOrUij()) { return false; } return isCallCategory(record) || isMediaNotification(record); @@ -199,11 +199,6 @@ public class NotificationComparator return false; } - private boolean isOngoing(NotificationRecord record) { - final int ongoingFlags = Notification.FLAG_FOREGROUND_SERVICE; - return (record.getNotification().flags & ongoingFlags) != 0; - } - private boolean isMediaNotification(NotificationRecord record) { return record.getNotification().isMediaNotification(); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java index bc3885605a6c..919fc712c409 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java +++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java @@ -35,6 +35,8 @@ public interface NotificationManagerInternal { void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, int userId); + void removeUserInitiatedJobFlagFromNotification(String pkg, int notificationId, int userId); + void onConversationRemoved(String pkg, int uid, Set<String> shortcuts); /** Get the number of notification channels for a given package */ diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 87070595f172..ebcbfed93ac7 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -21,6 +21,7 @@ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_ import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY; +import static android.app.Notification.FLAG_AUTO_CANCEL; import static android.app.Notification.FLAG_BUBBLE; import static android.app.Notification.FLAG_FOREGROUND_SERVICE; import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED; @@ -29,6 +30,7 @@ import static android.app.Notification.FLAG_NO_CLEAR; import static android.app.Notification.FLAG_NO_DISMISS; import static android.app.Notification.FLAG_ONGOING_EVENT; import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; +import static android.app.Notification.FLAG_USER_INITIATED_JOB; import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT; import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED; import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; @@ -163,6 +165,7 @@ import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.app.PendingIntent; import android.app.RemoteServiceException.BadForegroundServiceNotificationException; +import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException; import android.app.StatsManager; import android.app.StatusBarManager; import android.app.UriGrantsManager; @@ -304,6 +307,7 @@ import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.UiThread; +import com.android.server.job.JobSchedulerInternal; import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; import com.android.server.notification.ManagedServices.ManagedServiceInfo; @@ -315,6 +319,7 @@ import com.android.server.pm.PackageManagerService; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.policy.PermissionPolicyInternal; +import com.android.server.powerstats.StatsPullAtomCallbackImpl; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.utils.Slogf; @@ -898,11 +903,11 @@ public class NotificationManagerService extends SystemService { * has the same flag. It will delete the flag otherwise * @param userId user id of the autogroup summary * @param pkg package of the autogroup summary - * @param needsOngoingFlag true if the group has at least one ongoing notification + * @param flags the new flags for this summary * @param isAppForeground true if the app is currently in the foreground. */ @GuardedBy("mNotificationLock") - protected void updateAutobundledSummaryFlags(int userId, String pkg, boolean needsOngoingFlag, + protected void updateAutobundledSummaryFlags(int userId, String pkg, int flags, boolean isAppForeground) { ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); if (summaries == null) { @@ -917,13 +922,8 @@ public class NotificationManagerService extends SystemService { return; } int oldFlags = summary.getSbn().getNotification().flags; - if (needsOngoingFlag) { - summary.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT; - } else { - summary.getSbn().getNotification().flags &= ~FLAG_ONGOING_EVENT; - } - - if (summary.getSbn().getNotification().flags != oldFlags) { + if (oldFlags != flags) { + summary.getSbn().getNotification().flags = flags; mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground, SystemClock.elapsedRealtime())); } @@ -1156,8 +1156,8 @@ public class NotificationManagerService extends SystemService { StatusBarNotification sbn = r.getSbn(); cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), sbn.getId(), Notification.FLAG_AUTO_CANCEL, - FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE, false, r.getUserId(), - REASON_CLICK, nv.rank, nv.count, null); + FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_BUBBLE, + false, r.getUserId(), REASON_CLICK, nv.rank, nv.count, null); nv.recycle(); reportUserInteraction(r); mAssistants.notifyAssistantNotificationClicked(r); @@ -1265,21 +1265,26 @@ public class NotificationManagerService extends SystemService { public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, int uid, int initialPid, String message, int userId) { final boolean fgService; + final boolean uiJob; synchronized (mNotificationLock) { NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0; + uiJob = r != null && (r.getNotification().flags & FLAG_USER_INITIATED_JOB) != 0; } cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, REASON_ERROR, null); - if (fgService) { - // Still crash for foreground services, preventing the not-crash behaviour abused - // by apps to give us a garbage notification and silently start a fg service. + if (fgService || uiJob) { + // Still crash for foreground services or user-initiated jobs, preventing the + // not-crash behaviour abused by apps to give us a garbage notification and + // silently start a fg service or user-initiated job. + final int exceptionTypeId = fgService + ? BadForegroundServiceNotificationException.TYPE_ID + : BadUserInitiatedJobNotificationException.TYPE_ID; Binder.withCleanCallingIdentity( () -> mAm.crashApplicationWithType(uid, initialPid, pkg, -1, "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " - + message, true /* force */, - BadForegroundServiceNotificationException.TYPE_ID)); + + message, true /* force */, exceptionTypeId)); } } @@ -1689,8 +1694,8 @@ public class NotificationManagerService extends SystemService { cancelNotification(record.getSbn().getUid(), record.getSbn().getInitialPid(), record.getSbn().getPackageName(), record.getSbn().getTag(), record.getSbn().getId(), 0, - FLAG_FOREGROUND_SERVICE, true, record.getUserId(), - REASON_TIMEOUT, null); + FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB, + true, record.getUserId(), REASON_TIMEOUT, null); } } } @@ -2675,9 +2680,14 @@ public class NotificationManagerService extends SystemService { @Override public void addAutoGroupSummary(int userId, String pkg, String triggeringKey, - boolean needsOngoingFlag) { - NotificationManagerService.this.addAutoGroupSummary( - userId, pkg, triggeringKey, needsOngoingFlag); + int flags) { + NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey, flags); + if (r != null) { + final boolean isAppForeground = + mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; + mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, + SystemClock.elapsedRealtime())); + } } @Override @@ -2688,11 +2698,11 @@ public class NotificationManagerService extends SystemService { } @Override - public void updateAutogroupSummary(int userId, String pkg, boolean needsOngoingFlag) { + public void updateAutogroupSummary(int userId, String pkg, int flags) { boolean isAppForeground = pkg != null && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; synchronized (mNotificationLock) { - updateAutobundledSummaryFlags(userId, pkg, needsOngoingFlag, isAppForeground); + updateAutobundledSummaryFlags(userId, pkg, flags, isAppForeground); } } }); @@ -3325,7 +3335,7 @@ public class NotificationManagerService extends SystemService { } checkCallerIsSameApp(pkg); - final boolean isSystemToast = isCallerSystemOrPhone() + final boolean isSystemToast = isCallerIsSystemOrSystemUi() || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); boolean isAppRenderedToast = (callback != null); if (!checkCanEnqueueToast(pkg, callingUid, displayId, isAppRenderedToast, @@ -3519,10 +3529,10 @@ public class NotificationManagerService extends SystemService { userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); - // Don't allow the app to cancel active FGS notifications + // Don't allow the app to cancel active FGS or UIJ notifications cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), - pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId, - REASON_APP_CANCEL_ALL, null); + pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB, + true, userId, REASON_APP_CANCEL_ALL, null); } @Override @@ -3806,6 +3816,28 @@ public class NotificationManagerService extends SystemService { } @Override + public boolean canUseFullScreenIntent(@NonNull AttributionSource attributionSource) { + final String packageName = attributionSource.getPackageName(); + final int uid = attributionSource.getUid(); + final int userId = UserHandle.getUserId(uid); + checkCallerIsSameApp(packageName, uid, userId); + + final ApplicationInfo applicationInfo; + try { + applicationInfo = mPackageManagerClient.getApplicationInfoAsUser( + packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, userId); + } catch (NameNotFoundException e) { + Slog.e(TAG, "Failed to getApplicationInfo() in canUseFullScreenIntent()", e); + return false; + } + final boolean showStickyHunIfDenied = mFlagResolver.isEnabled( + SystemUiSystemPropertiesFlags.NotificationFlags + .SHOW_STICKY_HUN_FOR_DENIED_FSI); + return checkUseFullScreenIntentPermission(attributionSource, applicationInfo, + showStickyHunIfDenied /* isAppOpPermission */, false /* forDataDelivery */); + } + + @Override public void updateNotificationChannelGroupForPackage(String pkg, int uid, NotificationChannelGroup group) throws RemoteException { enforceSystemOrSystemUI("Caller not system or systemui"); @@ -3964,6 +3996,21 @@ public class NotificationManagerService extends SystemService { } } + // Throws a security exception if the given channel has a notification associated + // with an active user-initiated job. + private void enforceDeletingChannelHasNoUserInitiatedJob(String pkg, int userId, + String channelId) { + final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); + if (js != null && js.isNotificationChannelAssociatedWithAnyUserInitiatedJobs( + channelId, userId, pkg)) { + Slog.w(TAG, "Package u" + userId + "/" + pkg + + " may not delete notification channel '" + + channelId + "' with user-initiated job"); + throw new SecurityException("Not allowed to delete channel " + channelId + + " with a user-initiated job"); + } + } + @Override public void deleteNotificationChannel(String pkg, String channelId) { checkCallerIsSystemOrSameApp(pkg); @@ -3973,6 +4020,7 @@ public class NotificationManagerService extends SystemService { throw new IllegalArgumentException("Cannot delete default channel"); } enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId); + enforceDeletingChannelHasNoUserInitiatedJob(pkg, callingUser, channelId); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, callingUser, REASON_CHANNEL_REMOVED, null); boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel( @@ -4017,8 +4065,9 @@ public class NotificationManagerService extends SystemService { final int userId = UserHandle.getUserId(callingUid); List<NotificationChannel> groupChannels = groupToDelete.getChannels(); for (int i = 0; i < groupChannels.size(); i++) { - enforceDeletingChannelHasNoFgService(pkg, userId, - groupChannels.get(i).getId()); + final String channelId = groupChannels.get(i).getId(); + enforceDeletingChannelHasNoFgService(pkg, userId, channelId); + enforceDeletingChannelHasNoUserInitiatedJob(pkg, userId, channelId); } List<NotificationChannel> deletedChannels = mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId); @@ -5913,19 +5962,6 @@ public class NotificationManagerService extends SystemService { r.addAdjustment(adjustment); } - @VisibleForTesting - void addAutoGroupSummary(int userId, String pkg, String triggeringKey, - boolean needsOngoingFlag) { - NotificationRecord r = createAutoGroupSummary( - userId, pkg, triggeringKey, needsOngoingFlag); - if (r != null) { - final boolean isAppForeground = - mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; - mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, - SystemClock.elapsedRealtime())); - } - } - // Clears the 'fake' auto-group summary. @VisibleForTesting @GuardedBy("mNotificationLock") @@ -5949,7 +5985,7 @@ public class NotificationManagerService extends SystemService { // Creates a 'fake' summary for a package that has exceeded the solo-notification limit. NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey, - boolean needsOngoingFlag) { + int flagsToSet) { NotificationRecord summaryRecord = null; boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId); synchronized (mNotificationLock) { @@ -5959,7 +5995,6 @@ public class NotificationManagerService extends SystemService { // adjustment will post a summary if needed. return null; } - NotificationChannel channel = notificationRecord.getChannel(); final StatusBarNotification adjustedSbn = notificationRecord.getSbn(); userId = adjustedSbn.getUser().getIdentifier(); int uid = adjustedSbn.getUid(); @@ -5982,11 +6017,8 @@ public class NotificationManagerService extends SystemService { .setGroupSummary(true) .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN) .setGroup(GroupHelper.AUTOGROUP_KEY) - .setFlag(FLAG_AUTOGROUP_SUMMARY, true) - .setFlag(Notification.FLAG_GROUP_SUMMARY, true) - .setFlag(FLAG_ONGOING_EVENT, needsOngoingFlag) + .setFlag(flagsToSet, true) .setColor(adjustedSbn.getNotification().color) - .setLocalOnly(true) .build(); summaryNotification.extras.putAll(extras); Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg); @@ -6324,6 +6356,7 @@ public class NotificationManagerService extends SystemService { * The private API only accessible to the system process. */ private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { + @Override public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId) { @@ -6360,61 +6393,73 @@ public class NotificationManagerService extends SystemService { checkCallerIsSystem(); mHandler.post(() -> { synchronized (mNotificationLock) { - int count = getNotificationCount(pkg, userId); - boolean removeFgsNotification = false; - if (count > MAX_PACKAGE_NOTIFICATIONS) { - mUsageStats.registerOverCountQuota(pkg); - removeFgsNotification = true; - } - if (removeFgsNotification) { - NotificationRecord r = findNotificationLocked(pkg, null, notificationId, - userId); - if (r != null) { - if (DBG) { - Slog.d(TAG, "Remove FGS flag not allow. Cancel FGS notification"); - } - removeFromNotificationListsLocked(r); - cancelNotificationLocked(r, false, REASON_APP_CANCEL, true, - null, SystemClock.elapsedRealtime()); - } - } else { - // strip flag from all enqueued notifications. listeners will be informed - // in post runnable. - List<NotificationRecord> enqueued = findNotificationsByListLocked( - mEnqueuedNotifications, pkg, null, notificationId, userId); - for (int i = 0; i < enqueued.size(); i++) { - removeForegroundServiceFlagLocked(enqueued.get(i)); - } - - // if posted notification exists, strip its flag and tell listeners - NotificationRecord r = findNotificationByListLocked( - mNotificationList, pkg, null, notificationId, userId); - if (r != null) { - removeForegroundServiceFlagLocked(r); - mRankingHelper.sort(mNotificationList); - mListeners.notifyPostedLocked(r, r); - } - } + removeFlagFromNotificationLocked(pkg, notificationId, userId, + FLAG_FOREGROUND_SERVICE); } }); } @Override - public void onConversationRemoved(String pkg, int uid, Set<String> shortcuts) { - onConversationRemovedInternal(pkg, uid, shortcuts); + public void removeUserInitiatedJobFlagFromNotification(String pkg, int notificationId, + int userId) { + checkCallerIsSystem(); + mHandler.post(() -> { + synchronized (mNotificationLock) { + removeFlagFromNotificationLocked(pkg, notificationId, userId, + FLAG_USER_INITIATED_JOB); + } + }); } @GuardedBy("mNotificationLock") - private void removeForegroundServiceFlagLocked(NotificationRecord r) { - if (r == null) { - return; + private void removeFlagFromNotificationLocked(String pkg, int notificationId, int userId, + int flag) { + int count = getNotificationCount(pkg, userId); + boolean removeFlagFromNotification = false; + if (count > MAX_PACKAGE_NOTIFICATIONS) { + mUsageStats.registerOverCountQuota(pkg); + removeFlagFromNotification = true; + } + if (removeFlagFromNotification) { + NotificationRecord r = findNotificationLocked(pkg, null, notificationId, userId); + if (r != null) { + if (DBG) { + final String type = (flag == FLAG_FOREGROUND_SERVICE) ? "FGS" : "UIJ"; + Slog.d(TAG, "Remove " + type + " flag not allow. " + + "Cancel " + type + " notification"); + } + removeFromNotificationListsLocked(r); + cancelNotificationLocked(r, false, REASON_APP_CANCEL, true, + null, SystemClock.elapsedRealtime()); + } + } else { + List<NotificationRecord> enqueued = findNotificationsByListLocked( + mEnqueuedNotifications, pkg, null, notificationId, userId); + for (int i = 0; i < enqueued.size(); i++) { + final NotificationRecord r = enqueued.get(i); + if (r != null) { + // strip flag from all enqueued notifications. listeners will be informed + // in post runnable. + StatusBarNotification sbn = r.getSbn(); + sbn.getNotification().flags = (r.mOriginalFlags & ~flag); + } + } + + NotificationRecord r = findNotificationByListLocked( + mNotificationList, pkg, null, notificationId, userId); + if (r != null) { + // if posted notification exists, strip its flag and tell listeners + StatusBarNotification sbn = r.getSbn(); + sbn.getNotification().flags = (r.mOriginalFlags & ~flag); + mRankingHelper.sort(mNotificationList); + mListeners.notifyPostedLocked(r, r); + } } - StatusBarNotification sbn = r.getSbn(); - // NoMan adds flags FLAG_ONGOING_EVENT when it sees - // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove - // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received - // initially *and* force remove FLAG_FOREGROUND_SERVICE. - sbn.getNotification().flags = (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE); + } + + @Override + public void onConversationRemoved(String pkg, int uid, Set<String> shortcuts) { + onConversationRemovedInternal(pkg, uid, shortcuts); } @Override @@ -6490,10 +6535,10 @@ public class NotificationManagerService extends SystemService { } } - // Don't allow client applications to cancel foreground service notifs or autobundled - // summaries. + // Don't allow client applications to cancel foreground service notifs, user-initiated job + // notifs or autobundled summaries. final int mustNotHaveFlags = isCallingUidSystem() ? 0 : - (FLAG_FOREGROUND_SERVICE | FLAG_AUTOGROUP_SUMMARY); + (FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB | FLAG_AUTOGROUP_SUMMARY); cancelNotification(uid, callingPid, pkg, tag, id, 0, mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null); } @@ -6547,9 +6592,16 @@ public class NotificationManagerService extends SystemService { final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification( notification, tag, id, pkg, userId); + boolean stripUijFlag = true; + final JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); + if (js != null) { + stripUijFlag = !js.isNotificationAssociatedWithAnyUserInitiatedJobs(id, userId, pkg); + } + // Fix the notification as best we can. try { - fixNotification(notification, pkg, tag, id, userId, notificationUid, policy); + fixNotification(notification, pkg, tag, id, userId, notificationUid, + policy, stripUijFlag); } catch (Exception e) { if (notification.isForegroundService()) { throw new SecurityException("Invalid FGS notification", e); @@ -6558,7 +6610,6 @@ public class NotificationManagerService extends SystemService { return; } - if (policy == ServiceNotificationPolicy.UPDATE_ONLY) { // Proceed if the notification is already showing/known, otherwise ignore // because the service lifecycle logic has retained responsibility for its @@ -6617,26 +6668,25 @@ public class NotificationManagerService extends SystemService { boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId); r.setImportanceFixed(isImportanceFixed); - if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { - final boolean fgServiceShown = channel.isFgServiceShown(); + if (notification.isFgsOrUij()) { if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0 - || !fgServiceShown) + || !channel.isUserVisibleTaskShown()) && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) { - // Increase the importance of foreground service notifications unless the user had - // an opinion otherwise (and the channel hasn't yet shown a fg service). + // Increase the importance of fgs/uij notifications unless the user had + // an opinion otherwise (and the channel hasn't yet shown a fgs/uij). channel.setImportance(IMPORTANCE_LOW); r.setSystemImportance(IMPORTANCE_LOW); - if (!fgServiceShown) { + if (!channel.isUserVisibleTaskShown()) { channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); - channel.setFgServiceShown(true); + channel.setUserVisibleTaskShown(true); } mPreferencesHelper.updateNotificationChannel( pkg, notificationUid, channel, false); r.updateNotificationChannel(channel); - } else if (!fgServiceShown && !TextUtils.isEmpty(channelId) + } else if (!channel.isUserVisibleTaskShown() && !TextUtils.isEmpty(channelId) && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { - channel.setFgServiceShown(true); + channel.setUserVisibleTaskShown(true); r.updateNotificationChannel(channel); } } @@ -6729,7 +6779,8 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting protected void fixNotification(Notification notification, String pkg, String tag, int id, - @UserIdInt int userId, int notificationUid, ServiceNotificationPolicy fgsPolicy) + @UserIdInt int userId, int notificationUid, + ServiceNotificationPolicy fgsPolicy, boolean stripUijFlag) throws NameNotFoundException, RemoteException { final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, @@ -6739,6 +6790,14 @@ public class NotificationManagerService extends SystemService { if (notification.isForegroundService() && fgsPolicy == NOT_FOREGROUND_SERVICE) { notification.flags &= ~FLAG_FOREGROUND_SERVICE; } + if (notification.isUserInitiatedJob() && stripUijFlag) { + notification.flags &= ~FLAG_USER_INITIATED_JOB; + } + + // Remove FLAG_AUTO_CANCEL from notifications that are associated with a FGS or UIJ. + if (notification.isFgsOrUij()) { + notification.flags &= ~FLAG_AUTO_CANCEL; + } // Only notifications that can be non-dismissible can have the flag FLAG_NO_DISMISS if (mFlagResolver.isEnabled(ALLOW_DISMISS_ONGOING)) { @@ -6774,36 +6833,28 @@ public class NotificationManagerService extends SystemService { notification.flags &= ~FLAG_FSI_REQUESTED_BUT_DENIED; - if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) { + if (notification.fullScreenIntent != null) { final boolean forceDemoteFsiToStickyHun = mFlagResolver.isEnabled( SystemUiSystemPropertiesFlags.NotificationFlags.FSI_FORCE_DEMOTE); - - final boolean showStickyHunIfDenied = mFlagResolver.isEnabled( - SystemUiSystemPropertiesFlags.NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI); - if (forceDemoteFsiToStickyHun) { makeStickyHun(notification, pkg, userId); - - } else if (showStickyHunIfDenied) { - final AttributionSource source = new AttributionSource.Builder(notificationUid) - .setPackageName(pkg) - .build(); - - final int permissionResult = mPermissionManager.checkPermissionForDataDelivery( - Manifest.permission.USE_FULL_SCREEN_INTENT, source, /* message= */ null); - - if (permissionResult != PermissionManager.PERMISSION_GRANTED) { - makeStickyHun(notification, pkg, userId); - } - } else { - int fullscreenIntentPermission = getContext().checkPermission( - android.Manifest.permission.USE_FULL_SCREEN_INTENT, -1, notificationUid); - - if (fullscreenIntentPermission != PERMISSION_GRANTED) { - notification.fullScreenIntent = null; - Slog.w(TAG, "Package " + pkg + ": Use of fullScreenIntent requires the" - + "USE_FULL_SCREEN_INTENT permission"); + final AttributionSource attributionSource = + new AttributionSource.Builder(notificationUid).setPackageName(pkg).build(); + final boolean showStickyHunIfDenied = mFlagResolver.isEnabled( + SystemUiSystemPropertiesFlags.NotificationFlags + .SHOW_STICKY_HUN_FOR_DENIED_FSI); + final boolean canUseFullScreenIntent = checkUseFullScreenIntentPermission( + attributionSource, ai, showStickyHunIfDenied /* isAppOpPermission */, + true /* forDataDelivery */); + if (!canUseFullScreenIntent) { + if (showStickyHunIfDenied) { + makeStickyHun(notification, pkg, userId); + } else { + notification.fullScreenIntent = null; + Slog.w(TAG, "Package " + pkg + ": Use of fullScreenIntent requires the" + + "USE_FULL_SCREEN_INTENT permission"); + } } } } @@ -6899,6 +6950,30 @@ public class NotificationManagerService extends SystemService { ai.packageName) == AppOpsManager.MODE_ALLOWED; } + private boolean checkUseFullScreenIntentPermission(@NonNull AttributionSource attributionSource, + @NonNull ApplicationInfo applicationInfo, boolean isAppOpPermission, + boolean forDataDelivery) { + if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) { + return true; + } + if (isAppOpPermission) { + final int permissionResult; + if (forDataDelivery) { + permissionResult = mPermissionManager.checkPermissionForDataDelivery( + permission.USE_FULL_SCREEN_INTENT, attributionSource, /* message= */ null); + } else { + permissionResult = mPermissionManager.checkPermissionForPreflight( + permission.USE_FULL_SCREEN_INTENT, attributionSource); + } + return permissionResult == PermissionManager.PERMISSION_GRANTED; + } else { + final int permissionResult = getContext().checkPermission( + permission.USE_FULL_SCREEN_INTENT, attributionSource.getPid(), + attributionSource.getUid()); + return permissionResult == PERMISSION_GRANTED; + } + } + private void checkRemoteViews(String pkg, String tag, int id, Notification notification) { if (removeRemoteView(pkg, tag, id, notification.contentView)) { notification.contentView = null; @@ -7083,8 +7158,8 @@ public class NotificationManagerService extends SystemService { } } - // limit the number of non-fgs outstanding notificationrecords an app can have - if (!n.isForegroundService()) { + // limit the number of non-fgs/uij outstanding notificationrecords an app can have + if (!n.isFgsOrUij()) { int count = getNotificationCount(pkg, userId, id, tag); if (count >= MAX_PACKAGE_NOTIFICATIONS) { mUsageStats.registerOverCountQuota(pkg); @@ -7444,7 +7519,8 @@ public class NotificationManagerService extends SystemService { return false; } } else if (mReason == REASON_APP_CANCEL) { - if ((flags & FLAG_FOREGROUND_SERVICE) != 0) { + if ((flags & FLAG_FOREGROUND_SERVICE) != 0 + || (flags & FLAG_USER_INITIATED_JOB) != 0) { return false; } } @@ -7736,18 +7812,17 @@ public class NotificationManagerService extends SystemService { if (notification.getSmallIcon() != null) { StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null; mListeners.notifyPostedLocked(r, old); - if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) - && !isCritical(r)) { - mHandler.post(() -> { - synchronized (mNotificationLock) { - mGroupHelper.onNotificationPosted( - n, hasAutoGroupSummaryLocked(n)); - } - }); - } else if (oldSbn != null) { - final NotificationRecord finalRecord = r; - mHandler.post(() -> - mGroupHelper.onNotificationUpdated(finalRecord.getSbn())); + if (oldSbn == null + || !Objects.equals(oldSbn.getGroup(), n.getGroup()) + || oldSbn.getNotification().flags != n.getNotification().flags) { + if (!isCritical(r)) { + mHandler.post(() -> { + synchronized (mNotificationLock) { + mGroupHelper.onNotificationPosted( + n, hasAutoGroupSummaryLocked(n)); + } + }); + } } } else { Slog.e(TAG, "Not posting notification without small icon: " + notification); @@ -7997,7 +8072,7 @@ public class NotificationManagerService extends SystemService { } FlagChecker childrenFlagChecker = (flags) -> { - if ((flags & FLAG_FOREGROUND_SERVICE) != 0) { + if ((flags & FLAG_FOREGROUND_SERVICE) != 0 || (flags & FLAG_USER_INITIATED_JOB) != 0) { return false; } return true; diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index 9e91875bfd86..ffe33a832ce4 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -383,6 +383,7 @@ public class NotificationUsageStats { public int numWithBigText; public int numWithBigPicture; public int numForegroundService; + public int numUserInitiatedJob; public int numOngoing; public int numAutoCancel; public int numWithLargeIcon; @@ -433,6 +434,10 @@ public class NotificationUsageStats { numForegroundService++; } + if ((n.flags & Notification.FLAG_USER_INITIATED_JOB) != 0) { + numUserInitiatedJob++; + } + if ((n.flags & Notification.FLAG_ONGOING_EVENT) != 0) { numOngoing++; } @@ -516,6 +521,7 @@ public class NotificationUsageStats { maybeCount("note_big_text", (numWithBigText - previous.numWithBigText)); maybeCount("note_big_pic", (numWithBigPicture - previous.numWithBigPicture)); maybeCount("note_fg", (numForegroundService - previous.numForegroundService)); + maybeCount("note_uij", (numUserInitiatedJob - previous.numUserInitiatedJob)); maybeCount("note_ongoing", (numOngoing - previous.numOngoing)); maybeCount("note_auto", (numAutoCancel - previous.numAutoCancel)); maybeCount("note_large_icon", (numWithLargeIcon - previous.numWithLargeIcon)); @@ -550,6 +556,7 @@ public class NotificationUsageStats { previous.numWithBigText = numWithBigText; previous.numWithBigPicture = numWithBigPicture; previous.numForegroundService = numForegroundService; + previous.numUserInitiatedJob = numUserInitiatedJob; previous.numOngoing = numOngoing; previous.numAutoCancel = numAutoCancel; previous.numWithLargeIcon = numWithLargeIcon; @@ -645,6 +652,8 @@ public class NotificationUsageStats { output.append(indentPlusTwo); output.append("numForegroundService=").append(numForegroundService).append("\n"); output.append(indentPlusTwo); + output.append("numUserInitiatedJob=").append(numUserInitiatedJob).append("\n"); + output.append(indentPlusTwo); output.append("numOngoing=").append(numOngoing).append("\n"); output.append(indentPlusTwo); output.append("numAutoCancel=").append(numAutoCancel).append("\n"); @@ -701,6 +710,7 @@ public class NotificationUsageStats { maybePut(dump, "numWithBigText", numWithBigText); maybePut(dump, "numWithBigPicture", numWithBigPicture); maybePut(dump, "numForegroundService", numForegroundService); + maybePut(dump, "numUserInitiatedJob", numUserInitiatedJob); maybePut(dump, "numOngoing", numOngoing); maybePut(dump, "numAutoCancel", numAutoCancel); maybePut(dump, "numWithLargeIcon", numWithLargeIcon); diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java index 35b94e7ccd63..88d23ce3f9a1 100644 --- a/services/core/java/com/android/server/notification/ZenLog.java +++ b/services/core/java/com/android/server/notification/ZenLog.java @@ -27,6 +27,7 @@ import android.service.notification.Condition; import android.service.notification.IConditionProvider; import android.service.notification.NotificationListenerService; import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeDiff; import android.util.Log; import android.util.Slog; @@ -146,13 +147,13 @@ public class ZenLog { public static void traceConfig(String reason, ZenModeConfig oldConfig, ZenModeConfig newConfig) { - ZenModeConfig.Diff diff = ZenModeConfig.diff(oldConfig, newConfig); - if (diff.isEmpty()) { + ZenModeDiff.ConfigDiff diff = new ZenModeDiff.ConfigDiff(oldConfig, newConfig); + if (diff == null || !diff.hasDiff()) { append(TYPE_CONFIG, reason + " no changes"); } else { append(TYPE_CONFIG, reason + ",\n" + (newConfig != null ? newConfig.toString() : null) - + ",\n" + ZenModeConfig.diff(oldConfig, newConfig)); + + ",\n" + diff); } } diff --git a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java index cae7079c75e0..82b585d7ad01 100644 --- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java +++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java @@ -65,7 +65,7 @@ public class DynamicCodeLoggingService extends JobService { private static final String AVC_PREFIX = "type=" + AUDIT_AVC + " "; private static final Pattern EXECUTE_NATIVE_AUDIT_PATTERN = - Pattern.compile(".*\\bavc: granted \\{ execute(?:_no_trans|) \\} .*" + Pattern.compile(".*\\bavc: +granted +\\{ execute(?:_no_trans|) \\} .*" + "\\bpath=(?:\"([^\" ]*)\"|([0-9A-F]+)) .*" + "\\bscontext=u:r:untrusted_app(?:_25|_27)?:.*" + "\\btcontext=u:object_r:app_data_file:.*" diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index c29e4d78f929..52fdbda04fcd 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -606,6 +606,7 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { final Computer snapshot = snapshot(); // Return null for InstantApps. if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) { + Log.w(PackageManagerService.TAG, "Returning null PackageInstaller for InstantApps"); return null; } return mInstallerService; diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 5f424edb15c4..ad8a9bab4c5e 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -1135,22 +1135,22 @@ final class InstallPackageHelper { // behavior. if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, "MinInstallableTargetSdk__install_block_enabled", - false)) { + true)) { int minInstallableTargetSdk = DeviceConfig.getInt(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, "MinInstallableTargetSdk__min_installable_target_sdk", - 0); + PackageManagerService.MIN_INSTALLABLE_TARGET_SDK); // Determine if enforcement is in strict mode boolean strictMode = false; if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, "MinInstallableTargetSdk__install_block_strict_mode_enabled", - false)) { + true)) { if (parsedPackage.getTargetSdkVersion() < DeviceConfig.getInt(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, "MinInstallableTargetSdk__strict_mode_target_sdk", - 0)) { + PackageManagerService.MIN_INSTALLABLE_TARGET_SDK)) { strictMode = true; } } @@ -2265,10 +2265,26 @@ final class InstallPackageHelper { // The caller explicitly specified INSTALL_ALL_USERS flag. // Thus, updating the settings to install the app for all users. for (int currentUserId : allUsers) { - ps.setInstalled(true, currentUserId); - if (!installRequest.isApplicationEnabledSettingPersistent()) { - ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId, - installerPackageName); + // If the app is already installed for the currentUser, + // keep it as installed as we might be updating the app at this place. + // If not currently installed, check if the currentUser is restricted by + // DISALLOW_INSTALL_APPS or DISALLOW_DEBUGGING_FEATURES device policy. + // Install / update the app if the user isn't restricted. Skip otherwise. + final boolean installedForCurrentUser = ArrayUtils.contains( + installedForUsers, currentUserId); + final boolean restrictedByPolicy = + mPm.isUserRestricted(currentUserId, + UserManager.DISALLOW_INSTALL_APPS) + || mPm.isUserRestricted(currentUserId, + UserManager.DISALLOW_DEBUGGING_FEATURES); + if (installedForCurrentUser || !restrictedByPolicy) { + ps.setInstalled(true, currentUserId); + if (!installRequest.isApplicationEnabledSettingPersistent()) { + ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId, + installerPackageName); + } + } else { + ps.setInstalled(false, currentUserId); } } } @@ -3588,6 +3604,11 @@ final class InstallPackageHelper { // remove the package from the system and re-scan it without any // special privileges mRemovePackageHelper.removePackage(pkg, true); + PackageSetting ps = mPm.mSettings.getPackageLPr(packageName); + if (ps != null) { + ps.getPkgState().setUpdatedSystemApp(false); + } + try { final File codePath = new File(pkg.getPath()); synchronized (mPm.mInstallLock) { diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 84bee50b77b0..402fb30437b0 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; @@ -25,6 +26,8 @@ import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; +import static android.content.PermissionChecker.PERMISSION_GRANTED; +import static android.content.PermissionChecker.checkCallingOrSelfPermissionForPreflight; import static android.content.pm.LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS; import static android.content.pm.LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS; import static android.content.pm.LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS; @@ -32,6 +35,7 @@ import static android.content.pm.LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS; import android.annotation.AppIdInt; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; @@ -90,6 +94,7 @@ import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import android.util.Slog; +import android.window.IDumpCallback; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -104,6 +109,15 @@ import com.android.server.SystemService; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.wm.ActivityTaskManagerInternal; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.PosixFilePermission; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -111,6 +125,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.ExecutionException; /** @@ -118,6 +133,15 @@ import java.util.concurrent.ExecutionException; * managed profiles. */ public class LauncherAppsService extends SystemService { + private static final String WM_TRACE_DIR = "/data/misc/wmtrace/"; + private static final String VC_FILE_SUFFIX = ".vc"; + + private static final Set<PosixFilePermission> WM_TRACE_FILE_PERMISSIONS = Set.of( + PosixFilePermission.OWNER_WRITE, + PosixFilePermission.GROUP_READ, + PosixFilePermission.OTHERS_READ, + PosixFilePermission.OWNER_READ + ); private final LauncherAppsImpl mLauncherAppsImpl; @@ -191,6 +215,8 @@ public class LauncherAppsService extends SystemService { final LauncherAppsServiceInternal mInternal; + private RemoteCallbackList<IDumpCallback> mDumpCallbacks = new RemoteCallbackList<>(); + public LauncherAppsImpl(Context context) { mContext = context; mIPM = AppGlobals.getPackageManager(); @@ -1431,6 +1457,66 @@ public class LauncherAppsService extends SystemService { getActivityOptionsForLauncher(opts), user.getIdentifier()); } + + /** + * Using a pipe, outputs view capture data to the wmtrace dir + */ + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + super.dump(fd, pw, args); + + // Before the wmtrace directory is picked up by dumpstate service, some processes need + // to write their data to that location. They can do that via these dumpCallbacks. + int i = mDumpCallbacks.beginBroadcast(); + while (i > 0) { + i--; + dumpDataToWmTrace((String) mDumpCallbacks.getBroadcastCookie(i) + "_" + i, + mDumpCallbacks.getBroadcastItem(i)); + } + mDumpCallbacks.finishBroadcast(); + } + + private void dumpDataToWmTrace(String name, IDumpCallback cb) { + ParcelFileDescriptor[] pipe; + try { + pipe = ParcelFileDescriptor.createPipe(); + cb.onDump(pipe[1]); + } catch (IOException | RemoteException e) { + Log.d(TAG, "failed to pipe view capture data", e); + return; + } + + Path path = Paths.get(WM_TRACE_DIR + Paths.get(name + VC_FILE_SUFFIX).getFileName()); + try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0])) { + Files.copy(is, path, StandardCopyOption.REPLACE_EXISTING); + Files.setPosixFilePermissions(path, WM_TRACE_FILE_PERMISSIONS); + } catch (IOException e) { + Log.d(TAG, "failed to write data to file in wmtrace dir", e); + } + } + + @RequiresPermission(READ_FRAME_BUFFER) + @Override + public void registerDumpCallback(IDumpCallback cb) { + int status = checkCallingOrSelfPermissionForPreflight(mContext, READ_FRAME_BUFFER); + if (PERMISSION_GRANTED == status) { + String name = mContext.getPackageManager().getNameForUid(Binder.getCallingUid()); + mDumpCallbacks.register(cb, name); + } else { + Log.w(TAG, "caller lacks permissions to registerDumpCallback"); + } + } + + @RequiresPermission(READ_FRAME_BUFFER) + @Override + public void unRegisterDumpCallback(IDumpCallback cb) { + int status = checkCallingOrSelfPermissionForPreflight(mContext, READ_FRAME_BUFFER); + if (PERMISSION_GRANTED == status) { + mDumpCallbacks.unregister(cb); + } else { + Log.w(TAG, "caller lacks permissions to unRegisterDumpCallback"); + } + } + /** Checks if user is a profile of or same as listeningUser. * and the user is enabled. */ private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user, diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 69e92e075b51..f358ce796fcf 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -677,7 +677,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements ? params.installerPackageName : installerPackageName; if (PackageManagerServiceUtils.isRootOrShell(callingUid) - || PackageInstallerSession.isSystemDataLoaderInstallation(params)) { + || PackageInstallerSession.isSystemDataLoaderInstallation(params) + || PackageManagerServiceUtils.isAdoptedShell(callingUid, mContext)) { params.installFlags |= PackageManager.INSTALL_FROM_ADB; // adb installs can override the installingPackageName, but not the // initiatingPackageName diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ea6383e14969..006d7c82398a 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -745,6 +745,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private int mValidatedTargetSdk = INVALID_TARGET_SDK_VERSION; + @GuardedBy("mLock") + private boolean mAllowsUpdateOwnership = true; + private static final FileFilter sAddedApkFilter = new FileFilter() { @Override public boolean accept(File file) { @@ -866,13 +869,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final int USER_ACTION_NOT_NEEDED = 0; private static final int USER_ACTION_REQUIRED = 1; - private static final int USER_ACTION_PENDING_APK_PARSING = 2; private static final int USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER = 3; @IntDef({ USER_ACTION_NOT_NEEDED, USER_ACTION_REQUIRED, - USER_ACTION_PENDING_APK_PARSING, USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER, }) @interface UserActionRequirement {} @@ -963,11 +964,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { && !isApexSession() && !isUpdateOwner && !isInstallerShell + && mAllowsUpdateOwnership // We don't enforce the update ownership for the managed user and profile. && !isFromManagedUserOrProfile) { return USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER; } - if (isPermissionGranted) { return USER_ACTION_NOT_NEEDED; } @@ -982,7 +983,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { && isUpdateWithoutUserActionPermissionGranted && ((isUpdateOwnershipEnforcementEnabled ? isUpdateOwner : isInstallerOfRecord) || isSelfUpdate)) { - return USER_ACTION_PENDING_APK_PARSING; + if (!isApexSession()) { + if (!isTargetSdkConditionSatisfied(this)) { + return USER_ACTION_REQUIRED; + } + + if (!mSilentUpdatePolicy.isSilentUpdateAllowed( + getInstallerPackageName(), getPackageName())) { + // Fall back to the non-silent update if a repeated installation is invoked + // within the throttle time. + return USER_ACTION_REQUIRED; + } + mSilentUpdatePolicy.track(getInstallerPackageName(), getPackageName()); + return USER_ACTION_NOT_NEEDED; + } } return USER_ACTION_REQUIRED; @@ -1442,7 +1456,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @NonNull IOnChecksumsReadyListener onChecksumsReadyListener) { assertCallerIsOwnerRootOrVerifier(); final File file = new File(stageDir, name); - final String installerPackageName = getInstallSource().mInitiatingPackageName; + final String installerPackageName = PackageManagerServiceUtils.isInstalledByAdb( + getInstallSource().mInitiatingPackageName) + ? getInstallSource().mInstallerPackageName + : getInstallSource().mInitiatingPackageName; try { mPm.requestFileChecksums(file, installerPackageName, optional, required, trustedInstallers, onChecksumsReadyListener); @@ -2363,26 +2380,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { session.sendPendingUserActionIntent(target); return true; } - - if (!session.isApexSession() && userActionRequirement == USER_ACTION_PENDING_APK_PARSING) { - if (!isTargetSdkConditionSatisfied(session)) { - session.sendPendingUserActionIntent(target); - return true; - } - - if (session.params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED) { - if (!session.mSilentUpdatePolicy.isSilentUpdateAllowed( - session.getInstallerPackageName(), session.getPackageName())) { - // Fall back to the non-silent update if a repeated installation is invoked - // within the throttle time. - session.sendPendingUserActionIntent(target); - return true; - } - session.mSilentUpdatePolicy.track(session.getInstallerPackageName(), - session.getPackageName()); - } - } - return false; } @@ -3393,6 +3390,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // {@link PackageLite#getTargetSdk()} mValidatedTargetSdk = packageLite.getTargetSdk(); + mAllowsUpdateOwnership = packageLite.isAllowUpdateOwnership(); + return packageLite; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e4e3a9d0b7d3..3e1a1ac2605f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -560,6 +560,14 @@ public class PackageManagerService implements PackageSender, TestUtilityService // How many required verifiers can be on the system. private static final int REQUIRED_VERIFIERS_MAX_COUNT = 2; + /** + * Specifies the minimum target SDK version an apk must specify in order to be installed + * on the system. This improves security and privacy by blocking low + * target sdk apps as malware can target older sdk versions to avoid + * the enforcement of new API behavior. + */ + public static final int MIN_INSTALLABLE_TARGET_SDK = Build.VERSION_CODES.M; + // Compilation reasons. // TODO(b/260124949): Clean this up with the legacy dexopt code. public static final int REASON_FIRST_BOOT = 0; diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 42538f33c5f8..db997d8d1d79 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -36,6 +36,7 @@ import static com.android.server.pm.PackageManagerService.SHELL_PACKAGE_NAME; import static com.android.server.pm.PackageManagerService.STUB_SUFFIX; import static com.android.server.pm.PackageManagerService.TAG; +import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1389,6 +1390,14 @@ public class PackageManagerServiceUtils { } /** + * Check if a UID is non-system UID adopted shell permission. + */ + public static boolean isAdoptedShell(int uid, Context context) { + return uid != Process.SYSTEM_UID && context.checkCallingOrSelfPermission( + Manifest.permission.USE_SYSTEM_DATA_LOADERS) == PackageManager.PERMISSION_GRANTED; + } + + /** * Check if a UID is system UID or shell's UID. */ public static boolean isRootOrShell(int uid) { diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index cc60802967b0..89f46fed4862 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -692,7 +692,7 @@ class PackageManagerShellCommand extends ShellCommand { null /* usesSplitNames */, null /* configForSplit */, null /* splitApkPaths */, null /* splitRevisionCodes */, apkLite.getTargetSdkVersion(), null /* requiredSplitTypes */, - null /* splitTypes */); + null /* splitTypes */, apkLite.isAllowUpdateOwnership()); sessionSize += InstallLocationUtils.calculateInstalledSize(pkgLite, params.sessionParams.abiOverride, fd.getFileDescriptor()); } catch (IOException e) { diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java index ad77ef7ca975..9127a93a46ee 100644 --- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java +++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java @@ -187,6 +187,9 @@ public final class SuspendPackageHelper { if (changed) { changedPackagesList.add(packageName); changedUids.add(UserHandle.getUid(userId, packageState.getAppId())); + } else { + Slog.w(TAG, "No change is needed for package: " + packageName + + ". Skipping suspending/un-suspending."); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index ab9d1cfc2eec..5f8efe29459d 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2592,7 +2592,7 @@ public class UserManagerService extends IUserManager.Stub { } } if (scheduleWriteUser) { - scheduleWriteUser(userData); + scheduleWriteUser(userId); } } @@ -2641,6 +2641,7 @@ public class UserManagerService extends IUserManager.Stub { private void setUserRestrictionInner(int userId, @NonNull String key, boolean value) { if (!UserRestrictionsUtils.isValidRestriction(key)) { + Slog.e(LOG_TAG, "Setting invalid restriction " + key); return; } synchronized (mRestrictionsLock) { @@ -2902,7 +2903,7 @@ public class UserManagerService extends IUserManager.Stub { != newBaseRestrictions); if (mBaseUserRestrictions.updateRestrictions(userId, newBaseRestrictions)) { - scheduleWriteUser(getUserDataNoChecks(userId)); + scheduleWriteUser(userId); } } @@ -2978,7 +2979,7 @@ public class UserManagerService extends IUserManager.Stub { @GuardedBy("mRestrictionsLock") private void applyUserRestrictionsLR(@UserIdInt int userId) { updateUserRestrictionsInternalLR(null, userId); - scheduleWriteUser(getUserDataNoChecks(userId)); + scheduleWriteUser(userId); } @GuardedBy("mRestrictionsLock") @@ -4129,14 +4130,14 @@ public class UserManagerService extends IUserManager.Stub { } } - private void scheduleWriteUser(UserData userData) { + private void scheduleWriteUser(@UserIdInt int userId) { if (DBG) { debug("scheduleWriteUser"); } // No need to wrap it within a lock -- worst case, we'll just post the same message // twice. - if (!mHandler.hasMessages(WRITE_USER_MSG, userData)) { - Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userData); + if (!mHandler.hasMessages(WRITE_USER_MSG, userId)) { + Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userId); mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY); } } @@ -4152,7 +4153,7 @@ public class UserManagerService extends IUserManager.Stub { // Something went wrong, schedule full rewrite. UserData userData = getUserDataNoChecks(userId); if (userData != null) { - scheduleWriteUser(userData); + scheduleWriteUser(userId); } }); } @@ -6363,7 +6364,7 @@ public class UserManagerService extends IUserManager.Stub { userData.info.lastLoggedInTime = now; } userData.info.lastLoggedInFingerprint = PackagePartitions.FINGERPRINT; - scheduleWriteUser(userData); + scheduleWriteUser(userId); } /** @@ -6533,7 +6534,7 @@ public class UserManagerService extends IUserManager.Stub { private void setLastEnteredForegroundTimeToNow(@NonNull UserData userData) { userData.mLastEnteredForegroundTimeMillis = System.currentTimeMillis(); - scheduleWriteUser(userData); + scheduleWriteUser(userData.info.id); } @Override @@ -6832,7 +6833,7 @@ public class UserManagerService extends IUserManager.Stub { case WRITE_USER_MSG: removeMessages(WRITE_USER_MSG, msg.obj); synchronized (mPackagesLock) { - int userId = ((UserData) msg.obj).info.id; + int userId = (int) msg.obj; UserData userData = getUserDataNoChecks(userId); if (userData != null) { writeUserLP(userData); diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java index b7a2b86b1bcd..a814ca46fa5e 100644 --- a/services/core/java/com/android/server/pm/UserTypeFactory.java +++ b/services/core/java/com/android/server/pm/UserTypeFactory.java @@ -136,6 +136,7 @@ public final class UserTypeFactory { com.android.internal.R.color.system_neutral2_900) .setDefaultRestrictions(null) .setDefaultCrossProfileIntentFilters(getDefaultCloneCrossProfileIntentFilter()) + .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()) .setDefaultUserProperties(new UserProperties.Builder() .setStartWithParent(true) .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT) @@ -216,7 +217,8 @@ public final class UserTypeFactory { com.android.internal.R.color.profile_badge_1_dark, com.android.internal.R.color.profile_badge_2_dark, com.android.internal.R.color.profile_badge_3_dark) - .setDefaultRestrictions(restrictions); + .setDefaultRestrictions(restrictions) + .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings()); } /** @@ -337,6 +339,15 @@ public final class UserTypeFactory { return DefaultCrossProfileIntentFiltersUtils.getDefaultCloneProfileFilters(); } + /** Gets a default bundle, keyed by Settings.Secure String names, for non-managed profiles. */ + private static Bundle getDefaultNonManagedProfileSecureSettings() { + final Bundle settings = new Bundle(); + // Non-managed profiles go through neither SetupWizard nor DPC flows, so we automatically + // mark them as setup. + settings.putString(android.provider.Settings.Secure.USER_SETUP_COMPLETE, "1"); + return settings; + } + /** * Reads the given xml parser to obtain device user-type customization, and updates the given * map of {@link UserTypeDetails.Builder}s accordingly. diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java index c9ebeaee88ce..5015985dd747 100644 --- a/services/core/java/com/android/server/pm/VerifyingSession.java +++ b/services/core/java/com/android/server/pm/VerifyingSession.java @@ -361,7 +361,8 @@ final class VerifyingSession { } final int verifierUserId = verifierUser.getIdentifier(); - List<String> requiredVerifierPackages = Arrays.asList(mPm.mRequiredVerifierPackages); + List<String> requiredVerifierPackages = new ArrayList<>( + Arrays.asList(mPm.mRequiredVerifierPackages)); boolean requiredVerifierPackagesOverridden = false; // Allow verifier override for ADB installations which could already be unverified using diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index e5e32f0a9690..4d2b119d7800 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -206,8 +206,6 @@ final class DefaultPermissionGrantPolicy { static { SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS); SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND); - SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE); - SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND); } private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>(); diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index c5f939a2a66e..297ad73e054b 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1332,9 +1332,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Bg location is one-off runtime modifier permission and has no app op if (sPlatformPermissions.containsKey(permission) && !Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission) - && !Manifest.permission.BODY_SENSORS_BACKGROUND.equals(permission) - && !Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND - .equals(permission)) { + && !Manifest.permission.BODY_SENSORS_BACKGROUND.equals(permission)) { Slog.wtf(LOG_TAG, "Platform runtime permission " + permission + " with no app op defined!"); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java index cc2c9adfcba4..3492b2660c4a 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_ERRORED; import static android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_DEFAULT; +import static android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_DENIED; import static android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED; import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; @@ -3655,6 +3656,26 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt for (String permission : pkg.getRequestedPermissions()) { Integer permissionState = permissionStates.get(permission); + + if (Objects.equals(permission, Manifest.permission.USE_FULL_SCREEN_INTENT) + && permissionState == null) { + final PackageStateInternal ps; + final long token = Binder.clearCallingIdentity(); + try { + ps = mPackageManagerInt.getPackageStateInternal(pkg.getPackageName()); + } finally { + Binder.restoreCallingIdentity(token); + } + final String[] useFullScreenIntentPackageNames = + mContext.getResources().getStringArray( + com.android.internal.R.array.config_useFullScreenIntentPackages); + final boolean canUseFullScreenIntent = (ps != null && ps.isSystem()) + || ArrayUtils.contains(useFullScreenIntentPackageNames, + pkg.getPackageName()); + permissionState = canUseFullScreenIntent ? PERMISSION_STATE_GRANTED + : PERMISSION_STATE_DENIED; + } + if (permissionState == null || permissionState == PERMISSION_STATE_DEFAULT) { continue; } diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index 401eac6e2d19..7a5664f8135e 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -316,6 +316,7 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat private int resolveDatasourceOp(int code, int uid, @NonNull String packageName, @Nullable String attributionTag) { code = resolveRecordAudioOp(code, uid); + code = resolveSandboxedServiceOp(code, uid); if (attributionTag == null) { return code; } @@ -439,6 +440,28 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat return code; } + private int resolveSandboxedServiceOp(int code, int uid) { + if (!Process.isIsolated(uid) // simple check which fails-fast for the common case + || !(code == AppOpsManager.OP_RECORD_AUDIO || code == AppOpsManager.OP_CAMERA)) { + return code; + } + final HotwordDetectionServiceIdentity hotwordDetectionServiceIdentity = + mVoiceInteractionManagerInternal.getHotwordDetectionServiceIdentity(); + if (hotwordDetectionServiceIdentity != null + && uid == hotwordDetectionServiceIdentity.getIsolatedUid()) { + // Upgrade the op such that no indicators is shown for camera or audio service. This + // will bypass the permission checking for the original OP_RECORD_AUDIO and OP_CAMERA. + switch (code) { + case AppOpsManager.OP_RECORD_AUDIO: + return AppOpsManager.OP_RECORD_AUDIO_SANDBOXED; + case AppOpsManager.OP_CAMERA: + return AppOpsManager.OP_CAMERA_SANDBOXED; + } + } + return code; + } + + private int resolveUid(int code, int uid) { // The HotwordDetectionService is an isolated service, which ordinarily cannot hold // permissions. So we allow it to assume the owning package identity for certain diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 8165958bd4ef..fc6b4e9dcb20 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -222,6 +222,7 @@ import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener; import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.vr.VrManagerInternal; +import com.android.server.wallpaper.WallpaperManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.DisplayPolicy; import com.android.server.wm.DisplayRotation; @@ -412,6 +413,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { SensorPrivacyManager mSensorPrivacyManager; DisplayManager mDisplayManager; DisplayManagerInternal mDisplayManagerInternal; + + private WallpaperManagerInternal mWallpaperManagerInternal; + boolean mPreloadedRecentApps; final Object mServiceAcquireLock = new Object(); Vibrator mVibrator; // Vibrator for giving feedback of orientation changes @@ -5016,11 +5020,34 @@ public class PhoneWindowManager implements WindowManagerPolicy { return bootCompleted ? mKeyguardDrawnTimeout : 5000; } + @Nullable + private WallpaperManagerInternal getWallpaperManagerInternal() { + if (mWallpaperManagerInternal == null) { + mWallpaperManagerInternal = LocalServices.getService(WallpaperManagerInternal.class); + } + return mWallpaperManagerInternal; + } + + private void reportScreenTurningOnToWallpaper(int displayId) { + WallpaperManagerInternal wallpaperManagerInternal = getWallpaperManagerInternal(); + if (wallpaperManagerInternal != null) { + wallpaperManagerInternal.onScreenTurningOn(displayId); + } + } + + private void reportScreenTurnedOnToWallpaper(int displayId) { + WallpaperManagerInternal wallpaperManagerInternal = getWallpaperManagerInternal(); + if (wallpaperManagerInternal != null) { + wallpaperManagerInternal.onScreenTurnedOn(displayId); + } + } + // Called on the DisplayManager's DisplayPowerController thread. @Override public void screenTurningOn(int displayId, final ScreenOnListener screenOnListener) { if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turning on..."); + reportScreenTurningOnToWallpaper(displayId); if (displayId == DEFAULT_DISPLAY) { Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */); @@ -5061,6 +5088,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void screenTurnedOn(int displayId) { if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turned on..."); + reportScreenTurnedOnToWallpaper(displayId); + if (displayId != DEFAULT_DISPLAY) { return; } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 2e8a150f2b6d..e392c24026a7 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -667,15 +667,15 @@ public final class PowerManagerService extends SystemService // but the DreamService has not yet been told to start (it's an async process). private boolean mDozeStartInProgress; - // Whether to keep dreaming when the device is undocked. - private boolean mKeepDreamingWhenUndocked; + // Whether to keep dreaming when the device is unplugging. + private boolean mKeepDreamingWhenUnplugging; private final class DreamManagerStateListener implements DreamManagerInternal.DreamManagerStateListener { @Override - public void onKeepDreamingWhenUndockedChanged(boolean keepDreaming) { + public void onKeepDreamingWhenUnpluggingChanged(boolean keepDreaming) { synchronized (mLock) { - mKeepDreamingWhenUndocked = keepDreaming; + mKeepDreamingWhenUnplugging = keepDreaming; } } } @@ -2504,14 +2504,12 @@ public final class PowerManagerService extends SystemService return false; } - // Don't wake when undocking while dreaming if configured not to. - if (mKeepDreamingWhenUndocked + // Don't wake when unplugging while dreaming if configured not to. + if (mKeepDreamingWhenUnplugging && getGlobalWakefulnessLocked() == WAKEFULNESS_DREAMING - && wasPowered && !mIsPowered - && oldPlugType == BatteryManager.BATTERY_PLUGGED_DOCK) { + && wasPowered && !mIsPowered) { return false; } - // Don't wake when undocked from wireless charger. // See WirelessChargerDetector for justification. if (wasPowered && !mIsPowered @@ -4477,7 +4475,7 @@ public final class PowerManagerService extends SystemService + mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig); pw.println(" mTheaterModeEnabled=" + mTheaterModeEnabled); - pw.println(" mKeepDreamingWhenUndocked=" + mKeepDreamingWhenUndocked); + pw.println(" mKeepDreamingWhenUnplugging=" + mKeepDreamingWhenUnplugging); pw.println(" mSuspendWhenScreenOffDueToProximityConfig=" + mSuspendWhenScreenOffDueToProximityConfig); pw.println(" mDreamsSupportedConfig=" + mDreamsSupportedConfig); diff --git a/services/core/java/com/android/server/power/ShutdownCheckPoints.java b/services/core/java/com/android/server/power/ShutdownCheckPoints.java index 32f1bcfaad76..546dc819b4e6 100644 --- a/services/core/java/com/android/server/power/ShutdownCheckPoints.java +++ b/services/core/java/com/android/server/power/ShutdownCheckPoints.java @@ -295,11 +295,18 @@ public final class ShutdownCheckPoints { @Nullable String getProcessName() { try { - List<ActivityManager.RunningAppProcessInfo> runningProcesses = - mActivityManager.getRunningAppProcesses(); - for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) { - if (processInfo.pid == mCallerProcessId) { - return processInfo.processName; + List<ActivityManager.RunningAppProcessInfo> runningProcesses = null; + if (mActivityManager != null) { + runningProcesses = mActivityManager.getRunningAppProcesses(); + } else { + Slog.v(TAG, "No ActivityManager available to find process name with pid=" + + mCallerProcessId); + } + if (runningProcesses != null) { + for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) { + if (processInfo.pid == mCallerProcessId) { + return processInfo.processName; + } } } } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index c2d4ac694c39..b1430e7138e7 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -703,17 +703,20 @@ public final class ShutdownThread extends Thread { // vibrate before shutting down Vibrator vibrator = new SystemVibrator(context); try { - vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES); + if (vibrator.hasVibrator()) { + vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES); + // vibrator is asynchronous so we need to wait to avoid shutting down too soon. + try { + Thread.sleep(SHUTDOWN_VIBRATE_MS); + } catch (InterruptedException unused) { + // this is not critical and does not require logging + } + } } catch (Exception e) { // Failure to vibrate shouldn't interrupt shutdown. Just log it. Log.w(TAG, "Failed to vibrate during shutdown.", e); } - // vibrator is asynchronous so we need to wait to avoid shutting down too soon. - try { - Thread.sleep(SHUTDOWN_VIBRATE_MS); - } catch (InterruptedException unused) { - } } // Shutdown power Log.i(TAG, "Performing low-level shutdown..."); diff --git a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java b/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java index 231ffc6464c1..1d63489f3c4f 100644 --- a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java +++ b/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package com.android.server.power.stats; +package com.android.server.power.stats.wakeups; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_ALARM; +import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI; @@ -55,7 +56,8 @@ public class CpuWakeupStats { private static final String TAG = "CpuWakeupStats"; private static final String SUBSYSTEM_ALARM_STRING = "Alarm"; - private static final String SUBSYSTEM_ALARM_WIFI = "Wifi"; + private static final String SUBSYSTEM_WIFI_STRING = "Wifi"; + private static final String SUBSYSTEM_SOUND_TRIGGER_STRING = "Sound_trigger"; private static final String TRACE_TRACK_WAKEUP_ATTRIBUTION = "wakeup_attribution"; @VisibleForTesting static final long WAKEUP_REASON_HALF_WINDOW_MS = 500; @@ -91,12 +93,24 @@ public class CpuWakeupStats { mConfig.register(new HandlerExecutor(mHandler)); } + private static int typeToStatsType(int wakeupType) { + switch (wakeupType) { + case Wakeup.TYPE_ABNORMAL: + return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__TYPE__TYPE_ABNORMAL; + case Wakeup.TYPE_IRQ: + return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__TYPE__TYPE_IRQ; + } + return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__TYPE__TYPE_UNKNOWN; + } + private static int subsystemToStatsReason(int subsystem) { switch (subsystem) { case CPU_WAKEUP_SUBSYSTEM_ALARM: return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__ALARM; case CPU_WAKEUP_SUBSYSTEM_WIFI: return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__WIFI; + case CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER: + return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__SOUND_TRIGGER; } return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__UNKNOWN; } @@ -144,7 +158,7 @@ public class CpuWakeupStats { } } FrameworkStatsLog.write(FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED, - FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__TYPE__TYPE_IRQ, + typeToStatsType(wakeupToLog.mType), subsystemToStatsReason(subsystem), uids, wakeupToLog.mElapsedMillis, @@ -524,8 +538,10 @@ public class CpuWakeupStats { switch (rawSubsystem) { case SUBSYSTEM_ALARM_STRING: return CPU_WAKEUP_SUBSYSTEM_ALARM; - case SUBSYSTEM_ALARM_WIFI: + case SUBSYSTEM_WIFI_STRING: return CPU_WAKEUP_SUBSYSTEM_WIFI; + case SUBSYSTEM_SOUND_TRIGGER_STRING: + return CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER; } return CPU_WAKEUP_SUBSYSTEM_UNKNOWN; } @@ -535,25 +551,43 @@ public class CpuWakeupStats { case CPU_WAKEUP_SUBSYSTEM_ALARM: return SUBSYSTEM_ALARM_STRING; case CPU_WAKEUP_SUBSYSTEM_WIFI: - return SUBSYSTEM_ALARM_WIFI; + return SUBSYSTEM_WIFI_STRING; + case CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER: + return SUBSYSTEM_SOUND_TRIGGER_STRING; case CPU_WAKEUP_SUBSYSTEM_UNKNOWN: return "Unknown"; } return "N/A"; } - private static final class Wakeup { + @VisibleForTesting + static final class Wakeup { private static final String PARSER_TAG = "CpuWakeupStats.Wakeup"; private static final String ABORT_REASON_PREFIX = "Abort"; - private static final Pattern sIrqPattern = Pattern.compile("^(\\d+)\\s+(\\S+)"); + private static final Pattern sIrqPattern = Pattern.compile("^(\\-?\\d+)\\s+(\\S+)"); + + /** + * Classical interrupts, which arrive on a dedicated GPIO pin into the main CPU. + * Sometimes, when multiple IRQs happen close to each other, they may get batched together. + */ + static final int TYPE_IRQ = 1; + + /** + * Non-IRQ wakeups. The exact mechanism for these is unknown, except that these explicitly + * do not use an interrupt line or a GPIO pin. + */ + static final int TYPE_ABNORMAL = 2; + + int mType; long mElapsedMillis; long mUptimeMillis; IrqDevice[] mDevices; - private Wakeup(IrqDevice[] devices, long elapsedMillis, long uptimeMillis) { + private Wakeup(int type, IrqDevice[] devices, long elapsedMillis, long uptimeMillis) { + mType = type; + mDevices = devices; mElapsedMillis = elapsedMillis; mUptimeMillis = uptimeMillis; - mDevices = devices; } static Wakeup parseWakeup(String rawReason, long elapsedMillis, long uptimeMillis) { @@ -563,6 +597,7 @@ public class CpuWakeupStats { return null; } + int type = TYPE_IRQ; int parsedDeviceCount = 0; final IrqDevice[] parsedDevices = new IrqDevice[components.length]; @@ -574,6 +609,10 @@ public class CpuWakeupStats { try { line = Integer.parseInt(matcher.group(1)); device = matcher.group(2); + if (line < 0) { + // Assuming that IRQ wakeups cannot come batched with non-IRQ wakeups. + type = TYPE_ABNORMAL; + } } catch (NumberFormatException e) { Slog.e(PARSER_TAG, "Exception while parsing device names from part: " + component, e); @@ -585,15 +624,16 @@ public class CpuWakeupStats { if (parsedDeviceCount == 0) { return null; } - return new Wakeup(Arrays.copyOf(parsedDevices, parsedDeviceCount), elapsedMillis, + return new Wakeup(type, Arrays.copyOf(parsedDevices, parsedDeviceCount), elapsedMillis, uptimeMillis); } @Override public String toString() { return "Wakeup{" - + "mElapsedMillis=" + mElapsedMillis - + ", mUptimeMillis=" + TimeUtils.formatDuration(mUptimeMillis) + + "mType=" + mType + + ", mElapsedMillis=" + mElapsedMillis + + ", mUptimeMillis=" + mUptimeMillis + ", mDevices=" + Arrays.toString(mDevices) + '}'; } diff --git a/services/core/java/com/android/server/power/stats/IrqDeviceMap.java b/services/core/java/com/android/server/power/stats/wakeups/IrqDeviceMap.java index 091d18e30ccc..8644f720c661 100644 --- a/services/core/java/com/android/server/power/stats/IrqDeviceMap.java +++ b/services/core/java/com/android/server/power/stats/wakeups/IrqDeviceMap.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.power.stats; +package com.android.server.power.stats.wakeups; import android.annotation.XmlRes; import android.content.Context; diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 7beb1edfe51f..e437be8e01b5 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -105,36 +105,46 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver { @Override public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage, @FailureReasons int failureReason, int mitigationCount) { - // For native crashes, we will roll back any available rollbacks + boolean anyRollbackAvailable = !mContext.getSystemService(RollbackManager.class) + .getAvailableRollbacks().isEmpty(); + int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; + if (failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH - && !mContext.getSystemService(RollbackManager.class) - .getAvailableRollbacks().isEmpty()) { - return PackageHealthObserverImpact.USER_IMPACT_MEDIUM; - } - if (getAvailableRollback(failedPackage) == null) { - // Don't handle the notification, no rollbacks available for the package - return PackageHealthObserverImpact.USER_IMPACT_NONE; - } else { + && anyRollbackAvailable) { + // For native crashes, we will directly roll back any available rollbacks + // Note: For non-native crashes the rollback-all step has higher impact + impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30; + } else if (mitigationCount == 1 && getAvailableRollback(failedPackage) != null) { // Rollback is available, we may get a callback into #execute - return PackageHealthObserverImpact.USER_IMPACT_MEDIUM; + impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30; + } else if (mitigationCount > 1 && anyRollbackAvailable) { + // If any rollbacks are available, we will commit them + impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70; } + + return impact; } @Override public boolean execute(@Nullable VersionedPackage failedPackage, @FailureReasons int rollbackReason, int mitigationCount) { if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) { - mHandler.post(() -> rollbackAll()); + mHandler.post(() -> rollbackAll(rollbackReason)); return true; } - RollbackInfo rollback = getAvailableRollback(failedPackage); - if (rollback == null) { - Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage); - return false; + if (mitigationCount == 1) { + RollbackInfo rollback = getAvailableRollback(failedPackage); + if (rollback == null) { + Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage); + return false; + } + mHandler.post(() -> rollbackPackage(rollback, failedPackage, rollbackReason)); + } else if (mitigationCount > 1) { + mHandler.post(() -> rollbackAll(rollbackReason)); } - mHandler.post(() -> rollbackPackage(rollback, failedPackage, rollbackReason)); - // Assume rollback executed successfully + + // Assume rollbacks executed successfully return true; } @@ -468,7 +478,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver { } @WorkerThread - private void rollbackAll() { + private void rollbackAll(@FailureReasons int rollbackReason) { assertInWorkerThread(); RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks(); @@ -487,7 +497,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver { for (RollbackInfo rollback : rollbacks) { VersionedPackage sample = rollback.getPackages().get(0).getVersionRolledBackFrom(); - rollbackPackage(rollback, sample, PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); + rollbackPackage(rollback, sample, rollbackReason); } } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java index 584fbddee478..3699557706fd 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java @@ -27,4 +27,10 @@ public abstract class WallpaperManagerInternal { * Notifies the display is ready for adding wallpaper on it. */ public abstract void onDisplayReady(int displayId); + + /** Notifies when the screen finished turning on and is visible to the user. */ + public abstract void onScreenTurnedOn(int displayId); + + /** Notifies when the screen starts turning on and is not yet visible to the user. */ + public abstract void onScreenTurningOn(int displayId); } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index b1b0c559aad4..e17866922990 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1613,6 +1613,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub public void onDisplayReady(int displayId) { onDisplayReadyInternal(displayId); } + + @Override + public void onScreenTurnedOn(int displayId) { + notifyScreenTurnedOn(displayId); + } + @Override + public void onScreenTurningOn(int displayId) { + notifyScreenTurningOn(displayId); + } } void initialize() { @@ -2442,6 +2451,54 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + /** + * Propagates screen turned on event to wallpaper engine. + */ + @Override + public void notifyScreenTurnedOn(int displayId) { + synchronized (mLock) { + final WallpaperData data = mWallpaperMap.get(mCurrentUserId); + if (data != null + && data.connection != null + && data.connection.containsDisplay(displayId)) { + final IWallpaperEngine engine = data.connection + .getDisplayConnectorOrCreate(displayId).mEngine; + if (engine != null) { + try { + engine.onScreenTurnedOn(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + } + } + } + + + + /** + * Propagate screen turning on event to wallpaper engine. + */ + @Override + public void notifyScreenTurningOn(int displayId) { + synchronized (mLock) { + final WallpaperData data = mWallpaperMap.get(mCurrentUserId); + if (data != null + && data.connection != null + && data.connection.containsDisplay(displayId)) { + final IWallpaperEngine engine = data.connection + .getDisplayConnectorOrCreate(displayId).mEngine; + if (engine != null) { + try { + engine.onScreenTurningOn(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + } + } + } + @Override public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) { checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW); @@ -3569,6 +3626,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private void dumpWallpaper(WallpaperData wallpaper, PrintWriter pw) { if (wallpaper == null) { pw.println(" (null entry)"); + return; } pw.print(" User "); pw.print(wallpaper.userId); pw.print(": id="); pw.print(wallpaper.wallpaperId); diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java index 83804f75afea..32f7b9682fb7 100644 --- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java +++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java @@ -466,8 +466,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, } boolean isAnimatingByRecents(@NonNull Task task) { - return task.isAnimatingByRecents() - || mService.mAtmService.getTransitionController().inRecentsTransition(task); + return task.isAnimatingByRecents(); } void dump(PrintWriter pw, String prefix) { diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index fa3a186a6153..f3001133338a 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -25,6 +25,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFI import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; +import static com.android.internal.util.DumpUtils.dumpSparseArray; +import static com.android.internal.util.DumpUtils.dumpSparseArrayValues; import static com.android.server.accessibility.AccessibilityTraceFileProto.ENTRY; import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER; import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER_H; @@ -542,15 +544,12 @@ final class AccessibilityController { } void dump(PrintWriter pw, String prefix) { - for (int i = 0; i < mDisplayMagnifiers.size(); i++) { - final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.valueAt(i); - if (displayMagnifier != null) { - displayMagnifier.dump(pw, prefix - + "Magnification display# " + mDisplayMagnifiers.keyAt(i)); - } - } - pw.println(prefix - + "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver); + dumpSparseArray(pw, prefix, mDisplayMagnifiers, "magnification display", + (index, key) -> pw.printf("%sDisplay #%d:", prefix + " ", key), + dm -> dm.dump(pw, "")); + dumpSparseArrayValues(pw, prefix, mWindowsForAccessibilityObserver, + "windows for accessibility observer"); + mAccessibilityWindowsPopulator.dump(pw, prefix); } void onFocusChanged(InputTarget lastTarget, InputTarget newTarget) { diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java index 21b241a0d117..70f20075b48c 100644 --- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java +++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import static com.android.internal.util.DumpUtils.KeyDumper; +import static com.android.internal.util.DumpUtils.ValueDumper; +import static com.android.internal.util.DumpUtils.dumpSparseArray; import static com.android.server.wm.utils.RegionUtils.forEachRect; import android.annotation.NonNull; @@ -40,6 +43,7 @@ import android.window.WindowInfosListener; import com.android.internal.annotations.GuardedBy; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -562,6 +566,35 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener { notifyWindowsChanged(displayIdsForWindowsChanged); } + void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.println("AccessibilityWindowsPopulator"); + String prefix2 = prefix + " "; + + pw.print(prefix2); pw.print("mWindowsNotificationEnabled: "); + pw.println(mWindowsNotificationEnabled); + + if (mVisibleWindows.isEmpty()) { + pw.print(prefix2); pw.println("No visible windows"); + } else { + pw.print(prefix2); pw.print(mVisibleWindows.size()); + pw.print(" visible windows: "); pw.println(mVisibleWindows); + } + KeyDumper noKeyDumper = (i, k) -> {}; // display id is already shown on value; + KeyDumper displayDumper = (i, d) -> pw.printf("%sDisplay #%d: ", prefix, d); + // Ideally magnificationSpecDumper should use spec.dump(pw), but there is no such method + ValueDumper<MagnificationSpec> magnificationSpecDumper = spec -> pw.print(spec); + + dumpSparseArray(pw, prefix2, mDisplayInfos, "display info", noKeyDumper, d -> pw.print(d)); + dumpSparseArray(pw, prefix2, mInputWindowHandlesOnDisplays, "window handles on display", + displayDumper, list -> pw.print(list)); + dumpSparseArray(pw, prefix2, mMagnificationSpecInverseMatrix, "magnification spec matrix", + noKeyDumper, matrix -> matrix.dump(pw)); + dumpSparseArray(pw, prefix2, mCurrentMagnificationSpec, "current magnification spec", + noKeyDumper, magnificationSpecDumper); + dumpSparseArray(pw, prefix2, mPreviousMagnificationSpec, "previous magnification spec", + noKeyDumper, magnificationSpecDumper); + } + @GuardedBy("mLock") private void releaseResources() { mInputWindowHandlesOnDisplays.clear(); diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index ff1c28ad1973..8bbcd2787931 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -78,8 +78,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManagerInternal; -import android.content.pm.ParceledListSlice; -import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.os.Binder; import android.os.Bundle; @@ -99,7 +97,6 @@ import android.window.TransitionInfo; import com.android.internal.app.AssistUtils; import com.android.internal.policy.IKeyguardDismissCallback; -import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import com.android.server.LocalServices; import com.android.server.Watchdog; @@ -1144,19 +1141,11 @@ class ActivityClientController extends IActivityClientController.Stub { // Initiate the transition. final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */, controller, mService.mWindowManager.mSyncEngine); - if (mService.mWindowManager.mSyncEngine.hasActiveSync()) { - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - "Creating Pending Multiwindow Fullscreen Request: %s", transition); - mService.mWindowManager.mSyncEngine.queueSyncSet( - () -> r.mTransitionController.moveToCollecting(transition), - () -> { - executeFullscreenRequestTransition(fullscreenRequest, callback, r, - transition, true /* queued */); - }); - } else { - executeFullscreenRequestTransition(fullscreenRequest, callback, r, transition, - false /* queued */); - } + r.mTransitionController.startCollectOrQueue(transition, + (deferred) -> { + executeFullscreenRequestTransition(fullscreenRequest, callback, r, + transition, deferred); + }); } private void executeFullscreenRequestTransition(int fullscreenRequest, IRemoteCallback callback, @@ -1645,18 +1634,15 @@ class ActivityClientController extends IActivityClientController.Stub { launchedFromHome = root.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_HOME); } - // If the activity is one of the main entry points for the application, then we should + // If the activity was launched directly from the home screen, then we should // refrain from finishing the activity and instead move it to the back to keep it in // memory. The requirements for this are: // 1. The activity is the last running activity in the task. // 2. The current activity is the base activity for the task. - // 3. a. If the activity was launched by the home process, we trust that its intent - // was resolved, so we check if the it is a main intent for the application. - // b. Otherwise, we query Package Manager to verify whether the activity is a - // launcher activity for the application. + // 3. The activity was launched by the home process, and is one of the main entry + // points for the application. if (baseActivityIntent != null && isLastRunningActivity - && ((launchedFromHome && ActivityRecord.isMainIntent(baseActivityIntent)) - || isLauncherActivity(baseActivityIntent.getComponent()))) { + && launchedFromHome && ActivityRecord.isMainIntent(baseActivityIntent)) { moveActivityTaskToBack(token, true /* nonRoot */); return; } @@ -1668,31 +1654,6 @@ class ActivityClientController extends IActivityClientController.Stub { } } - /** - * Queries PackageManager to see if the given activity is one of the main entry point for the - * application. This should not be called with the WM lock held. - */ - @SuppressWarnings("unchecked") - private boolean isLauncherActivity(@NonNull ComponentName activity) { - final Intent queryIntent = new Intent(Intent.ACTION_MAIN); - queryIntent.addCategory(Intent.CATEGORY_LAUNCHER); - queryIntent.setPackage(activity.getPackageName()); - try { - final ParceledListSlice<ResolveInfo> resolved = - mService.getPackageManager().queryIntentActivities( - queryIntent, null, 0, mContext.getUserId()); - if (resolved == null) return false; - for (final ResolveInfo ri : resolved.getList()) { - if (ri.getComponentInfo().getComponentName().equals(activity)) { - return true; - } - } - } catch (RemoteException e) { - Slog.e(TAG, "Failed to query intent activities", e); - } - return false; - } - @Override public void enableTaskLocaleOverride(IBinder token) { if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 8346e7c83190..f5cb613601fe 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -306,7 +306,6 @@ import android.os.Bundle; import android.os.Debug; import android.os.IBinder; import android.os.IRemoteCallback; -import android.os.LocaleList; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteCallbackList; @@ -2865,11 +2864,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } - if (animate && mTransitionController.inCollectingTransition(startingWindow) - && startingWindow.cancelAndRedraw()) { + if (animate && mTransitionController.inCollectingTransition(startingWindow)) { // Defer remove starting window after transition start. - // If splash screen window was in collecting, the client side is unable to draw because - // of Session#cancelDraw, which will blocking the remove animation. + // The surface of app window could really show after the transition finish. startingWindow.mSyncTransaction.addTransactionCommittedListener(Runnable::run, () -> { synchronized (mAtmService.mGlobalLock) { surface.remove(true); @@ -3522,7 +3519,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean endTask = task.getTopNonFinishingActivity() == null && !task.isClearingToReuseTask(); - mTransitionController.requestCloseTransitionIfNeeded(endTask ? task : this); + final Transition newTransition = + mTransitionController.requestCloseTransitionIfNeeded(endTask ? task : this); if (isState(RESUMED)) { if (endTask) { mAtmService.getTaskChangeNotificationController().notifyTaskRemovalStarted( @@ -3543,8 +3541,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // the best capture timing (e.g. IME window capture), // No need additional task capture while task is controlled by RecentsAnimation. if (mAtmService.mWindowManager.mTaskSnapshotController != null - && !(task.isAnimatingByRecents() - || mTransitionController.inRecentsTransition(task))) { + && !task.isAnimatingByRecents()) { final ArraySet<Task> tasks = Sets.newArraySet(task); mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks); mAtmService.mWindowManager.mTaskSnapshotController @@ -3576,7 +3573,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else if (!isState(PAUSING)) { if (mVisibleRequested) { // Prepare and execute close transition. - prepareActivityHideTransitionAnimation(); + if (mTransitionController.isShellTransitionsEnabled()) { + setVisibility(false); + if (newTransition != null) { + // This is a transition specifically for this close operation, so set + // ready now. + newTransition.setReady(mDisplayContent, true); + } + } else { + prepareActivityHideTransitionAnimation(); + } } final boolean removedActivity = completeFinishing("finishIfPossible") == null; @@ -4138,7 +4144,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ void handleAppDied() { final boolean remove; - if ((mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE + if (Process.isSdkSandboxUid(getUid())) { + // Sandbox activities are created for SDKs run in the sandbox process, when the sandbox + // process dies, the SDKs are unloaded and can not handle the activity, so sandbox + // activity records should be removed. + remove = true; + } else if ((mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE || mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE) && launchCount < 3 && !finishing) { // If the process crashed during a resize, always try to relaunch it, unless it has @@ -7917,6 +7928,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( task.mTaskId, requestedOrientation); + + mDisplayContent.getDisplayRotation().onSetRequestedOrientation(); } /* @@ -9760,6 +9773,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * directly with keeping its record. */ void restartProcessIfVisible() { + if (finishing) return; Slog.i(TAG, "Request to restart process of " + this); // Reset the existing override configuration so it can be updated according to the latest @@ -9794,7 +9808,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (mTransitionController.isShellTransitionsEnabled()) { final Transition transition = new Transition(TRANSIT_RELAUNCH, 0 /* flags */, mTransitionController, mWmService.mSyncEngine); - final Runnable executeRestart = () -> { + mTransitionController.startCollectOrQueue(transition, (deferred) -> { if (mState != RESTARTING_PROCESS || !attachedToProcess()) { transition.abort(); return; @@ -9806,14 +9820,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mTransitionController.requestStartTransition(transition, task, null /* remoteTransition */, null /* displayChange */); scheduleStopForRestartProcess(); - }; - if (mWmService.mSyncEngine.hasActiveSync()) { - mWmService.mSyncEngine.queueSyncSet( - () -> mTransitionController.moveToCollecting(transition), executeRestart); - } else { - mTransitionController.moveToCollecting(transition); - executeRestart.run(); - } + }); } else { startFreezingScreen(); scheduleStopForRestartProcess(); @@ -10522,11 +10529,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override boolean isSyncFinished() { - if (task != null && mTransitionController.isTransientHide(task)) { - // The activity keeps visibleRequested but may be hidden later, so no need to wait for - // it to be drawn. - return true; - } if (!super.isSyncFinished()) return false; if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController .isVisibilityUnknown(this)) { @@ -10591,17 +10593,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } - LocaleList locale; final ActivityTaskManagerInternal.PackageConfig appConfig = mAtmService.mPackageConfigPersister.findPackageConfiguration( task.realActivity.getPackageName(), mUserId); - // if there is no app locale for the package, clear the target activity's locale. - if (appConfig == null || appConfig.mLocales == null || appConfig.mLocales.isEmpty()) { - locale = LocaleList.getEmptyLocaleList(); - } else { - locale = appConfig.mLocales; + // If package lookup yields locales, set the target activity's locales to match, + // otherwise leave target activity as-is. + if (appConfig != null && appConfig.mLocales != null && !appConfig.mLocales.isEmpty()) { + resolvedConfig.setLocales(appConfig.mLocales); } - resolvedConfig.setLocales(locale); } /** diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 7c1e9071b926..bfe298653584 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -577,7 +577,6 @@ public class ActivityStartController { final Transition transition = controller.getCollectingTransition(); if (transition != null) { transition.setRemoteAnimationApp(r.app.getThread()); - controller.collect(task); controller.setTransientLaunch(r, TaskDisplayArea.getRootTaskAbove(rootTask)); } task.moveToFront("startExistingRecents"); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index d4f151f5c66d..c5e75faf2c6c 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1606,6 +1606,8 @@ class ActivityStarter { transitionController.requestStartTransition(newTransition, mTargetTask == null ? started.getTask() : mTargetTask, remoteTransition, null /* displayChange */); + } else if (result == START_SUCCESS && mStartActivity.isState(RESUMED)) { + // Do nothing if the activity is started and is resumed directly. } else if (isStarted) { // Make the collecting transition wait until this request is ready. transitionController.setReady(started, false); @@ -2546,6 +2548,7 @@ class ActivityStarter { mAvoidMoveToFront = false; mFrozeTaskList = false; mTransientLaunch = false; + mPriorAboveTask = null; mDisplayLockAndOccluded = false; mVoiceSession = null; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 12fe6a0dba25..064af0f3165e 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -250,7 +250,6 @@ import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.TransferPipe; import com.android.internal.policy.AttributeCache; import com.android.internal.policy.KeyguardDismissCallback; -import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; @@ -831,7 +830,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private final Runnable mUpdateOomAdjRunnable = new Runnable() { @Override public void run() { - mAmInternal.updateOomAdj(); + mAmInternal.updateOomAdj(ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY); } }; @@ -2873,29 +2872,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */, getTransitionController(), mWindowManager.mSyncEngine); - if (mWindowManager.mSyncEngine.hasActiveSync()) { - mWindowManager.mSyncEngine.queueSyncSet( - () -> getTransitionController().moveToCollecting(transition), - () -> { - if (!task.getWindowConfiguration().canResizeTask()) { - Slog.w(TAG, "resizeTask not allowed on task=" + task); - transition.abort(); - return; - } - getTransitionController().requestStartTransition(transition, task, - null /* remoteTransition */, null /* displayChange */); - getTransitionController().collect(task); - task.resize(bounds, resizeMode, preserveWindow); - transition.setReady(task, true); - }); - } else { - getTransitionController().moveToCollecting(transition); - getTransitionController().requestStartTransition(transition, task, - null /* remoteTransition */, null /* displayChange */); - getTransitionController().collect(task); - task.resize(bounds, resizeMode, preserveWindow); - transition.setReady(task, true); - } + getTransitionController().startCollectOrQueue(transition, + (deferred) -> { + if (deferred && !task.getWindowConfiguration().canResizeTask()) { + Slog.w(TAG, "resizeTask not allowed on task=" + task); + transition.abort(); + return; + } + getTransitionController().requestStartTransition(transition, task, + null /* remoteTransition */, null /* displayChange */); + getTransitionController().collect(task); + task.resize(bounds, resizeMode, preserveWindow); + transition.setReady(task, true); + }); } } finally { Binder.restoreCallingIdentity(ident); @@ -3626,34 +3615,25 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mActivityClientController.dismissKeyguard(r.token, new KeyguardDismissCallback() { @Override public void onDismissSucceeded() { - if (transition != null && mWindowManager.mSyncEngine.hasActiveSync()) { - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - "Creating Pending Pip-Enter: %s", transition); - mWindowManager.mSyncEngine.queueSyncSet( - () -> getTransitionController().moveToCollecting(transition), - enterPipRunnable); - } else { - // Move to collecting immediately to "claim" the sync-engine for this - // transition. - if (transition != null) { - getTransitionController().moveToCollecting(transition); - } + if (transition == null) { mH.post(enterPipRunnable); + return; } + getTransitionController().startCollectOrQueue(transition, (deferred) -> { + if (deferred) { + enterPipRunnable.run(); + } else { + mH.post(enterPipRunnable); + } + }); } }, null /* message */); } else { // Enter picture in picture immediately otherwise - if (transition != null && mWindowManager.mSyncEngine.hasActiveSync()) { - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - "Creating Pending Pip-Enter: %s", transition); - mWindowManager.mSyncEngine.queueSyncSet( - () -> getTransitionController().moveToCollecting(transition), - enterPipRunnable); + if (transition != null) { + getTransitionController().startCollectOrQueue(transition, + (deferred) -> enterPipRunnable.run()); } else { - if (transition != null) { - getTransitionController().moveToCollecting(transition); - } enterPipRunnable.run(); } } diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java index 48cf567ba9be..d916a1be1a03 100644 --- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java +++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java @@ -23,6 +23,7 @@ import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Handler; import android.os.Trace; import android.util.ArraySet; import android.util.Slog; @@ -172,7 +173,7 @@ class BLASTSyncEngine { if (ran) { return; } - mWm.mH.removeCallbacks(this); + mHandler.removeCallbacks(this); ran = true; SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (WindowContainer wc : wcAwaitingCommit) { @@ -199,13 +200,13 @@ class BLASTSyncEngine { }; CommitCallback callback = new CommitCallback(); merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::onCommitted); - mWm.mH.postDelayed(callback, BLAST_TIMEOUT_DURATION); + mHandler.postDelayed(callback, BLAST_TIMEOUT_DURATION); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady"); mListener.onTransactionReady(mSyncId, merged); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); mActiveSyncs.remove(mSyncId); - mWm.mH.removeCallbacks(mOnTimeout); + mHandler.removeCallbacks(mOnTimeout); // Immediately start the next pending sync-transaction if there is one. if (mActiveSyncs.size() == 0 && !mPendingSyncSets.isEmpty()) { @@ -216,7 +217,7 @@ class BLASTSyncEngine { throw new IllegalStateException("Pending Sync Set didn't start a sync."); } // Post this so that the now-playing transition setup isn't interrupted. - mWm.mH.post(() -> { + mHandler.post(() -> { synchronized (mWm.mGlobalLock) { pt.mApplySync.run(); } @@ -228,7 +229,7 @@ class BLASTSyncEngine { if (mReady == ready) { return; } - ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready", mSyncId); + ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready %b", mSyncId, ready); mReady = ready; if (!ready) return; mWm.mWindowPlacerLocked.requestTraversal(); @@ -269,6 +270,7 @@ class BLASTSyncEngine { } private final WindowManagerService mWm; + private final Handler mHandler; private int mNextSyncId = 0; private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>(); @@ -280,7 +282,13 @@ class BLASTSyncEngine { private final ArrayList<PendingSyncSet> mPendingSyncSets = new ArrayList<>(); BLASTSyncEngine(WindowManagerService wms) { + this(wms, wms.mH); + } + + @VisibleForTesting + BLASTSyncEngine(WindowManagerService wms, Handler mainHandler) { mWm = wms; + mHandler = mainHandler; } /** @@ -305,8 +313,8 @@ class BLASTSyncEngine { if (mActiveSyncs.size() != 0) { // We currently only support one sync at a time, so start a new SyncGroup when there is // another may cause issue. - ProtoLog.w(WM_DEBUG_SYNC_ENGINE, - "SyncGroup %d: Started when there is other active SyncGroup", s.mSyncId); + Slog.e(TAG, "SyncGroup " + s.mSyncId + + ": Started when there is other active SyncGroup"); } mActiveSyncs.put(s.mSyncId, s); ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", @@ -325,7 +333,7 @@ class BLASTSyncEngine { @VisibleForTesting void scheduleTimeout(SyncGroup s, long timeoutMs) { - mWm.mH.postDelayed(s.mOnTimeout, timeoutMs); + mHandler.postDelayed(s.mOnTimeout, timeoutMs); } void addToSyncSet(int id, WindowContainer wc) { diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 587e7204f993..11d84ffbd064 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -286,8 +286,8 @@ class BackNavigationController { currentActivity.getCustomAnimation(false/* open */); if (customAppTransition != null) { infoBuilder.setCustomAnimation(currentActivity.packageName, - customAppTransition.mExitAnim, customAppTransition.mEnterAnim, + customAppTransition.mExitAnim, customAppTransition.mBackgroundColor); } } @@ -532,14 +532,7 @@ class BackNavigationController { if (newFocus != null && newFocus != mNavigatingWindow && (newFocus.mActivityRecord == null || (newFocus.mActivityRecord == mNavigatingWindow.mActivityRecord))) { - EventLogTags.writeWmBackNaviCanceled("focusWindowChanged"); - if (isMonitorForRemote()) { - mObserver.sendResult(null /* result */); - } - if (isMonitorAnimationOrTransition()) { - // transition won't happen, cancel internal status - clearBackAnimations(); - } + cancelBackNavigating("focusWindowChanged"); } } @@ -553,19 +546,12 @@ class BackNavigationController { } final ArrayList<WindowContainer> all = new ArrayList<>(opening); all.addAll(closing); - for (WindowContainer app : all) { - if (app.hasChild(mNavigatingWindow)) { - EventLogTags.writeWmBackNaviCanceled("transitionHappens"); - if (isMonitorForRemote()) { - mObserver.sendResult(null /* result */); - } - if (isMonitorAnimationOrTransition()) { - clearBackAnimations(); - } + for (int i = all.size() - 1; i >= 0; --i) { + if (all.get(i).hasChild(mNavigatingWindow)) { + cancelBackNavigating("transitionHappens"); break; } } - } private boolean atSameDisplay(WindowState newFocus) { @@ -575,6 +561,17 @@ class BackNavigationController { final int navigatingDisplayId = mNavigatingWindow.getDisplayId(); return newFocus == null || newFocus.getDisplayId() == navigatingDisplayId; } + + private void cancelBackNavigating(String reason) { + EventLogTags.writeWmBackNaviCanceled(reason); + if (isMonitorForRemote()) { + mObserver.sendResult(null /* result */); + } + if (isMonitorAnimationOrTransition()) { + clearBackAnimations(); + } + cancelPendingAnimation(); + } } // For shell transition @@ -585,14 +582,14 @@ class BackNavigationController { * The closing target should only exist in close list, but the opening target can be either in * open or close list. */ - void onTransactionReady(Transition transition) { + void onTransactionReady(Transition transition, ArrayList<Transition.ChangeInfo> targets) { if (!isMonitoringTransition()) { return; } - final ArraySet<WindowContainer> targets = transition.mParticipants; for (int i = targets.size() - 1; i >= 0; --i) { - final WindowContainer wc = targets.valueAt(i); - if (wc.asActivityRecord() == null && wc.asTask() == null) { + final WindowContainer wc = targets.get(i).mContainer; + if (wc.asActivityRecord() == null && wc.asTask() == null + && wc.asTaskFragment() == null) { continue; } // WC can be visible due to setLaunchBehind @@ -605,6 +602,9 @@ class BackNavigationController { final boolean matchAnimationTargets = isWaitBackTransition() && (transition.mType == TRANSIT_CLOSE || transition.mType == TRANSIT_TO_BACK) && mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps); + ProtoLog.d(WM_DEBUG_BACK_PREVIEW, + "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b", + mTmpOpenApps, mTmpCloseApps, mAnimationHandler, matchAnimationTargets); if (!matchAnimationTargets) { mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps); } else { @@ -645,31 +645,28 @@ class BackNavigationController { if (finishedTransition == mWaitTransitionFinish) { clearBackAnimations(); } + if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) { return false; } - ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Handling the deferred animation after transition finished"); - // Show the target surface and its parents to prevent it or its parents hidden when - // the transition finished. - // The target could be affected by transition when : - // Open transition -> the open target in back navigation - // Close transition -> the close target in back navigation. + // Find the participated container collected by transition when : + // Open transition -> the open target in back navigation, the close target in transition. + // Close transition -> the close target in back navigation, the open target in transition. boolean hasTarget = false; - final SurfaceControl.Transaction t = - mPendingAnimationBuilder.mCloseTarget.getPendingTransaction(); - for (int i = 0; i < targets.size(); i++) { - final WindowContainer wc = targets.get(i).mContainer; - if (wc.asActivityRecord() == null && wc.asTask() == null) { - continue; - } else if (!mPendingAnimationBuilder.containTarget(wc)) { + for (int i = 0; i < finishedTransition.mParticipants.size(); i++) { + final WindowContainer wc = finishedTransition.mParticipants.valueAt(i); + if (wc.asActivityRecord() == null && wc.asTask() == null + && wc.asTaskFragment() == null) { continue; } - hasTarget = true; - t.show(wc.getSurfaceControl()); + if (mPendingAnimationBuilder.containTarget(wc)) { + hasTarget = true; + break; + } } if (!hasTarget) { @@ -677,20 +674,33 @@ class BackNavigationController { Slog.w(TAG, "Finished transition didn't include the targets" + " open: " + mPendingAnimationBuilder.mOpenTarget + " close: " + mPendingAnimationBuilder.mCloseTarget); - try { - mPendingAnimationBuilder.mBackAnimationAdapter.getRunner().onAnimationCancelled(); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - mPendingAnimationBuilder = null; + cancelPendingAnimation(); return false; } + // Ensure the final animation targets which hidden by transition could be visible. + for (int i = 0; i < targets.size(); i++) { + final WindowContainer wc = targets.get(i).mContainer; + wc.prepareSurfaces(); + } + scheduleAnimation(mPendingAnimationBuilder); mPendingAnimationBuilder = null; return true; } + private void cancelPendingAnimation() { + if (mPendingAnimationBuilder == null) { + return; + } + try { + mPendingAnimationBuilder.mBackAnimationAdapter.getRunner().onAnimationCancelled(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote animation gone", e); + } + mPendingAnimationBuilder = null; + } + /** * Create and handling animations status for an open/close animation targets. */ @@ -829,10 +839,16 @@ class BackNavigationController { if (!mComposed) { return false; } + + // WC must be ActivityRecord in legacy transition, but it also can be Task or + // TaskFragment when using Shell transition. + // Open target: Can be Task or ActivityRecord or TaskFragment + // Close target: Limit to the top activity for now, to reduce the chance of misjudgment. final WindowContainer target = open ? mOpenAdaptor.mTarget : mCloseAdaptor.mTarget; if (mSwitchType == TASK_SWITCH) { return wc == target - || (wc.asTask() != null && wc.hasChild(target)); + || (wc.asTask() != null && wc.hasChild(target)) + || (wc.asActivityRecord() != null && target.hasChild(wc)); } else if (mSwitchType == ACTIVITY_SWITCH) { return wc == target || (wc.asTaskFragment() != null && wc.hasChild(target)); } @@ -1067,7 +1083,7 @@ class BackNavigationController { boolean containTarget(@NonNull WindowContainer wc) { return wc == mOpenTarget || wc == mCloseTarget - || wc.hasChild(mOpenTarget) || wc.hasChild(mCloseTarget); + || mOpenTarget.hasChild(wc) || mCloseTarget.hasChild(wc); } /** @@ -1142,6 +1158,11 @@ class BackNavigationController { private static void setLaunchBehind(@NonNull ActivityRecord activity) { if (!activity.isVisibleRequested()) { activity.setVisibility(true); + // The transition could commit the visibility and in the finishing state, that could + // skip commitVisibility call in setVisibility cause the activity won't visible here. + // Call it again to make sure the activity could be visible while handling the pending + // animation. + activity.commitVisibility(true, true); } activity.mLaunchTaskBehind = true; diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index 13a1cb6daf38..8660becf56a9 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -126,6 +126,9 @@ class Dimmer { boolean isVisible; SurfaceAnimator mSurfaceAnimator; + // TODO(b/64816140): Remove after confirming dimmer layer always matches its container. + final Rect mDimBounds = new Rect(); + /** * Determines whether the dim layer should animate before destroying. */ @@ -262,11 +265,19 @@ class Dimmer { * a chance to request dims to continue. */ void resetDimStates() { - if (mDimState != null && !mDimState.mDontReset) { + if (mDimState == null) { + return; + } + if (!mDimState.mDontReset) { mDimState.mDimming = false; } } + /** Returns non-null bounds if the dimmer is showing. */ + Rect getDimBounds() { + return mDimState != null ? mDimState.mDimBounds : null; + } + void dontAnimateExit() { if (mDimState != null) { mDimState.mAnimateExit = false; @@ -275,13 +286,13 @@ class Dimmer { /** * Call after invoking {@link WindowContainer#prepareSurfaces} on children as - * described in {@link #resetDimStates}. + * described in {@link #resetDimStates}. The dim bounds returned by {@link #resetDimStates} + * should be set before calling this method. * * @param t A transaction in which to update the dims. - * @param bounds The bounds at which to dim. * @return true if any Dims were updated. */ - boolean updateDims(SurfaceControl.Transaction t, Rect bounds) { + boolean updateDims(SurfaceControl.Transaction t) { if (mDimState == null) { return false; } @@ -297,6 +308,7 @@ class Dimmer { mDimState = null; return false; } else { + final Rect bounds = mDimState.mDimBounds; // TODO: Once we use geometry from hierarchy this falls away. t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top); t.setWindowCrop(mDimState.mDimLayer, bounds.width(), bounds.height()); diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 00299c286b08..9f59f5a30caf 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -767,7 +767,6 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { */ static class Dimmable extends DisplayArea<DisplayArea> { private final Dimmer mDimmer = new Dimmer(this); - private final Rect mTmpDimBoundsRect = new Rect(); Dimmable(WindowManagerService wms, Type type, String name, int featureId) { super(wms, type, name, featureId); @@ -782,9 +781,12 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { void prepareSurfaces() { mDimmer.resetDimStates(); super.prepareSurfaces(); - // Bounds need to be relative, as the dim layer is a child. - getBounds(mTmpDimBoundsRect); - mTmpDimBoundsRect.offsetTo(0 /* newLeft */, 0 /* newTop */); + final Rect dimBounds = mDimmer.getDimBounds(); + if (dimBounds != null) { + // Bounds need to be relative, as the dim layer is a child. + getBounds(dimBounds); + dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */); + } // If SystemUI is dragging for recents, we want to reset the dim state so any dim layer // on the display level fades out. @@ -792,8 +794,10 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { mDimmer.resetDimStates(); } - if (mDimmer.updateDims(getSyncTransaction(), mTmpDimBoundsRect)) { - scheduleAnimation(); + if (dimBounds != null) { + if (mDimmer.updateDims(getSyncTransaction())) { + scheduleAnimation(); + } } } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index bec58b848478..c2bc4591ce0d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -775,6 +775,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ DisplayWindowPolicyControllerHelper mDwpcHelper; + private final DisplayRotationReversionController mRotationReversionController; + private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> { WindowStateAnimator winAnimator = w.mWinAnimator; final ActivityRecord activity = w.mActivityRecord; @@ -1204,6 +1206,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mWmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabled( /* checkDeviceConfig */ false) ? new DisplayRotationCompatPolicy(this) : null; + mRotationReversionController = new DisplayRotationReversionController(this); mInputMonitor = new InputMonitor(mWmService, this); mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this); @@ -1333,6 +1336,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp .show(mA11yOverlayLayer); } + DisplayRotationReversionController getRotationReversionController() { + return mRotationReversionController; + } + boolean isReady() { // The display is ready when the system and the individual display are both ready. return mWmService.mDisplayReady && mDisplayReady; @@ -1711,9 +1718,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } private boolean updateOrientation(boolean forceUpdate) { + final WindowContainer prevOrientationSource = mLastOrientationSource; final int orientation = getOrientation(); // The last orientation source is valid only after getOrientation. final WindowContainer orientationSource = getLastOrientationSource(); + if (orientationSource != prevOrientationSource + && mRotationReversionController.isRotationReversionEnabled()) { + mRotationReversionController.updateForNoSensorOverride(); + } final ActivityRecord r = orientationSource != null ? orientationSource.asActivityRecord() : null; if (r != null) { diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 628f4d3a85d6..20048ce543f3 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -33,6 +33,9 @@ import static com.android.server.wm.DisplayRotationProto.IS_FIXED_TO_USER_ROTATI import static com.android.server.wm.DisplayRotationProto.LAST_ORIENTATION; import static com.android.server.wm.DisplayRotationProto.ROTATION; import static com.android.server.wm.DisplayRotationProto.USER_ROTATION; +import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_CAMERA_COMPAT; +import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_HALF_FOLD; +import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_NOSENSOR; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE; @@ -97,6 +100,8 @@ public class DisplayRotation { // config changes and unexpected jumps while folding the device to closed state. private static final int FOLDING_RECOMPUTE_CONFIG_DELAY_MS = 800; + private static final int ROTATION_UNDEFINED = -1; + private static class RotationAnimationPair { @AnimRes int mEnter; @@ -104,6 +109,9 @@ public class DisplayRotation { int mExit; } + @Nullable + final FoldController mFoldController; + private final WindowManagerService mService; private final DisplayContent mDisplayContent; private final DisplayPolicy mDisplayPolicy; @@ -125,8 +133,6 @@ public class DisplayRotation { private OrientationListener mOrientationListener; private StatusBarManagerInternal mStatusBarManagerInternal; private SettingsObserver mSettingsObserver; - @Nullable - private FoldController mFoldController; @NonNull private final DeviceStateController mDeviceStateController; @NonNull @@ -189,6 +195,12 @@ public class DisplayRotation { */ private int mShowRotationSuggestions; + /** + * The most recent {@link Surface.Rotation} choice shown to the user for confirmation, or + * {@link #ROTATION_UNDEFINED} + */ + private int mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; + private static final int ALLOW_ALL_ROTATIONS_UNDEFINED = -1; private static final int ALLOW_ALL_ROTATIONS_DISABLED = 0; private static final int ALLOW_ALL_ROTATIONS_ENABLED = 1; @@ -291,7 +303,11 @@ public class DisplayRotation { if (mSupportAutoRotation && mContext.getResources().getBoolean( R.bool.config_windowManagerHalfFoldAutoRotateOverride)) { mFoldController = new FoldController(); + } else { + mFoldController = null; } + } else { + mFoldController = null; } } @@ -349,6 +365,11 @@ public class DisplayRotation { return -1; } + @VisibleForTesting + boolean useDefaultSettingsProvider() { + return isDefaultDisplay; + } + /** * Updates the configuration which may have different values depending on current user, e.g. * runtime resource overlay. @@ -894,7 +915,8 @@ public class DisplayRotation { @VisibleForTesting void setUserRotation(int userRotationMode, int userRotation) { - if (isDefaultDisplay) { + mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; + if (useDefaultSettingsProvider()) { // We'll be notified via settings listener, so we don't need to update internal values. final ContentResolver res = mContext.getContentResolver(); final int accelerometerRotation = @@ -1613,6 +1635,17 @@ public class DisplayRotation { } } + /** + * Called from {@link ActivityRecord#setRequestedOrientation(int)} + */ + void onSetRequestedOrientation() { + if (mCompatPolicyForImmersiveApps == null + || mRotationChoiceShownToUserForConfirmation == ROTATION_UNDEFINED) { + return; + } + mOrientationListener.onProposedRotationChanged(mRotationChoiceShownToUserForConfirmation); + } + void dump(String prefix, PrintWriter pw) { pw.println(prefix + "DisplayRotation"); pw.println(prefix + " mCurrentAppOrientation=" @@ -1839,7 +1872,7 @@ public class DisplayRotation { return false; } if (mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) { - return !(isTabletop ^ mTabletopRotations.contains(mRotation)); + return isTabletop == mTabletopRotations.contains(mRotation); } return true; } @@ -1863,14 +1896,17 @@ public class DisplayRotation { return mDeviceState == DeviceStateController.DeviceState.OPEN && !mShouldIgnoreSensorRotation // Ignore if the hinge angle still moving && mInHalfFoldTransition - && mHalfFoldSavedRotation != -1 // Ignore if we've already reverted. + && mDisplayContent.getRotationReversionController().isOverrideActive( + REVERSION_TYPE_HALF_FOLD) && mUserRotationMode - == WindowManagerPolicy.USER_ROTATION_LOCKED; // Ignore if we're unlocked. + == WindowManagerPolicy.USER_ROTATION_LOCKED; // Ignore if we're unlocked. } int revertOverriddenRotation() { int savedRotation = mHalfFoldSavedRotation; mHalfFoldSavedRotation = -1; + mDisplayContent.getRotationReversionController() + .revertOverride(REVERSION_TYPE_HALF_FOLD); mInHalfFoldTransition = false; return savedRotation; } @@ -1890,6 +1926,8 @@ public class DisplayRotation { && mDeviceState != DeviceStateController.DeviceState.HALF_FOLDED) { // The device has transitioned to HALF_FOLDED state: save the current rotation and // update the device rotation. + mDisplayContent.getRotationReversionController().beforeOverrideApplied( + REVERSION_TYPE_HALF_FOLD); mHalfFoldSavedRotation = mRotation; mDeviceState = newState; // Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will @@ -2012,9 +2050,11 @@ public class DisplayRotation { mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); dispatchProposedRotation(rotation); if (isRotationChoiceAllowed(rotation)) { + mRotationChoiceShownToUserForConfirmation = rotation; final boolean isValid = isValidRotationChoice(rotation); sendProposedRotationChangeToStatusBarInternal(rotation, isValid); } else { + mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; mService.updateRotation(false /* alwaysSendConfiguration */, false /* forceRelayout */); } @@ -2093,6 +2133,8 @@ public class DisplayRotation { final int mHalfFoldSavedRotation; final boolean mInHalfFoldTransition; final DeviceStateController.DeviceState mDeviceState; + @Nullable final boolean[] mRotationReversionSlots; + @Nullable final String mDisplayRotationCompatPolicySummary; Record(DisplayRotation dr, int fromRotation, int toRotation) { @@ -2133,6 +2175,8 @@ public class DisplayRotation { ? null : dc.mDisplayRotationCompatPolicy .getSummaryForDisplayRotationHistoryRecord(); + mRotationReversionSlots = + dr.mDisplayContent.getRotationReversionController().getSlotsCopy(); } void dump(String prefix, PrintWriter pw) { @@ -2158,6 +2202,12 @@ public class DisplayRotation { if (mDisplayRotationCompatPolicySummary != null) { pw.println(prefix + mDisplayRotationCompatPolicySummary); } + if (mRotationReversionSlots != null) { + pw.println(prefix + " reversionSlots= NOSENSOR " + + mRotationReversionSlots[REVERSION_TYPE_NOSENSOR] + ", CAMERA " + + mRotationReversionSlots[REVERSION_TYPE_CAMERA_COMPAT] + " HALF_FOLD " + + mRotationReversionSlots[REVERSION_TYPE_HALF_FOLD]); + } } } diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java index fb72d6c6b56d..ae93a9496f7c 100644 --- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java @@ -33,6 +33,7 @@ import static android.view.Display.TYPE_INTERNAL; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; +import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_CAMERA_COMPAT; import android.annotation.NonNull; import android.annotation.Nullable; @@ -156,6 +157,11 @@ final class DisplayRotationCompatPolicy { @ScreenOrientation int getOrientation() { mLastReportedOrientation = getOrientationInternal(); + if (mLastReportedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { + rememberOverriddenOrientationIfNeeded(); + } else { + restoreOverriddenOrientationIfNeeded(); + } return mLastReportedOrientation; } @@ -277,6 +283,34 @@ final class DisplayRotationCompatPolicy { + " }"; } + private void restoreOverriddenOrientationIfNeeded() { + if (!isOrientationOverridden()) { + return; + } + if (mDisplayContent.getRotationReversionController().revertOverride( + REVERSION_TYPE_CAMERA_COMPAT)) { + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Reverting orientation after camera compat force rotation"); + // Reset last orientation source since we have reverted the orientation. + mDisplayContent.mLastOrientationSource = null; + } + } + + private boolean isOrientationOverridden() { + return mDisplayContent.getRotationReversionController().isOverrideActive( + REVERSION_TYPE_CAMERA_COMPAT); + } + + private void rememberOverriddenOrientationIfNeeded() { + if (!isOrientationOverridden()) { + mDisplayContent.getRotationReversionController().beforeOverrideApplied( + REVERSION_TYPE_CAMERA_COMPAT); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Saving original orientation before camera compat, last orientation is %d", + mDisplayContent.getLastOrientation()); + } + } + // Refreshing only when configuration changes after rotation. private boolean shouldRefreshActivity(ActivityRecord activity, Configuration newConfig, Configuration lastReportedConfig) { diff --git a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java new file mode 100644 index 000000000000..d3a8a82f8f87 --- /dev/null +++ b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java @@ -0,0 +1,148 @@ +/* + * 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.wm; + +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; + +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; + +import android.annotation.Nullable; +import android.app.WindowConfiguration; +import android.content.ActivityInfoProto; +import android.view.Surface; + +import com.android.internal.protolog.common.ProtoLog; +import com.android.server.policy.WindowManagerPolicy; + +/** + * Defines the behavior of reversion from device rotation overrides. + * + * <p>There are 3 override types: + * <ol> + * <li>The top application has {@link SCREEN_ORIENTATION_NOSENSOR} set and is rotated to + * {@link ROTATION_0}. + * <li>Camera compat treatment has rotated the app {@link DisplayRotationCompatPolicy}. + * <li>The device is half-folded and has auto-rotate is temporarily enabled. + * </ol> + * + * <p>Before an override is enabled, a component should call {@code beforeOverrideApplied}. When + * it wishes to revert, it should call {@code revertOverride}. The user rotation will be restored + * if there are no other overrides present. + */ +final class DisplayRotationReversionController { + + static final int REVERSION_TYPE_NOSENSOR = 0; + static final int REVERSION_TYPE_CAMERA_COMPAT = 1; + static final int REVERSION_TYPE_HALF_FOLD = 2; + private static final int NUM_SLOTS = 3; + + @Surface.Rotation + private int mUserRotationOverridden = WindowConfiguration.ROTATION_UNDEFINED; + @WindowManagerPolicy.UserRotationMode + private int mUserRotationModeOverridden; + + private final boolean[] mSlots = new boolean[NUM_SLOTS]; + private final DisplayContent mDisplayContent; + + DisplayRotationReversionController(DisplayContent content) { + mDisplayContent = content; + } + + boolean isRotationReversionEnabled() { + return mDisplayContent.mDisplayRotationCompatPolicy != null + || mDisplayContent.getDisplayRotation().mFoldController != null + || mDisplayContent.getIgnoreOrientationRequest(); + } + + void beforeOverrideApplied(int slotIndex) { + if (mSlots[slotIndex]) return; + maybeSaveUserRotation(); + mSlots[slotIndex] = true; + } + + boolean isOverrideActive(int slotIndex) { + return mSlots[slotIndex]; + } + + @Nullable + boolean[] getSlotsCopy() { + return isRotationReversionEnabled() ? mSlots.clone() : null; + } + + void updateForNoSensorOverride() { + if (!mSlots[REVERSION_TYPE_NOSENSOR]) { + if (isTopFullscreenActivityNoSensor()) { + ProtoLog.v(WM_DEBUG_ORIENTATION, "NOSENSOR override detected"); + beforeOverrideApplied(REVERSION_TYPE_NOSENSOR); + } + } else { + if (!isTopFullscreenActivityNoSensor()) { + ProtoLog.v(WM_DEBUG_ORIENTATION, "NOSENSOR override is absent: reverting"); + revertOverride(REVERSION_TYPE_NOSENSOR); + } + } + } + + boolean isAnyOverrideActive() { + for (int i = 0; i < NUM_SLOTS; ++i) { + if (mSlots[i]) { + return true; + } + } + return false; + } + + boolean revertOverride(int slotIndex) { + if (!mSlots[slotIndex]) return false; + mSlots[slotIndex] = false; + if (isAnyOverrideActive()) { + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Other orientation overrides are in place: not reverting"); + return false; + } + // Only override if the rotation is frozen and there are no other active slots. + if (mDisplayContent.getDisplayRotation().isRotationFrozen()) { + mDisplayContent.getDisplayRotation().setUserRotation( + mUserRotationModeOverridden, + mUserRotationOverridden); + return true; + } else { + return false; + } + } + + private void maybeSaveUserRotation() { + if (!isAnyOverrideActive()) { + mUserRotationModeOverridden = + mDisplayContent.getDisplayRotation().getUserRotationMode(); + mUserRotationOverridden = mDisplayContent.getDisplayRotation().getUserRotation(); + } + } + + private boolean isTopFullscreenActivityNoSensor() { + final Task topFullscreenTask = + mDisplayContent.getTask( + t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + if (topFullscreenTask != null) { + final ActivityRecord topActivity = + topFullscreenTask.topRunningActivity(); + return topActivity != null && topActivity.getOrientation() + == ActivityInfoProto.SCREEN_ORIENTATION_NOSENSOR; + } + return false; + } +} diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java index bb50372ba019..bf511adf0bf9 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java +++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java @@ -263,8 +263,8 @@ class LaunchParamsPersister { boolean changed = !Objects.equals(params.mDisplayUniqueId, info.uniqueId); params.mDisplayUniqueId = info.uniqueId; - changed |= params.mWindowingMode != task.getTaskDisplayArea().getWindowingMode(); - params.mWindowingMode = task.getTaskDisplayArea().getWindowingMode(); + changed |= params.mWindowingMode != task.getWindowingMode(); + params.mWindowingMode = task.getWindowingMode(); if (task.mLastNonFullscreenBounds != null) { changed |= !Objects.equals(params.mBounds, task.mLastNonFullscreenBounds); diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 93233dd4bda8..ff1deaf415b3 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -1597,11 +1597,10 @@ final class LetterboxUiController { inheritConfiguration(firstOpaqueActivityBeneath); mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation( mActivityRecord, firstOpaqueActivityBeneath, - (opaqueConfig, transparentConfig) -> { - final Configuration mutatedConfiguration = - fromOriginalTranslucentConfig(transparentConfig); + (opaqueConfig, transparentOverrideConfig) -> { + resetTranslucentOverrideConfig(transparentOverrideConfig); final Rect parentBounds = parent.getWindowConfiguration().getBounds(); - final Rect bounds = mutatedConfiguration.windowConfiguration.getBounds(); + final Rect bounds = transparentOverrideConfig.windowConfiguration.getBounds(); final Rect letterboxBounds = opaqueConfig.windowConfiguration.getBounds(); // We cannot use letterboxBounds directly here because the position relies on // letterboxing. Using letterboxBounds directly, would produce a double offset. @@ -1610,9 +1609,9 @@ final class LetterboxUiController { parentBounds.top + letterboxBounds.height()); // We need to initialize appBounds to avoid NPE. The actual value will // be set ahead when resolving the Configuration for the activity. - mutatedConfiguration.windowConfiguration.setAppBounds(new Rect()); + transparentOverrideConfig.windowConfiguration.setAppBounds(new Rect()); inheritConfiguration(firstOpaqueActivityBeneath); - return mutatedConfiguration; + return transparentOverrideConfig; }); } @@ -1691,20 +1690,16 @@ final class LetterboxUiController { true /* traverseTopToBottom */)); } - // When overriding translucent activities configuration we need to keep some of the - // original properties - private Configuration fromOriginalTranslucentConfig(Configuration translucentConfig) { - final Configuration configuration = new Configuration(translucentConfig); + /** Resets the screen size related fields so they can be resolved by requested bounds later. */ + private static void resetTranslucentOverrideConfig(Configuration config) { // The values for the following properties will be defined during the configuration // resolution in {@link ActivityRecord#resolveOverrideConfiguration} using the // properties inherited from the first not finishing opaque activity beneath. - configuration.orientation = ORIENTATION_UNDEFINED; - configuration.screenWidthDp = configuration.compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; - configuration.screenHeightDp = - configuration.compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; - configuration.smallestScreenWidthDp = - configuration.compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; - return configuration; + config.orientation = ORIENTATION_UNDEFINED; + config.screenWidthDp = config.compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; + config.screenHeightDp = config.compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; + config.smallestScreenWidthDp = config.compatSmallestScreenWidthDp = + SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; } private void inheritConfiguration(ActivityRecord firstOpaque) { diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index b38666522754..f5079d37b324 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -338,7 +338,8 @@ class RecentTasks { synchronized (mService.mGlobalLock) { final Task focusedStack = mService.getTopDisplayFocusedRootTask(); final Task topTask = focusedStack != null ? focusedStack.getTopMostTask() : null; - resetFreezeTaskListReordering(topTask); + final Task reorderToEndTask = topTask != null && topTask.hasChild() ? topTask : null; + resetFreezeTaskListReordering(reorderToEndTask); } } @@ -1511,7 +1512,7 @@ class RecentTasks { // callbacks here. final Task removedTask = mTasks.remove(removeIndex); if (removedTask != task) { - if (removedTask.hasChild()) { + if (removedTask.hasChild() && !removedTask.isActivityTypeHome()) { Slog.i(TAG, "Add " + removedTask + " to hidden list because adding " + task); // A non-empty task is replaced by a new task. Because the removed task is no longer // managed by the recent tasks list, add it to the hidden list to prevent the task diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 57fca3aeea79..237846997e9e 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -146,8 +146,6 @@ public class RecentsAnimationController implements DeathRecipient { @VisibleForTesting boolean mIsAddingTaskToTargets; - @VisibleForTesting - boolean mShouldAttachNavBarToAppDuringTransition; private boolean mNavigationBarAttachedToApp; private ActivityRecord mNavBarAttachedApp; @@ -379,8 +377,6 @@ public class RecentsAnimationController implements DeathRecipient { mDisplayId = displayId; mStatusBar = LocalServices.getService(StatusBarManagerInternal.class); mDisplayContent = service.mRoot.getDisplayContent(displayId); - mShouldAttachNavBarToAppDuringTransition = - mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition(); } /** @@ -577,7 +573,7 @@ public class RecentsAnimationController implements DeathRecipient { } private void attachNavigationBarToApp() { - if (!mShouldAttachNavBarToAppDuringTransition + if (!mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition() // Skip the case where the nav bar is controlled by fade rotation. || mDisplayContent.getAsyncRotationController() != null) { return; @@ -652,7 +648,7 @@ public class RecentsAnimationController implements DeathRecipient { } void animateNavigationBarForAppLaunch(long duration) { - if (!mShouldAttachNavBarToAppDuringTransition + if (!mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition() // Skip the case where the nav bar is controlled by fade rotation. || mDisplayContent.getAsyncRotationController() != null || mNavigationBarAttachedToApp diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 07daa4b22ac9..cd4b3c565a41 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2328,19 +2328,23 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // this as a signal to the transition-player. final Transition transition = new Transition(TRANSIT_SLEEP, 0 /* flags */, display.mTransitionController, mWmService.mSyncEngine); - final Runnable sendSleepTransition = () -> { + final TransitionController.OnStartCollect sendSleepTransition = (deferred) -> { display.mTransitionController.requestStartTransition(transition, null /* trigger */, null /* remote */, null /* display */); // Force playing immediately so that unrelated ops can't be collected. transition.playNow(); }; - if (display.mTransitionController.isCollecting()) { - mWmService.mSyncEngine.queueSyncSet( - () -> display.mTransitionController.moveToCollecting(transition), - sendSleepTransition); - } else { + if (!display.mTransitionController.isCollecting()) { + // Since this bypasses sync, submit directly ignoring whether sync-engine + // is active. + if (mWindowManager.mSyncEngine.hasActiveSync()) { + Slog.w(TAG, "Ongoing sync outside of a transition."); + } display.mTransitionController.moveToCollecting(transition); - sendSleepTransition.run(); + sendSleepTransition.onCollectStarted(false /* deferred */); + } else { + display.mTransitionController.startCollectOrQueue(transition, + sendSleepTransition); } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index db4453297001..9363eb5cefc6 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -188,7 +188,6 @@ import android.window.WindowContainerToken; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; -import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledLambda; @@ -481,8 +480,6 @@ class Task extends TaskFragment { // to layout without loading all the task snapshots final PersistedTaskSnapshotData mLastTaskSnapshotData; - private final Rect mTmpDimBoundsRect = new Rect(); - /** @see #setCanAffectSystemUiFlags */ private boolean mCanAffectSystemUiFlags = true; @@ -3008,7 +3005,8 @@ class Task extends TaskFragment { /** Checking if self or its child tasks are animated by recents animation. */ boolean isAnimatingByRecents() { - return isAnimating(CHILDREN, ANIMATION_TYPE_RECENTS); + return isAnimating(CHILDREN, ANIMATION_TYPE_RECENTS) + || mTransitionController.isTransientHide(this); } WindowState getTopVisibleAppMainWindow() { @@ -3256,20 +3254,23 @@ class Task extends TaskFragment { void prepareSurfaces() { mDimmer.resetDimStates(); super.prepareSurfaces(); - getDimBounds(mTmpDimBoundsRect); - // Bounds need to be relative, as the dim layer is a child. - if (inFreeformWindowingMode()) { - getBounds(mTmpRect); - mTmpDimBoundsRect.offsetTo(mTmpDimBoundsRect.left - mTmpRect.left, - mTmpDimBoundsRect.top - mTmpRect.top); - } else { - mTmpDimBoundsRect.offsetTo(0, 0); + final Rect dimBounds = mDimmer.getDimBounds(); + if (dimBounds != null) { + getDimBounds(dimBounds); + + // Bounds need to be relative, as the dim layer is a child. + if (inFreeformWindowingMode()) { + getBounds(mTmpRect); + dimBounds.offsetTo(dimBounds.left - mTmpRect.left, dimBounds.top - mTmpRect.top); + } else { + dimBounds.offsetTo(0, 0); + } } final SurfaceControl.Transaction t = getSyncTransaction(); - if (mDimmer.updateDims(t, mTmpDimBoundsRect)) { + if (dimBounds != null && mDimmer.updateDims(t)) { scheduleAnimation(); } @@ -4687,7 +4688,7 @@ class Task extends TaskFragment { if (!isAttached()) { return; } - mTransitionController.collect(this); + mTransitionController.recordTaskOrder(this); final TaskDisplayArea taskDisplayArea = getDisplayArea(); @@ -5631,30 +5632,20 @@ class Task extends TaskFragment { final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */, mTransitionController, mWmService.mSyncEngine); // Guarantee that this gets its own transition by queueing on SyncEngine - if (mWmService.mSyncEngine.hasActiveSync()) { - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - "Creating Pending Move-to-back: %s", transition); - mWmService.mSyncEngine.queueSyncSet( - () -> mTransitionController.moveToCollecting(transition), - () -> { - // Need to check again since this happens later and the system might - // be in a different state. - if (!canMoveTaskToBack(tr)) { - Slog.e(TAG, "Failed to move task to back after saying we could: " - + tr.mTaskId); - transition.abort(); - return; - } - mTransitionController.requestStartTransition(transition, tr, - null /* remoteTransition */, null /* displayChange */); - moveTaskToBackInner(tr); - }); - } else { - mTransitionController.moveToCollecting(transition); - mTransitionController.requestStartTransition(transition, tr, - null /* remoteTransition */, null /* displayChange */); - moveTaskToBackInner(tr); - } + mTransitionController.startCollectOrQueue(transition, + (deferred) -> { + // Need to check again if deferred since the system might + // be in a different state. + if (deferred && !canMoveTaskToBack(tr)) { + Slog.e(TAG, "Failed to move task to back after saying we could: " + + tr.mTaskId); + transition.abort(); + return; + } + mTransitionController.requestStartTransition(transition, tr, + null /* remoteTransition */, null /* displayChange */); + moveTaskToBackInner(tr); + }); } else { // Skip the transition for pinned task. if (!inPinnedWindowingMode()) { @@ -5683,6 +5674,7 @@ class Task extends TaskFragment { // Usually resuming a top activity triggers the next app transition, but nothing's got // resumed in this case, so we need to execute it explicitly. mDisplayContent.executeAppTransition(); + mDisplayContent.setFocusedApp(topActivity); } else { mRootWindowContainer.resumeFocusedTasksTopActivities(); } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 612fc4be70db..311b9a6d2876 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2926,11 +2926,13 @@ class TaskFragment extends WindowContainer<WindowContainer> { mDimmer.resetDimStates(); super.prepareSurfaces(); - // Bounds need to be relative, as the dim layer is a child. - final Rect dimBounds = getBounds(); - dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */); - if (mDimmer.updateDims(getSyncTransaction(), dimBounds)) { - scheduleAnimation(); + final Rect dimBounds = mDimmer.getDimBounds(); + if (dimBounds != null) { + // Bounds need to be relative, as the dim layer is a child. + dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */); + if (mDimmer.updateDims(getSyncTransaction())) { + scheduleAnimation(); + } } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 1fb353476592..76b0e7b82ba6 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -109,7 +109,7 @@ import java.util.function.Predicate; */ class Transition implements BLASTSyncEngine.TransactionReadyListener { private static final String TAG = "Transition"; - private static final String TRACE_NAME_PLAY_TRANSITION = "PlayTransition"; + private static final String TRACE_NAME_PLAY_TRANSITION = "playing"; /** The default package for resources */ private static final String DEFAULT_PACKAGE = "android"; @@ -287,7 +287,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (restoreBelow != null) { final Task transientRootTask = activity.getRootTask(); - // Collect all visible activities which can be occluded by the transient activity to + // Collect all visible tasks which can be occluded by the transient activity to // make sure they are in the participants so their visibilities can be updated when // finishing transition. ((WindowContainer<?>) restoreBelow.getParent()).forAllTasks(t -> { @@ -297,11 +297,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mTransientHideTasks.add(t); } if (t.isLeafTask()) { - t.forAllActivities(r -> { - if (r.isVisibleRequested()) { - collect(r); - } - }); + collect(t); } } return t == restoreBelow; @@ -511,8 +507,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (mParticipants.contains(wc)) return; // Wallpaper is like in a static drawn state unless display may have changes, so exclude // the case to reduce transition latency waiting for the unchanged wallpaper to redraw. - final boolean needSyncDraw = !isWallpaper(wc) || mParticipants.contains(wc.mDisplayContent); - if (needSyncDraw) { + final boolean needSync = (!isWallpaper(wc) || mParticipants.contains(wc.mDisplayContent)) + // Transient-hide may be hidden later, so no need to request redraw. + && !isInTransientHide(wc); + if (needSync) { mSyncEngine.addToSyncSet(mSyncId, wc); } ChangeInfo info = mChanges.get(wc); @@ -521,10 +519,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mChanges.put(wc, info); } mParticipants.add(wc); - if (wc.getDisplayContent() != null && !mTargetDisplays.contains(wc.getDisplayContent())) { - mTargetDisplays.add(wc.getDisplayContent()); - addOnTopTasks(wc.getDisplayContent(), mOnTopTasksStart); - } + recordDisplay(wc.getDisplayContent()); if (info.mShowWallpaper) { // Collect the wallpaper token (for isWallpaper(wc)) so it is part of the sync set. final WindowState wallpaper = @@ -535,6 +530,20 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } + private void recordDisplay(DisplayContent dc) { + if (dc == null || mTargetDisplays.contains(dc)) return; + mTargetDisplays.add(dc); + addOnTopTasks(dc, mOnTopTasksStart); + } + + /** + * Records information about the initial task order. This does NOT collect anything. Call this + * before any ordering changes *could* occur, but it is not known yet if it will occur. + */ + void recordTaskOrder(WindowContainer from) { + recordDisplay(from.getDisplayContent()); + } + /** Adds the top non-alwaysOnTop tasks within `task` to `out`. */ private static void addOnTopTasks(Task task, ArrayList<Task> out) { for (int i = task.getChildCount() - 1; i >= 0; --i) { @@ -870,8 +879,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { */ void finishTransition() { if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER) && mIsPlayerEnabled) { - Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION, - System.identityHashCode(this)); + asyncTraceEnd(System.identityHashCode(this)); } mLogger.mFinishTimeNs = SystemClock.elapsedRealtimeNanos(); mController.mLoggerHandler.post(mLogger::logOnFinish); @@ -892,6 +900,18 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mController.mFinishingTransition = this; if (mTransientHideTasks != null && !mTransientHideTasks.isEmpty()) { + // Record all the now-hiding activities so that they are committed after + // recalculating visibilities. We just use mParticipants because we can and it will + // ensure proper reporting of `isInFinishTransition`. + for (int i = 0; i < mTransientHideTasks.size(); ++i) { + mTransientHideTasks.get(i).forAllActivities(r -> { + // Only check leaf-tasks that were collected + if (!mParticipants.contains(r.getTask())) return; + // Only concern ourselves with anything that can become invisible + if (!r.isVisible()) return; + mParticipants.add(r); + }); + } // The transient hide tasks could be occluded now, e.g. returning to home. So trigger // the update to make the activities in the tasks invisible-requested, then the next // step can continue to commit the visibility. @@ -907,6 +927,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { final WindowContainer<?> participant = mParticipants.valueAt(i); final ActivityRecord ar = participant.asActivityRecord(); if (ar != null) { + final Task task = ar.getTask(); + if (task == null) continue; boolean visibleAtTransitionEnd = mVisibleAtTransitionEndTokens.contains(ar); // We need both the expected visibility AND current requested-visibility to be // false. If it is expected-visible but not currently visible, it means that @@ -925,9 +947,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (commitVisibility) { ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Commit activity becoming invisible: %s", ar); - final Task task = ar.getTask(); - if (task != null && !task.isVisibleRequested() - && mTransientLaunches != null) { + if (mTransientLaunches != null && !task.isVisibleRequested()) { // If transition is transient, then snapshots are taken at end of // transition. mController.mSnapshotController.mTaskSnapshotController @@ -941,7 +961,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { enterAutoPip = true; } } - if (mChanges.get(ar).mVisible != visibleAtTransitionEnd) { + final ChangeInfo changeInfo = mChanges.get(ar); + // Due to transient-hide, there may be some activities here which weren't in the + // transition. + if (changeInfo != null && changeInfo.mVisible != visibleAtTransitionEnd) { // Legacy dispatch relies on this (for now). ar.mEnteringAnimation = visibleAtTransitionEnd; } else if (mTransientLaunches != null && mTransientLaunches.containsKey(ar) @@ -952,8 +975,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // Since transient launches don't automatically take focus, make sure we // synchronize focus since we committed to the launch. - if (ar.isTopRunningActivity()) { - ar.moveFocusableActivityToTop("transitionFinished"); + if (!task.isFocused() && ar.isTopRunningActivity()) { + mController.mAtm.setLastResumedActivityUncheckLocked(ar, + "transitionFinished"); } } continue; @@ -1199,13 +1223,12 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (primaryDisplay.isKeyguardLocked()) { mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED; } - // Check whether the participants were animated from back navigation. - mController.mAtm.mBackNavigationController.onTransactionReady(this); - collectOrderChanges(); // Resolve the animating targets from the participants. mTargets = calculateTargets(mParticipants, mChanges); + // Check whether the participants were animated from back navigation. + mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets); final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction); info.setDebugId(mSyncId); @@ -1322,8 +1345,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mController.getTransitionPlayer().onTransitionReady( mToken, info, transaction, mFinishTransaction); if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) { - Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION, - System.identityHashCode(this)); + asyncTraceBegin(TRACE_NAME_PLAY_TRANSITION, System.identityHashCode(this)); } } catch (RemoteException e) { // If there's an exception when trying to send the mergedTransaction to the @@ -1598,7 +1620,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(" id=" + mSyncId); sb.append(" type=" + transitTypeToString(mType)); - sb.append(" flags=" + mFlags); + sb.append(" flags=0x" + Integer.toHexString(mFlags)); sb.append('}'); return sb.toString(); } @@ -2310,6 +2332,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return isCollecting() && mSyncId >= 0; } + static void asyncTraceBegin(@NonNull String name, int cookie) { + Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_WINDOW_MANAGER, TAG, name, cookie); + } + + static void asyncTraceEnd(int cookie) { + Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_WINDOW_MANAGER, TAG, cookie); + } + @VisibleForTesting static class ChangeInfo { private static final int FLAG_NONE = 0; @@ -2805,7 +2835,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc; SurfaceControl snapshotSurface = wc.makeAnimationLeash() .setName(name) - .setOpaque(true) + .setOpaque(wc.fillsParent()) .setParent(wc.getSurfaceControl()) .setSecure(screenshotBuffer.containsSecureLayers()) .setCallsite("Transition.ScreenshotSync") diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index bcb8c46de5ed..cbb4fe2eaa21 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -37,7 +37,6 @@ import android.os.IRemoteCallback; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; -import android.os.Trace; import android.util.ArrayMap; import android.util.Slog; import android.util.TimeUtils; @@ -334,28 +333,6 @@ class TransitionController { return inCollectingTransition(wc) || inPlayingTransition(wc); } - boolean inRecentsTransition(@NonNull WindowContainer wc) { - for (WindowContainer p = wc; p != null; p = p.getParent()) { - // TODO(b/221417431): replace this with deterministic snapshots - if (mCollectingTransition == null) break; - if ((mCollectingTransition.getFlags() & TRANSIT_FLAG_IS_RECENTS) != 0 - && mCollectingTransition.mParticipants.contains(wc)) { - return true; - } - } - - for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { - for (WindowContainer p = wc; p != null; p = p.getParent()) { - // TODO(b/221417431): replace this with deterministic snapshots - if ((mPlayingTransitions.get(i).getFlags() & TRANSIT_FLAG_IS_RECENTS) != 0 - && mPlayingTransitions.get(i).mParticipants.contains(p)) { - return true; - } - } - } - return false; - } - /** @return {@code true} if wc is in a participant subtree */ boolean isTransitionOnDisplay(@NonNull DisplayContent dc) { if (mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc)) { @@ -466,26 +443,36 @@ 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) { + /** Sets the sync method for the display change. */ + private void setDisplaySyncMethod(@NonNull TransitionRequestInfo.DisplayChange displayChange, + @NonNull Transition displayTransition, @NonNull DisplayContent displayContent) { + final int startRotation = displayChange.getStartRotation(); + final int endRotation = displayChange.getEndRotation(); + if (startRotation != endRotation && (startRotation + endRotation) % 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; + mAtm.mWindowManager.mSyncEngine.setSyncMethod(displayTransition.getSyncId(), + BLASTSyncEngine.METHOD_BLAST); } final Rect startBounds = displayChange.getStartAbsBounds(); final Rect endBounds = displayChange.getEndAbsBounds(); - if (startBounds == null || endBounds == null) return false; + if (startBounds == null || endBounds == null) return; 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 ((endWidth > startWidth) == (endHeight > startHeight) + && (endWidth != startWidth || endHeight != startHeight)) { + displayContent.forAllWindows(w -> { + if (w.mToken.mRoundedCornerOverlay && w.mHasSurface) { + w.mSyncMethodOverride = BLASTSyncEngine.METHOD_BLAST; + } + }, true /* traverseTopToBottom */); + } } /** @@ -517,9 +504,9 @@ class TransitionController { } else { newTransition = requestStartTransition(createTransition(type, flags), trigger != null ? trigger.asTask() : null, remoteTransition, displayChange); - if (newTransition != null && displayChange != null && shouldSync(displayChange)) { - mAtm.mWindowManager.mSyncEngine.setSyncMethod(newTransition.getSyncId(), - BLASTSyncEngine.METHOD_BLAST); + if (newTransition != null && displayChange != null && trigger != null + && trigger.asDisplayContent() != null) { + setDisplaySyncMethod(displayChange, newTransition, trigger.asDisplayContent()); } } if (trigger != null) { @@ -577,12 +564,16 @@ class TransitionController { return transition; } - /** Requests transition for a window container which will be removed or invisible. */ - void requestCloseTransitionIfNeeded(@NonNull WindowContainer<?> wc) { - if (mTransitionPlayer == null) return; + /** + * Requests transition for a window container which will be removed or invisible. + * @return the new transition if it was created for this request, `null` otherwise. + */ + Transition requestCloseTransitionIfNeeded(@NonNull WindowContainer<?> wc) { + if (mTransitionPlayer == null) return null; + Transition out = null; if (wc.isVisibleRequested()) { if (!isCollecting()) { - requestStartTransition(createTransition(TRANSIT_CLOSE, 0 /* flags */), + out = requestStartTransition(createTransition(TRANSIT_CLOSE, 0 /* flags */), wc.asTask(), null /* remoteTransition */, null /* displayChange */); } collectExistenceChange(wc); @@ -591,6 +582,7 @@ class TransitionController { // collecting, this should be a member just in case. collect(wc); } + return out; } /** @see Transition#collect */ @@ -605,6 +597,12 @@ class TransitionController { mCollectingTransition.collectExistenceChange(wc); } + /** @see Transition#recordTaskOrder */ + void recordTaskOrder(@NonNull WindowContainer wc) { + if (mCollectingTransition == null) return; + mCollectingTransition.recordTaskOrder(wc); + } + /** * Collects the window containers which need to be synced with the changing display area into * the current collecting transition. @@ -762,12 +760,12 @@ class TransitionController { // happening in app), so pause task snapshot persisting to not increase the load. mAtm.mWindowManager.mSnapshotController.setPause(true); mAnimatingState = true; - Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "transitAnim", 0); + Transition.asyncTraceBegin("animating", 0x41bfaf1 /* hashcode of TAG */); } else if (!animatingState && mAnimatingState) { t.setEarlyWakeupEnd(); mAtm.mWindowManager.mSnapshotController.setPause(false); mAnimatingState = false; - Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "transitAnim", 0); + Transition.asyncTraceEnd(0x41bfaf1 /* hashcode of TAG */); } } @@ -886,6 +884,32 @@ class TransitionController { proto.end(token); } + /** Returns {@code true} if it started collecting, {@code false} if it was queued. */ + boolean startCollectOrQueue(Transition transit, OnStartCollect onStartCollect) { + if (mAtm.mWindowManager.mSyncEngine.hasActiveSync()) { + if (!isCollecting()) { + Slog.w(TAG, "Ongoing Sync outside of transition."); + } + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, + "Queueing transition: %s", transit); + mAtm.mWindowManager.mSyncEngine.queueSyncSet( + // Make sure to collect immediately to prevent another transition + // from sneaking in before it. Note: moveToCollecting internally + // calls startSyncSet. + () -> moveToCollecting(transit), + () -> onStartCollect.onCollectStarted(true /* deferred */)); + return false; + } else { + moveToCollecting(transit); + onStartCollect.onCollectStarted(false /* deferred */); + return true; + } + } + + interface OnStartCollect { + void onCollectStarted(boolean deferred); + } + /** * This manages the animating state of processes that are running remote animations for * {@link #mTransitionPlayerProc}. diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 41176410a789..cf6efd28acb7 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -4047,7 +4047,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< final Configuration mergedConfiguration = configurationMerger != null ? configurationMerger.merge(mergedOverrideConfig, - receiver.getConfiguration()) + receiver.getRequestedOverrideConfiguration()) : supplier.getConfiguration(); receiver.onRequestedOverrideConfigurationChanged(mergedConfiguration); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index cd4d6e4f1600..8fecf111d98c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6697,9 +6697,8 @@ public class WindowManagerService extends IWindowManager.Stub mInputManagerCallback.dump(pw, " "); mSnapshotController.dump(pw, " "); - if (mAccessibilityController.hasCallbacks()) { - mAccessibilityController.dump(pw, " "); - } + + dumpAccessibilityController(pw, /* force= */ false); if (dumpAll) { final WindowState imeWindow = mRoot.getCurrentInputMethodWindow(); @@ -6736,6 +6735,23 @@ public class WindowManagerService extends IWindowManager.Stub } } + private void dumpAccessibilityController(PrintWriter pw, boolean force) { + boolean hasCallbacks = mAccessibilityController.hasCallbacks(); + if (!hasCallbacks && !force) { + return; + } + if (!hasCallbacks) { + pw.println("AccessibilityController doesn't have callbacks, but printing it anways:"); + } else { + pw.println("AccessibilityController:"); + } + mAccessibilityController.dump(pw, " "); + } + + private void dumpAccessibilityLocked(PrintWriter pw) { + dumpAccessibilityController(pw, /* force= */ true); + } + private boolean dumpWindows(PrintWriter pw, String name, boolean dumpAll) { final ArrayList<WindowState> windows = new ArrayList(); if ("apps".equals(name) || "visible".equals(name) || "visible-apps".equals(name)) { @@ -6855,6 +6871,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(" d[isplays]: active display contents"); pw.println(" t[okens]: token list"); pw.println(" w[indows]: window list"); + pw.println(" a11y[accessibility]: accessibility-related state"); pw.println(" package-config: installed packages having app-specific config"); pw.println(" trace: print trace status and write Winscope trace to file"); pw.println(" cmd may also be a NAME to dump windows. NAME may"); @@ -6918,6 +6935,11 @@ public class WindowManagerService extends IWindowManager.Stub dumpWindowsLocked(pw, true, null); } return; + } else if ("accessibility".equals(cmd) || "a11y".equals(cmd)) { + synchronized (mGlobalLock) { + dumpAccessibilityLocked(pw); + } + return; } else if ("all".equals(cmd)) { synchronized (mGlobalLock) { dumpWindowsLocked(pw, true, null); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 32d54d774b40..ee86b97e9404 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -280,43 +280,31 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub applyTransaction(t, -1 /* syncId */, null, caller); return null; } - // In cases where transition is already provided, the "readiness lifecycle" of the - // transition is determined outside of this transaction. However, if this is a - // direct call from shell, the entire transition lifecycle is contained in the - // provided transaction and thus we can setReady immediately after apply. - final boolean needsSetReady = transition == null && t != null; final WindowContainerTransaction wct = t != null ? t : new WindowContainerTransaction(); if (transition == null) { if (type < 0) { throw new IllegalArgumentException("Can't create transition with no type"); } - // If there is already a collecting transition, queue up a new transition and - // return that. The actual start and apply will then be deferred until that - // transition starts collecting. This should almost never happen except during - // tests. - if (mService.mWindowManager.mSyncEngine.hasActiveSync()) { - Slog.w(TAG, "startTransition() while one is already collecting."); - final Transition nextTransition = new Transition(type, 0 /* flags */, - mTransitionController, mService.mWindowManager.mSyncEngine); - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - "Creating Pending Transition: %s", nextTransition); - mService.mWindowManager.mSyncEngine.queueSyncSet( - // Make sure to collect immediately to prevent another transition - // from sneaking in before it. Note: moveToCollecting internally - // calls startSyncSet. - () -> mTransitionController.moveToCollecting(nextTransition), - () -> { - nextTransition.start(); - applyTransaction(wct, -1 /*syncId*/, nextTransition, caller); - if (needsSetReady) { - nextTransition.setAllReady(); - } - }); - return nextTransition.getToken(); - } - transition = mTransitionController.createTransition(type); + // This is a direct call from shell, so the entire transition lifecycle is + // contained in the provided transaction if provided. Thus, we can setReady + // immediately after apply. + final boolean needsSetReady = t != null; + final Transition nextTransition = new Transition(type, 0 /* flags */, + mTransitionController, mService.mWindowManager.mSyncEngine); + mTransitionController.startCollectOrQueue(nextTransition, + (deferred) -> { + nextTransition.start(); + nextTransition.mLogger.mStartWCT = wct; + applyTransaction(wct, -1 /*syncId*/, nextTransition, caller); + if (needsSetReady) { + nextTransition.setAllReady(); + } + }); + return nextTransition.getToken(); } + // The transition already started collecting before sending a request to shell, + // so just start here. if (!transition.isCollecting() && !transition.isForcePlaying()) { Slog.e(TAG, "Trying to start a transition that isn't collecting. This probably" + " means Shell took too long to respond to a request. WM State may be" @@ -327,9 +315,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub transition.start(); transition.mLogger.mStartWCT = wct; applyTransaction(wct, -1 /*syncId*/, transition, caller); - if (needsSetReady) { - transition.setAllReady(); - } + // Since the transition is already provided, it means WMCore is determining the + // "readiness lifecycle" outside the provided transaction, so don't set ready here. return transition.getToken(); } } finally { @@ -434,23 +421,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return; } - if (!mService.mWindowManager.mSyncEngine.hasActiveSync()) { - // Sync is for either transition or applySyncTransaction(). We don't support - // multiple sync at the same time because it may cause conflict. - // Create a new transition when there is no active sync to collect the changes. - final Transition transition = mTransitionController.createTransition(type); - if (applyTransaction(wct, -1 /* syncId */, transition, caller) - == TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) { - transition.abort(); - return; - } - mTransitionController.requestStartTransition(transition, null /* startTask */, - null /* remoteTransition */, null /* displayChange */); - transition.setAllReady(); - return; - } - - if (!shouldApplyIndependently) { + if (mService.mWindowManager.mSyncEngine.hasActiveSync() + && !shouldApplyIndependently) { // Although there is an active sync, we want to apply the transaction now. // TODO(b/232042367) Redesign the organizer update on activity callback so that we // we will know about the transition explicitly. @@ -469,29 +441,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return; } - // It is ok to queue the WCT until the sync engine is free. - final Transition nextTransition = new Transition(type, 0 /* flags */, + final Transition transition = new Transition(type, 0 /* flags */, mTransitionController, mService.mWindowManager.mSyncEngine); - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - "Creating Pending Transition for TaskFragment: %s", nextTransition); - mService.mWindowManager.mSyncEngine.queueSyncSet( - // Make sure to collect immediately to prevent another transition - // from sneaking in before it. Note: moveToCollecting internally - // calls startSyncSet. - () -> mTransitionController.moveToCollecting(nextTransition), - () -> { - if (mTaskFragmentOrganizerController.isValidTransaction(wct) - && (applyTransaction(wct, -1 /* syncId */, nextTransition, caller) - != TRANSACT_EFFECTS_NONE - || !nextTransition.mParticipants.isEmpty())) { - mTransitionController.requestStartTransition(nextTransition, - null /* startTask */, null /* remoteTransition */, - null /* displayChange */); - nextTransition.setAllReady(); - return; - } - nextTransition.abort(); - }); + TransitionController.OnStartCollect doApply = (deferred) -> { + if (deferred && !mTaskFragmentOrganizerController.isValidTransaction(wct)) { + transition.abort(); + return; + } + if (applyTransaction(wct, -1 /* syncId */, transition, caller) + == TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) { + transition.abort(); + return; + } + mTransitionController.requestStartTransition(transition, null /* startTask */, + null /* remoteTransition */, null /* displayChange */); + transition.setAllReady(); + }; + mTransitionController.startCollectOrQueue(transition, doApply); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 736f489cf99d..e5a49c3a0ee2 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5177,13 +5177,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void prepareSurfaces() { mIsDimming = false; - applyDims(); - updateSurfacePositionNonOrganized(); - // Send information to SurfaceFlinger about the priority of the current window. - updateFrameRateSelectionPriorityIfNeeded(); - updateScaleIfNeeded(); - - mWinAnimator.prepareSurfaceLocked(getSyncTransaction()); + if (mHasSurface) { + applyDims(); + updateSurfacePositionNonOrganized(); + // Send information to SurfaceFlinger about the priority of the current window. + updateFrameRateSelectionPriorityIfNeeded(); + updateScaleIfNeeded(); + mWinAnimator.prepareSurfaceLocked(getSyncTransaction()); + } super.prepareSurfaces(); } @@ -5646,7 +5647,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override boolean isSyncFinished() { - if (!isVisibleRequested()) { + if (!isVisibleRequested() || isFullyTransparent()) { // Don't wait for invisible windows. However, we don't alter the state in case the // window becomes visible while the sync group is still active. return true; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 327483ebbef7..da54b15fd0a4 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -119,24 +119,20 @@ class WindowToken extends WindowContainer<WindowState> { final DisplayInfo mDisplayInfo; final DisplayFrames mDisplayFrames; final Configuration mRotatedOverrideConfiguration; - final SeamlessRotator mRotator; + /** * The tokens that share the same transform. Their end time of transform are the same. The * list should at least contain the token who creates this state. */ final ArrayList<WindowToken> mAssociatedTokens = new ArrayList<>(3); - final ArrayList<WindowContainer<?>> mRotatedContainers = new ArrayList<>(3); + boolean mIsTransforming = true; FixedRotationTransformState(DisplayInfo rotatedDisplayInfo, - DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig, - int currentRotation) { + DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig) { mDisplayInfo = rotatedDisplayInfo; mDisplayFrames = rotatedDisplayFrames; mRotatedOverrideConfiguration = rotatedConfig; - // This will use unrotate as rotate, so the new and old rotation are inverted. - mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation, - rotatedDisplayInfo, true /* applyFixedTransformationHint */); } /** @@ -144,10 +140,8 @@ class WindowToken extends WindowContainer<WindowState> { * showing the window in a display with different rotation. */ void transform(WindowContainer<?> container) { - mRotator.unrotate(container.getPendingTransaction(), container); - if (!mRotatedContainers.contains(container)) { - mRotatedContainers.add(container); - } + // The default implementation assumes shell transition is enabled, so the transform + // is done by getOrCreateFixedRotationLeash(). } /** @@ -155,6 +149,40 @@ class WindowToken extends WindowContainer<WindowState> { * be called when the window has the same rotation as display. */ void resetTransform() { + for (int i = mAssociatedTokens.size() - 1; i >= 0; --i) { + mAssociatedTokens.get(i).removeFixedRotationLeash(); + } + } + + /** The state may not only be used by self. Make sure to leave the influence by others. */ + void disassociate(WindowToken token) { + mAssociatedTokens.remove(token); + } + } + + private static class FixedRotationTransformStateLegacy extends FixedRotationTransformState { + final SeamlessRotator mRotator; + final ArrayList<WindowContainer<?>> mRotatedContainers = new ArrayList<>(3); + + FixedRotationTransformStateLegacy(DisplayInfo rotatedDisplayInfo, + DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig, + int currentRotation) { + super(rotatedDisplayInfo, rotatedDisplayFrames, rotatedConfig); + // This will use unrotate as rotate, so the new and old rotation are inverted. + mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation, + rotatedDisplayInfo, true /* applyFixedTransformationHint */); + } + + @Override + void transform(WindowContainer<?> container) { + mRotator.unrotate(container.getPendingTransaction(), container); + if (!mRotatedContainers.contains(container)) { + mRotatedContainers.add(container); + } + } + + @Override + void resetTransform() { for (int i = mRotatedContainers.size() - 1; i >= 0; i--) { final WindowContainer<?> c = mRotatedContainers.get(i); // If the window is detached (no parent), its surface may have been released. @@ -164,9 +192,9 @@ class WindowToken extends WindowContainer<WindowState> { } } - /** The state may not only be used by self. Make sure to leave the influence by others. */ + @Override void disassociate(WindowToken token) { - mAssociatedTokens.remove(token); + super.disassociate(token); mRotatedContainers.remove(token); } } @@ -437,8 +465,11 @@ class WindowToken extends WindowContainer<WindowState> { if (mFixedRotationTransformState != null) { mFixedRotationTransformState.disassociate(this); } - mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames, - new Configuration(config), mDisplayContent.getRotation()); + config = new Configuration(config); + mFixedRotationTransformState = mTransitionController.isShellTransitionsEnabled() + ? new FixedRotationTransformState(info, displayFrames, config) + : new FixedRotationTransformStateLegacy(info, displayFrames, config, + mDisplayContent.getRotation()); mFixedRotationTransformState.mAssociatedTokens.add(this); mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames); onFixedRotationStatePrepared(); @@ -508,14 +539,7 @@ class WindowToken extends WindowContainer<WindowState> { if (state == null) { return; } - if (!mTransitionController.isShellTransitionsEnabled()) { - state.resetTransform(); - } else { - // Remove all the leashes - for (int i = state.mAssociatedTokens.size() - 1; i >= 0; --i) { - state.mAssociatedTokens.get(i).removeFixedRotationLeash(); - } - } + state.resetTransform(); // Clear the flag so if the display will be updated to the same orientation, the transform // won't take effect. state.mIsTransforming = false; @@ -589,7 +613,9 @@ class WindowToken extends WindowContainer<WindowState> { void removeFixedRotationLeash() { if (mFixedRotationTransformLeash == null) return; final SurfaceControl.Transaction t = getSyncTransaction(); - t.reparent(getSurfaceControl(), getParentSurfaceControl()); + if (mSurfaceControl != null) { + t.reparent(mSurfaceControl, getParentSurfaceControl()); + } t.remove(mFixedRotationTransformLeash); mFixedRotationTransformLeash = null; } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 1510bd037a54..439ad76ced22 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1300,17 +1300,17 @@ bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t JNIEnv* env = jniEnv(); switch (inputEvent->getType()) { - case AINPUT_EVENT_TYPE_KEY: - inputEventObj = android_view_KeyEvent_fromNative(env, - static_cast<const KeyEvent*>(inputEvent)); - break; - case AINPUT_EVENT_TYPE_MOTION: - inputEventObj = - android_view_MotionEvent_obtainAsCopy(env, - static_cast<const MotionEvent&>(*inputEvent)); - break; - default: - return true; // dispatch the event normally + case InputEventType::KEY: + inputEventObj = + android_view_KeyEvent_fromNative(env, static_cast<const KeyEvent*>(inputEvent)); + break; + case InputEventType::MOTION: + inputEventObj = android_view_MotionEvent_obtainAsCopy(env, + static_cast<const MotionEvent&>( + *inputEvent)); + break; + default: + return true; // dispatch the event normally } if (!inputEventObj) { diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java index bbebbf2383f5..19a0c5e8adcb 100644 --- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java @@ -27,9 +27,10 @@ import android.credentials.ui.RequestInfo; import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; -import android.util.Log; +import android.util.Slog; import java.util.ArrayList; +import java.util.Set; /** * Central session for a single clearCredentialState request. This class listens to the @@ -43,11 +44,12 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta public ClearRequestSession(Context context, RequestSession.SessionLifetime sessionCallback, Object lock, int userId, int callingUid, IClearCredentialStateCallback callback, ClearCredentialStateRequest request, - CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal, + CallingAppInfo callingAppInfo, Set<ComponentName> enabledProviders, + CancellationSignal cancellationSignal, long startedTimestamp) { super(context, sessionCallback, lock, userId, callingUid, request, callback, RequestInfo.TYPE_UNDEFINED, - callingAppInfo, cancellationSignal, startedTimestamp); + callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp); } /** @@ -65,7 +67,8 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta .createNewSession(mContext, mUserId, providerInfo, this, remoteCredentialService); if (providerClearSession != null) { - Log.i(TAG, "In startProviderSession - provider session created and being added"); + Slog.d(TAG, "In startProviderSession - provider session created " + + "and being added for: " + providerInfo.getComponentName()); mProviders.put(providerClearSession.getComponentName().flattenToString(), providerClearSession); } @@ -75,12 +78,12 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta @Override // from provider session public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName, ProviderSession.CredentialsSource source) { - Log.i(TAG, "in onStatusChanged with status: " + status); + Slog.d(TAG, "in onStatusChanged with status: " + status + ", and source: " + source); if (ProviderSession.isTerminatingStatus(status)) { - Log.i(TAG, "in onStatusChanged terminating status"); + Slog.d(TAG, "in onProviderStatusChanged terminating status"); onProviderTerminated(componentName); } else if (ProviderSession.isCompletionStatus(status)) { - Log.i(TAG, "in onStatusChanged isCompletionStatus status"); + Slog.d(TAG, "in onProviderStatusChanged isCompletionStatus status"); onProviderResponseComplete(componentName); } } diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 4c456a88b00b..fc7fd1afe58f 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -33,11 +33,12 @@ import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; import android.service.credentials.PermissionUtils; -import android.util.Log; +import android.util.Slog; import com.android.server.credentials.metrics.ProviderStatusForMetrics; import java.util.ArrayList; +import java.util.Set; /** * Central session for a single {@link CredentialManager#createCredential} request. @@ -54,11 +55,14 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR CreateCredentialRequest request, ICreateCredentialCallback callback, CallingAppInfo callingAppInfo, + Set<ComponentName> enabledProviders, CancellationSignal cancellationSignal, long startedTimestamp) { super(context, sessionCallback, lock, userId, callingUid, request, callback, RequestInfo.TYPE_CREATE, - callingAppInfo, cancellationSignal, startedTimestamp); + callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp); + mRequestSessionMetric.collectCreateFlowInitialMetricInfo( + /*origin=*/request.getOrigin() != null); } /** @@ -75,7 +79,8 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR .createNewSession(mContext, mUserId, providerInfo, this, remoteCredentialService); if (providerCreateSession != null) { - Log.i(TAG, "In startProviderSession - provider session created and being added"); + Slog.d(TAG, "In initiateProviderSession - provider session created and " + + "being added for: " + providerInfo.getComponentName()); mProviders.put(providerCreateSession.getComponentName().flattenToString(), providerCreateSession); } @@ -86,14 +91,16 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { mRequestSessionMetric.collectUiCallStartTime(System.nanoTime()); mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION); + cancelExistingPendingIntent(); try { - mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent( + mPendingIntent = mCredentialManagerUi.createPendingIntent( RequestInfo.newCreateRequestInfo( mRequestId, mClientRequest, mClientAppInfo.getPackageName(), PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(), Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS)), - providerDataList)); + providerDataList); + mClientCallback.onPendingIntent(mPendingIntent); } catch (RemoteException e) { mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED); @@ -118,7 +125,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR @Override public void onFinalResponseReceived(ComponentName componentName, @Nullable CreateCredentialResponse response) { - Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString()); + Slog.d(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString()); mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime()); mRequestSessionMetric.collectChosenMetricViaCandidateTransfer(mProviders.get( componentName.flattenToString()).mProviderSessionMetric @@ -161,13 +168,13 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR @Override public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName, ProviderSession.CredentialsSource source) { - Log.i(TAG, "in onProviderStatusChanged with status: " + status); + Slog.d(TAG, "in onStatusChanged with status: " + status + ", and source: " + source); // 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 (!isAnyProviderPending()) { if (isUiInvocationNeeded()) { - Log.i(TAG, "in onProviderStatusChanged - isUiInvocationNeeded"); + Slog.d(TAG, "in onProviderStatusChanged - isUiInvocationNeeded"); getProviderDataAndInitiateUi(); } else { respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS, diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 90f30b567023..06b96eb46ac1 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -458,6 +458,7 @@ public final class CredentialManagerService callback, request, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), + getEnabledProviders(), CancellationSignal.fromTransport(cancelTransport), timestampBegan); addSessionLocked(userId, session); @@ -512,6 +513,7 @@ public final class CredentialManagerService getCredentialCallback, request, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), + getEnabledProviders(), CancellationSignal.fromTransport(cancelTransport), timestampBegan, prepareGetCredentialCallback); @@ -629,6 +631,7 @@ public final class CredentialManagerService request, callback, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), + getEnabledProviders(), CancellationSignal.fromTransport(cancelTransport), timestampBegan); addSessionLocked(userId, session); @@ -793,7 +796,7 @@ public final class CredentialManagerService return DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER, - false); + true); } finally { Binder.restoreCallingIdentity(origId); } @@ -846,6 +849,7 @@ public final class CredentialManagerService callback, request, constructCallingAppInfo(callingPackage, userId, null), + getEnabledProviders(), CancellationSignal.fromTransport(cancelTransport), timestampBegan); addSessionLocked(userId, session); diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java index e16d48e0a680..0dee7a44375d 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java @@ -20,7 +20,6 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ServiceInfo; import android.credentials.CredentialManager; import android.credentials.CredentialProviderInfo; import android.credentials.ui.DisabledProviderData; @@ -34,38 +33,35 @@ import android.os.IBinder; import android.os.Looper; import android.os.ResultReceiver; import android.service.credentials.CredentialProviderInfoFactory; -import android.util.Log; import android.util.Slog; import java.util.ArrayList; -import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; /** Initiates the Credential Manager UI and receives results. */ public class CredentialManagerUi { private static final String TAG = "CredentialManagerUi"; @NonNull private final CredentialManagerUiCallback mCallbacks; - @NonNull private final Context mContext; + @NonNull + private final Context mContext; // TODO : Use for starting the activity for this user private final int mUserId; private UiStatus mStatus; - /** Creates intent that is ot be invoked to cancel an in-progress UI session. */ - public Intent createCancelIntent(IBinder requestId, String packageName) { - return IntentFactory.createCancelUiIntent(requestId, /*shouldShowCancellationUi=*/ true, - packageName); - } + private final Set<ComponentName> mEnabledProviders; enum UiStatus { IN_PROGRESS, USER_INTERACTION, NOT_STARTED, TERMINATED } - @NonNull private final ResultReceiver mResultReceiver = new ResultReceiver( + + @NonNull + private final ResultReceiver mResultReceiver = new ResultReceiver( new Handler(Looper.getMainLooper())) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { @@ -105,24 +101,32 @@ public class CredentialManagerUi { } } + /** Creates intent that is ot be invoked to cancel an in-progress UI session. */ + public Intent createCancelIntent(IBinder requestId, String packageName) { + return IntentFactory.createCancelUiIntent(requestId, /*shouldShowCancellationUi=*/ true, + packageName); + } + /** * Interface to be implemented by any class that wishes to get callbacks from the UI. */ public interface CredentialManagerUiCallback { /** Called when the user makes a selection. */ void onUiSelection(UserSelectionDialogResult selection); + /** Called when the UI is canceled without a successful provider result. */ void onUiCancellation(boolean isUserCancellation); /** Called when the selector UI fails to come up (mostly due to parsing issue today). */ void onUiSelectorInvocationFailure(); } + public CredentialManagerUi(Context context, int userId, - CredentialManagerUiCallback callbacks) { - Log.i(TAG, "In CredentialManagerUi constructor"); + CredentialManagerUiCallback callbacks, Set<ComponentName> enabledProviders) { mContext = context; mUserId = userId; mCallbacks = callbacks; + mEnabledProviders = enabledProviders; mStatus = UiStatus.IN_PROGRESS; } @@ -139,37 +143,26 @@ public class CredentialManagerUi { /** * Creates a {@link PendingIntent} to be used to invoke the credential manager selector UI, * by the calling app process. - * @param requestInfo the information about the request + * + * @param requestInfo the information about the request * @param providerDataList the list of provider data from remote providers */ public PendingIntent createPendingIntent( RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) { - Log.i(TAG, "In createPendingIntent"); - - ArrayList<DisabledProviderData> disabledProviderDataList = new ArrayList<>(); - Set<String> enabledProviders = providerDataList.stream() - .map(ProviderData::getProviderFlattenedComponentName) - .collect(Collectors.toUnmodifiableSet()); - Set<String> allProviders = + List<CredentialProviderInfo> allProviders = CredentialProviderInfoFactory.getCredentialProviderServices( - mContext, - mUserId, - CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY, - new HashSet<>()) - .stream() - .map(CredentialProviderInfo::getServiceInfo) - .map(ServiceInfo::getComponentName) - .map(ComponentName::flattenToString) - .collect(Collectors.toUnmodifiableSet()); - - for (String provider: allProviders) { - if (!enabledProviders.contains(provider)) { - disabledProviderDataList.add(new DisabledProviderData(provider)); - } - } + mContext, + mUserId, + CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY, + mEnabledProviders); + + List<DisabledProviderData> disabledProviderDataList = allProviders.stream() + .filter(provider -> !provider.isEnabled()) + .map(disabledProvider -> new DisabledProviderData( + disabledProvider.getComponentName().flattenToString())).toList(); Intent intent = IntentFactory.createCredentialSelectorIntent(requestInfo, providerDataList, - disabledProviderDataList, mResultReceiver) + new ArrayList<>(disabledProviderDataList), mResultReceiver) .setAction(UUID.randomUUID().toString()); //TODO: Create unique pending intent using request code and cancel any pre-existing pending // intents diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index 2548bd888b9d..f39de43b5076 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -30,11 +30,12 @@ import android.credentials.ui.RequestInfo; import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; -import android.util.Log; +import android.util.Slog; import com.android.server.credentials.metrics.ProviderStatusForMetrics; import java.util.ArrayList; +import java.util.Set; import java.util.stream.Collectors; /** @@ -45,22 +46,27 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, IGetCredentialCallback, GetCredentialResponse> implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> { private static final String TAG = "GetRequestSession"; + public GetRequestSession(Context context, RequestSession.SessionLifetime sessionCallback, Object lock, int userId, int callingUid, IGetCredentialCallback callback, GetCredentialRequest request, - CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal, + CallingAppInfo callingAppInfo, Set<ComponentName> enabledProviders, + CancellationSignal cancellationSignal, long startedTimestamp) { super(context, sessionCallback, lock, userId, callingUid, request, callback, - RequestInfo.TYPE_GET, callingAppInfo, cancellationSignal, startedTimestamp); + RequestInfo.TYPE_GET, callingAppInfo, enabledProviders, cancellationSignal, + startedTimestamp); int numTypes = (request.getCredentialOptions().stream() .map(CredentialOption::getType).collect( - Collectors.toSet())).size(); // Dedupe type strings - mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes); + Collectors.toSet())).size(); // Dedupe type strings + mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes, + /*origin=*/request.getOrigin() != null); } /** * 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. */ @@ -72,7 +78,8 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, .createNewSession(mContext, mUserId, providerInfo, this, remoteCredentialService); if (providerGetSession != null) { - Log.i(TAG, "In startProviderSession - provider session created and being added"); + Slog.d(TAG, "In startProviderSession - provider session created and " + + "being added for: " + providerInfo.getComponentName()); mProviders.put(providerGetSession.getComponentName().flattenToString(), providerGetSession); } @@ -83,11 +90,13 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { mRequestSessionMetric.collectUiCallStartTime(System.nanoTime()); mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION); + cancelExistingPendingIntent(); try { - mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent( + mPendingIntent = mCredentialManagerUi.createPendingIntent( RequestInfo.newGetRequestInfo( mRequestId, mClientRequest, mClientAppInfo.getPackageName()), - providerDataList)); + providerDataList); + mClientCallback.onPendingIntent(mPendingIntent); } catch (RemoteException e) { mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED); @@ -111,7 +120,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, @Override public void onFinalResponseReceived(ComponentName componentName, @Nullable GetCredentialResponse response) { - Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString()); + Slog.d(TAG, "onFinalResponseReceived from: " + componentName.flattenToString()); mRequestSessionMetric.collectUiResponseData(/*uiReturned=*/ true, System.nanoTime()); mRequestSessionMetric.collectChosenMetricViaCandidateTransfer( mProviders.get(componentName.flattenToString()) @@ -149,13 +158,14 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, @Override public void onUiSelectorInvocationFailure() { respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, - "No credentials available."); + "No credentials available."); } @Override public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName, ProviderSession.CredentialsSource source) { - Log.i(TAG, "in onStatusChanged with status: " + status + "and source: " + source); + Slog.d(TAG, "in onStatusChanged for: " + componentName + ", 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) { @@ -168,7 +178,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, // or we need to respond with error. The only other case is the entry being // selected after the UI has been invoked which has a separate code path. if (isUiInvocationNeeded()) { - Log.i(TAG, "in onProviderStatusChanged - isUiInvocationNeeded"); + Slog.d(TAG, "in onProviderStatusChanged - isUiInvocationNeeded"); getProviderDataAndInitiateUi(); } else { respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index 703ab7c7fae8..e25614846896 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -287,6 +287,8 @@ public class MetricUtilities { /* count_credential_request_classtypes */ initialPhaseMetric.getCountRequestClassType() // TODO(b/271135048) - add total count of request options + // TODO(b/271135048) - Uncomment once built past PWG review - + // initialPhaseMetric.isOriginSpecified() ); } catch (Exception e) { 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 88f3e6c92947..1c3d213c8072 100644 --- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java @@ -33,7 +33,6 @@ import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; import android.service.credentials.PermissionUtils; -import android.util.Log; import android.util.Slog; import java.util.ArrayList; @@ -52,20 +51,25 @@ public class PrepareGetRequestSession extends GetRequestSession { public PrepareGetRequestSession(Context context, RequestSession.SessionLifetime sessionCallback, Object lock, int userId, int callingUid, IGetCredentialCallback getCredCallback, GetCredentialRequest request, - CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal, - long startedTimestamp, IPrepareGetCredentialCallback prepareGetCredentialCallback) { + CallingAppInfo callingAppInfo, Set<ComponentName> enabledProviders, + CancellationSignal cancellationSignal, long startedTimestamp, + IPrepareGetCredentialCallback prepareGetCredentialCallback) { super(context, sessionCallback, lock, userId, callingUid, getCredCallback, request, - callingAppInfo, cancellationSignal, startedTimestamp); + callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp); int numTypes = (request.getCredentialOptions().stream() .map(CredentialOption::getType).collect( Collectors.toSet())).size(); // Dedupe type strings - mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes); + mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes, + /*origin=*/request.getOrigin() != null); mPrepareGetCredentialCallback = prepareGetCredentialCallback; } @Override public void onProviderStatusChanged(ProviderSession.Status status, ComponentName componentName, ProviderSession.CredentialsSource source) { + Slog.d(TAG, "in onProviderStatusChanged with status: " + status + ", and " + + "source: " + source); + switch (source) { case REMOTE_PROVIDER: // Remote provider's status changed. We should check if all providers are done, and @@ -122,7 +126,7 @@ public class PrepareGetRequestSession extends GetRequestSession { hasPermission, credentialTypes, hasAuthenticationResults, hasRemoteResults, uiIntent)); } catch (RemoteException e) { - Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e); + Slog.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e); } } @@ -137,7 +141,7 @@ public class PrepareGetRequestSession extends GetRequestSession { /*hasRemoteResults=*/ false, /*pendingIntent=*/ null)); } catch (RemoteException e) { - Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e); + Slog.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e); } } @@ -178,10 +182,8 @@ public class PrepareGetRequestSession extends GetRequestSession { private PendingIntent getUiIntent() { ArrayList<ProviderData> providerDataList = new ArrayList<>(); for (ProviderSession session : mProviders.values()) { - Log.i(TAG, "preparing data for : " + session.getComponentName()); ProviderData providerData = session.prepareUiData(); if (providerData != null) { - Log.i(TAG, "Provider data is not null"); providerDataList.add(providerData); } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java index eaf58f13e2fa..9ec0ecd93b3c 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java @@ -23,9 +23,9 @@ import android.credentials.ClearCredentialStateException; import android.credentials.CredentialProviderInfo; import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderPendingIntentResponse; +import android.os.ICancellationSignal; import android.service.credentials.CallingAppInfo; import android.service.credentials.ClearCredentialStateRequest; -import android.util.Log; import android.util.Slog; /** @@ -80,7 +80,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS @Override public void onProviderResponseSuccess(@Nullable Void response) { - Log.i(TAG, "in onProviderResponseSuccess"); + Slog.d(TAG, "Remote provider responded with a valid response: " + mComponentName); mProviderResponseSet = true; updateStatusAndInvokeCallback(Status.COMPLETE, /*source=*/ CredentialsSource.REMOTE_PROVIDER); @@ -104,11 +104,16 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS updateStatusAndInvokeCallback(Status.SERVICE_DEAD, /*source=*/ CredentialsSource.REMOTE_PROVIDER); } else { - Slog.i(TAG, "Component names different in onProviderServiceDied - " + Slog.w(TAG, "Component names different in onProviderServiceDied - " + "this should not happen"); } } + @Override + public void onProviderCancellable(ICancellationSignal cancellation) { + mProviderCancellationSignal = cancellation; + } + @Nullable @Override protected ProviderData prepareUiData() { @@ -126,8 +131,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS protected void invokeSession() { if (mRemoteCredentialService != null) { startCandidateMetrics(); - mProviderCancellationSignal = - mRemoteCredentialService.onClearCredentialState(mProviderRequest, this); + mRemoteCredentialService.onClearCredentialState(mProviderRequest, this); } } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java index c657e3b1b389..09433dbb0c52 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java @@ -29,6 +29,7 @@ import android.credentials.ui.CreateCredentialProviderData; import android.credentials.ui.Entry; import android.credentials.ui.ProviderPendingIntentResponse; import android.os.Bundle; +import android.os.ICancellationSignal; import android.service.credentials.BeginCreateCredentialRequest; import android.service.credentials.BeginCreateCredentialResponse; import android.service.credentials.CallingAppInfo; @@ -36,7 +37,6 @@ import android.service.credentials.CreateCredentialRequest; import android.service.credentials.CreateEntry; import android.service.credentials.CredentialProviderService; import android.service.credentials.RemoteEntry; -import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -92,7 +92,8 @@ public final class ProviderCreateSession extends ProviderSession< createRequestSession.mHybridService ); } - Log.i(TAG, "Unable to create provider session"); + Slog.d(TAG, "Unable to create provider session for: " + + providerInfo.getComponentName()); return null; } @@ -121,7 +122,6 @@ public final class ProviderCreateSession extends ProviderSession< return new CreateCredentialRequest(callingAppInfo, capability, clientRequest.getCredentialData()); } - Log.i(TAG, "Unable to create provider request - capabilities do not match"); return null; } @@ -145,7 +145,7 @@ public final class ProviderCreateSession extends ProviderSession< @Override public void onProviderResponseSuccess( @Nullable BeginCreateCredentialResponse response) { - Log.i(TAG, "in onProviderResponseSuccess"); + Slog.d(TAG, "Remote provider responded with a valid response: " + mComponentName); onSetInitialRemoteResponse(response); } @@ -168,13 +168,17 @@ public final class ProviderCreateSession extends ProviderSession< updateStatusAndInvokeCallback(Status.SERVICE_DEAD, /*source=*/ CredentialsSource.REMOTE_PROVIDER); } else { - Slog.i(TAG, "Component names different in onProviderServiceDied - " + Slog.w(TAG, "Component names different in onProviderServiceDied - " + "this should not happen"); } } + @Override + public void onProviderCancellable(ICancellationSignal cancellation) { + mProviderCancellationSignal = cancellation; + } + private void onSetInitialRemoteResponse(BeginCreateCredentialResponse response) { - Log.i(TAG, "onSetInitialRemoteResponse with save entries"); mProviderResponse = response; mProviderResponseDataHandler.addResponseContent(response.getCreateEntries(), response.getRemoteCreateEntry()); @@ -193,14 +197,12 @@ public final class ProviderCreateSession extends ProviderSession< @Nullable protected CreateCredentialProviderData prepareUiData() throws IllegalArgumentException { - Log.i(TAG, "In prepareUiData"); if (!ProviderSession.isUiInvokingStatus(getStatus())) { - Log.i(TAG, "In prepareUiData not in uiInvokingStatus"); + Slog.d(TAG, "No data for UI from: " + mComponentName.flattenToString()); return null; } if (mProviderResponse != null && !mProviderResponseDataHandler.isEmptyResponse()) { - Log.i(TAG, "In prepareUiData save entries not null"); return mProviderResponseDataHandler.toCreateCredentialProviderData(); } return null; @@ -212,7 +214,7 @@ public final class ProviderCreateSession extends ProviderSession< switch (entryType) { case SAVE_ENTRY_KEY: if (mProviderResponseDataHandler.getCreateEntry(entryKey) == null) { - Log.i(TAG, "Unexpected save entry key"); + Slog.w(TAG, "Unexpected save entry key"); invokeCallbackOnInternalInvalidState(); return; } @@ -220,14 +222,14 @@ public final class ProviderCreateSession extends ProviderSession< break; case REMOTE_ENTRY_KEY: if (mProviderResponseDataHandler.getRemoteEntry(entryKey) == null) { - Log.i(TAG, "Unexpected remote entry key"); + Slog.w(TAG, "Unexpected remote entry key"); invokeCallbackOnInternalInvalidState(); return; } onRemoteEntrySelected(providerPendingIntentResponse); break; default: - Log.i(TAG, "Unsupported entry type selected"); + Slog.w(TAG, "Unsupported entry type selected"); invokeCallbackOnInternalInvalidState(); } } @@ -236,8 +238,7 @@ public final class ProviderCreateSession extends ProviderSession< protected void invokeSession() { if (mRemoteCredentialService != null) { startCandidateMetrics(); - mProviderCancellationSignal = - mRemoteCredentialService.onCreateCredential(mProviderRequest, this); + mRemoteCredentialService.onBeginCreateCredential(mProviderRequest, this); } } @@ -263,7 +264,7 @@ public final class ProviderCreateSession extends ProviderSession< if (credentialResponse != null) { mCallbacks.onFinalResponseReceived(mComponentName, credentialResponse); } else { - Log.i(TAG, "onSaveEntrySelected - no response or error found in pending " + Slog.w(TAG, "onSaveEntrySelected - no response or error found in pending " + "intent response"); invokeCallbackOnInternalInvalidState(); } @@ -279,14 +280,14 @@ public final class ProviderCreateSession extends ProviderSession< private CreateCredentialException maybeGetPendingIntentException( ProviderPendingIntentResponse pendingIntentResponse) { if (pendingIntentResponse == null) { - Log.i(TAG, "pendingIntentResponse is null"); + Slog.w(TAG, "pendingIntentResponse is null"); return new CreateCredentialException(CreateCredentialException.TYPE_NO_CREATE_OPTIONS); } if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) { CreateCredentialException exception = PendingIntentResultHandler .extractCreateCredentialException(pendingIntentResponse.getResultData()); if (exception != null) { - Log.i(TAG, "Pending intent contains provider exception"); + Slog.d(TAG, "Pending intent contains provider exception"); return exception; } } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) { @@ -338,7 +339,7 @@ public final class ProviderCreateSession extends ProviderSession< public void setRemoteEntry(@Nullable RemoteEntry remoteEntry) { if (!enforceRemoteEntryRestrictions(mExpectedRemoteEntryProviderService)) { - Log.i(TAG, "Remote entry being dropped as it does not meet the restriction" + Slog.w(TAG, "Remote entry being dropped as it does not meet the restriction" + "checks."); return; } diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index 9c9c0c212d0c..0c2b5633d501 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -30,6 +30,7 @@ import android.credentials.ui.AuthenticationEntry; import android.credentials.ui.Entry; import android.credentials.ui.GetCredentialProviderData; import android.credentials.ui.ProviderPendingIntentResponse; +import android.os.ICancellationSignal; import android.service.credentials.Action; import android.service.credentials.BeginGetCredentialOption; import android.service.credentials.BeginGetCredentialRequest; @@ -114,7 +115,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential getRequestSession.mHybridService ); } - Log.i(TAG, "Unable to create provider session"); + Slog.d(TAG, "Unable to create provider session for: " + + providerInfo.getComponentName()); return null; } @@ -145,17 +147,15 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential android.credentials.GetCredentialRequest clientRequest, CredentialProviderInfo info ) { + Slog.d(TAG, "Filtering request options for: " + info.getComponentName()); List<CredentialOption> filteredOptions = new ArrayList<>(); for (CredentialOption option : clientRequest.getCredentialOptions()) { if (providerCapabilities.contains(option.getType()) && isProviderAllowed(option, info.getComponentName()) && checkSystemProviderRequirement(option, info.isSystemProvider())) { - Log.i(TAG, "In createProviderRequest - capability found : " - + option.getType()); + Slog.d(TAG, "Option of type: " + option.getType() + " meets all filtering" + + "conditions"); filteredOptions.add(option); - } else { - Log.i(TAG, "In createProviderRequest - capability not " - + "found, or provider not allowed : " + option.getType()); } } if (!filteredOptions.isEmpty()) { @@ -164,15 +164,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential .setCredentialOptions( filteredOptions).build(); } - Log.i(TAG, "In createProviderRequest - returning null"); + Slog.d(TAG, "No options filtered"); return null; } private static boolean isProviderAllowed(CredentialOption option, ComponentName componentName) { if (!option.getAllowedProviders().isEmpty() && !option.getAllowedProviders().contains( componentName)) { - Log.d(TAG, "Provider allow list specified but does not contain this provider: " - + componentName.flattenToString()); + Slog.d(TAG, "Provider allow list specified but does not contain this provider"); return false; } return true; @@ -181,7 +180,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential private static boolean checkSystemProviderRequirement(CredentialOption option, boolean isSystemProvider) { if (option.isSystemProviderRequired() && !isSystemProvider) { - Log.d(TAG, "System provider required, but this service is not a system provider"); + Slog.d(TAG, "System provider required, but this service is not a system provider"); return false; } return true; @@ -209,6 +208,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential /** Called when the provider response has been updated by an external source. */ @Override // Callback from the remote provider public void onProviderResponseSuccess(@Nullable BeginGetCredentialResponse response) { + Slog.d(TAG, "Remote provider responded with a valid response: " + mComponentName); onSetInitialRemoteResponse(response); } @@ -230,21 +230,27 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential updateStatusAndInvokeCallback(Status.SERVICE_DEAD, /*source=*/ CredentialsSource.REMOTE_PROVIDER); } else { - Slog.i(TAG, "Component names different in onProviderServiceDied - " + Slog.w(TAG, "Component names different in onProviderServiceDied - " + "this should not happen"); } } + @Override + public void onProviderCancellable(ICancellationSignal cancellation) { + mProviderCancellationSignal = cancellation; + } + @Override // Selection call from the request provider protected void onUiEntrySelected(String entryType, String entryKey, ProviderPendingIntentResponse providerPendingIntentResponse) { - Log.i(TAG, "onUiEntrySelected with entryKey: " + entryKey); + Slog.d(TAG, "onUiEntrySelected with entryType: " + entryType + ", and entryKey: " + + entryKey); switch (entryType) { case CREDENTIAL_ENTRY_KEY: CredentialEntry credentialEntry = mProviderResponseDataHandler .getCredentialEntry(entryKey); if (credentialEntry == null) { - Log.i(TAG, "Unexpected credential entry key"); + Slog.w(TAG, "Unexpected credential entry key"); invokeCallbackOnInternalInvalidState(); return; } @@ -253,7 +259,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential case ACTION_ENTRY_KEY: Action actionEntry = mProviderResponseDataHandler.getActionEntry(entryKey); if (actionEntry == null) { - Log.i(TAG, "Unexpected action entry key"); + Slog.w(TAG, "Unexpected action entry key"); invokeCallbackOnInternalInvalidState(); return; } @@ -263,21 +269,21 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential Action authenticationEntry = mProviderResponseDataHandler .getAuthenticationAction(entryKey); if (authenticationEntry == null) { - Log.i(TAG, "Unexpected authenticationEntry key"); + Slog.w(TAG, "Unexpected authenticationEntry key"); invokeCallbackOnInternalInvalidState(); return; } boolean additionalContentReceived = onAuthenticationEntrySelected(providerPendingIntentResponse); if (additionalContentReceived) { - Log.i(TAG, "Additional content received - removing authentication entry"); + Slog.d(TAG, "Additional content received - removing authentication entry"); mProviderResponseDataHandler.removeAuthenticationAction(entryKey); if (!mProviderResponseDataHandler.isEmptyResponse()) { updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED, /*source=*/ CredentialsSource.AUTH_ENTRY); } } else { - Log.i(TAG, "Additional content not received"); + Slog.d(TAG, "Additional content not received from authentication entry"); mProviderResponseDataHandler .updateAuthEntryWithNoCredentialsReceived(entryKey); updateStatusAndInvokeCallback(Status.NO_CREDENTIALS_FROM_AUTH_ENTRY, @@ -288,12 +294,12 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential if (mProviderResponseDataHandler.getRemoteEntry(entryKey) != null) { onRemoteEntrySelected(providerPendingIntentResponse); } else { - Log.i(TAG, "Unexpected remote entry key"); + Slog.d(TAG, "Unexpected remote entry key"); invokeCallbackOnInternalInvalidState(); } break; default: - Log.i(TAG, "Unsupported entry type selected"); + Slog.w(TAG, "Unsupported entry type selected"); invokeCallbackOnInternalInvalidState(); } } @@ -302,9 +308,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential protected void invokeSession() { if (mRemoteCredentialService != null) { startCandidateMetrics(); - mProviderCancellationSignal = - mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this); - boolean foundSig = mProviderCancellationSignal == null; + mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this); } } @@ -316,26 +320,24 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential @Override // Call from request session to data to be shown on the UI @Nullable protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException { - Log.i(TAG, "In prepareUiData"); if (!ProviderSession.isUiInvokingStatus(getStatus())) { - Log.i(TAG, "In prepareUiData - provider does not want to show UI: " - + mComponentName.flattenToString()); + Slog.d(TAG, "No data for UI from: " + mComponentName.flattenToString()); return null; } if (mProviderResponse != null && !mProviderResponseDataHandler.isEmptyResponse()) { return mProviderResponseDataHandler.toGetCredentialProviderData(); } - Log.i(TAG, "In prepareUiData response null"); + Slog.d(TAG, "In prepareUiData response null"); return null; } - private Intent setUpFillInIntent(@NonNull String id) { + private Intent setUpFillInIntentWithFinalRequest(@NonNull String id) { // TODO: Determine if we should skip this entry if entry id is not set, or is set // but does not resolve to a valid option. For now, not skipping it because // it may be possible that the provider adds their own extras and expects to receive // those and complete the flow. if (mBeginGetOptionToCredentialOptionMap.get(id) == null) { - Log.i(TAG, "Id from Credential Entry does not resolve to a valid option"); + Slog.w(TAG, "Id from Credential Entry does not resolve to a valid option"); return new Intent(); } return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, @@ -378,7 +380,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential getCredentialResponse); return; } - Log.i(TAG, "Pending intent response contains no credential, or error"); + Slog.d(TAG, "Pending intent response contains no credential, or error " + + "for a credential entry"); invokeCallbackOnInternalInvalidState(); } @@ -386,14 +389,12 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential private GetCredentialException maybeGetPendingIntentException( ProviderPendingIntentResponse pendingIntentResponse) { if (pendingIntentResponse == null) { - Log.i(TAG, "pendingIntentResponse is null"); return null; } if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) { GetCredentialException exception = PendingIntentResultHandler .extractGetCredentialException(pendingIntentResponse.getResultData()); if (exception != null) { - Log.i(TAG, "Pending intent contains provider exception"); return exception; } } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) { @@ -459,7 +460,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential /** Returns true if either an exception or a response is found. */ private void onActionEntrySelected(ProviderPendingIntentResponse providerPendingIntentResponse) { - Log.i(TAG, "onActionEntrySelected"); + Slog.d(TAG, "onActionEntrySelected"); onCredentialEntrySelected(providerPendingIntentResponse); } @@ -555,7 +556,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential String id = generateUniqueId(); Entry entry = new Entry(CREDENTIAL_ENTRY_KEY, id, credentialEntry.getSlice(), - setUpFillInIntent(credentialEntry.getBeginGetCredentialOptionId())); + setUpFillInIntentWithFinalRequest(credentialEntry + .getBeginGetCredentialOptionId())); mUiCredentialEntries.put(id, new Pair<>(credentialEntry, entry)); mCredentialEntryTypes.add(credentialEntry.getType()); } @@ -570,9 +572,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential public void addAuthenticationAction(Action authenticationAction, @AuthenticationEntry.Status int status) { - Log.i(TAG, "In addAuthenticationAction"); String id = generateUniqueId(); - Log.i(TAG, "In addAuthenticationAction, id : " + id); AuthenticationEntry entry = new AuthenticationEntry( AUTHENTICATION_ACTION_ENTRY_KEY, id, authenticationAction.getSlice(), @@ -587,7 +587,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential public void setRemoteEntry(@Nullable RemoteEntry remoteEntry) { if (!enforceRemoteEntryRestrictions(mExpectedRemoteEntryProviderService)) { - Log.i(TAG, "Remote entry being dropped as it does not meet the restriction" + Slog.w(TAG, "Remote entry being dropped as it does not meet the restriction" + " checks."); return; } @@ -711,7 +711,6 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential == AuthenticationEntry.STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT) .findFirst(); if (previousMostRecentAuthEntry.isEmpty()) { - Log.i(TAG, "In updatePreviousMostRecentAuthEntry - previous entry not found"); return; } String id = previousMostRecentAuthEntry.get().getKey(); diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java index 9cf27210dde0..c10f5640c466 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java @@ -29,10 +29,11 @@ import android.credentials.ui.Entry; import android.credentials.ui.GetCredentialProviderData; import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderPendingIntentResponse; +import android.os.ICancellationSignal; import android.service.credentials.CallingAppInfo; import android.service.credentials.CredentialEntry; import android.service.credentials.CredentialProviderService; -import android.telecom.Log; +import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -115,7 +116,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption @NonNull String servicePackageName, @NonNull CredentialOption requestOption) { super(context, requestOption, session, - new ComponentName(servicePackageName, servicePackageName) , + new ComponentName(servicePackageName, servicePackageName), userId, null); mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId); mCallingAppInfo = callingAppInfo; @@ -132,7 +133,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption @NonNull String servicePackageName, @NonNull CredentialOption requestOption) { super(context, requestOption, session, - new ComponentName(servicePackageName, servicePackageName) , + new ComponentName(servicePackageName, servicePackageName), userId, null); mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId); mCallingAppInfo = callingAppInfo; @@ -144,14 +145,12 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption private List<Entry> prepareUiCredentialEntries( @NonNull List<CredentialEntry> credentialEntries) { - Log.i(TAG, "in prepareUiProviderDataWithCredentials"); List<Entry> credentialUiEntries = new ArrayList<>(); // Populate the credential entries for (CredentialEntry credentialEntry : credentialEntries) { String entryId = generateUniqueId(); mUiCredentialEntries.put(entryId, credentialEntry); - Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId); credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId, credentialEntry.getSlice(), setUpFillInIntent())); @@ -171,15 +170,13 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption @Override protected ProviderData prepareUiData() { - Log.i(TAG, "In prepareUiData"); if (!ProviderSession.isUiInvokingStatus(getStatus())) { - Log.i(TAG, "In prepareUiData - provider does not want to show UI: " - + mComponentName.flattenToString()); + Slog.d(TAG, "No date for UI coming from: " + mComponentName.flattenToString()); return null; } if (mProviderResponse == null) { - Log.i(TAG, "In prepareUiData response null"); - throw new IllegalStateException("Response must be in completion mode"); + Slog.w(TAG, "In prepareUiData but response is null. This is strange."); + return null; } return new GetCredentialProviderData.Builder( mComponentName.flattenToString()).setActionChips(null) @@ -199,13 +196,13 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption case CREDENTIAL_ENTRY_KEY: CredentialEntry credentialEntry = mUiCredentialEntries.get(entryKey); if (credentialEntry == null) { - Log.i(TAG, "Unexpected credential entry key"); + Slog.w(TAG, "Unexpected credential entry key"); return; } onCredentialEntrySelected(credentialEntry, providerPendingIntentResponse); break; default: - Log.i(TAG, "Unsupported entry type selected"); + Slog.w(TAG, "Unsupported entry type selected"); } } @@ -232,10 +229,8 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption } return; } - - Log.i(TAG, "Pending intent response contains no credential, or error"); } - Log.i(TAG, "CredentialEntry does not have a credential or a pending intent result"); + Slog.w(TAG, "CredentialEntry does not have a credential or a pending intent result"); } @Override @@ -255,13 +250,18 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption } @Override + public void onProviderCancellable(ICancellationSignal cancellation) { + // No need to do anything since this class does not rely on a remote service. + } + + @Override protected void invokeSession() { mProviderResponse = mCredentialDescriptionRegistry .getFilteredResultForProvider(mCredentialProviderPackageName, mElementKeys); mCredentialEntries = mProviderResponse.stream().flatMap( - (Function<CredentialDescriptionRegistry.FilterResult, - Stream<CredentialEntry>>) filterResult + (Function<CredentialDescriptionRegistry.FilterResult, + Stream<CredentialEntry>>) filterResult -> filterResult.mCredentialEntries.stream()) .collect(Collectors.toList()); updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED, @@ -273,14 +273,13 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption protected GetCredentialException maybeGetPendingIntentException( ProviderPendingIntentResponse pendingIntentResponse) { if (pendingIntentResponse == null) { - android.util.Log.i(TAG, "pendingIntentResponse is null"); return null; } if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) { GetCredentialException exception = PendingIntentResultHandler .extractGetCredentialException(pendingIntentResponse.getResultData()); if (exception != null) { - android.util.Log.i(TAG, "Pending intent contains provider exception"); + Slog.d(TAG, "Pending intent contains provider exception"); return exception; } } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) { diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java index d165756b3811..d02a8c1ee510 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java @@ -29,7 +29,6 @@ import android.credentials.ui.ProviderData; import android.credentials.ui.ProviderPendingIntentResponse; import android.os.ICancellationSignal; import android.os.RemoteException; -import android.util.Log; import android.util.Slog; import com.android.server.credentials.metrics.ProviderSessionMetric; @@ -253,7 +252,7 @@ public abstract class ProviderSession<T, R> @Nullable ComponentName expectedRemoteEntryProviderService) { // Check if the service is the one set by the OEM. If not silently reject this entry if (!mComponentName.equals(expectedRemoteEntryProviderService)) { - Log.i(TAG, "Remote entry being dropped as it is not from the service " + Slog.w(TAG, "Remote entry being dropped as it is not from the service " + "configured by the OEM."); return false; } @@ -270,15 +269,12 @@ public abstract class ProviderSession<T, R> return true; } } catch (SecurityException e) { - Log.i(TAG, "Error getting info for " - + mComponentName.flattenToString() + ": " + e.getMessage()); + Slog.e(TAG, "Error getting info for " + mComponentName.flattenToString(), e); return false; } catch (PackageManager.NameNotFoundException e) { - Log.i(TAG, "Error getting info for " - + mComponentName.flattenToString() + ": " + e.getMessage()); + Slog.i(TAG, "Error getting info for " + mComponentName.flattenToString(), e); return false; } - Log.i(TAG, "In enforceRemoteEntryRestrictions - remote entry checks fail"); return false; } diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java index ff4e3b680131..0ad73c945284 100644 --- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java +++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java @@ -40,7 +40,6 @@ import android.service.credentials.IBeginGetCredentialCallback; import android.service.credentials.IClearCredentialStateCallback; import android.service.credentials.ICredentialProviderService; import android.text.format.DateUtils; -import android.util.Log; import android.util.Slog; import com.android.internal.infra.ServiceConnector; @@ -82,6 +81,9 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr /** Called when the remote provider service dies. */ void onProviderServiceDied(RemoteCredentialService service); + + /** Called to set the cancellation transport from the remote provider service. */ + void onProviderCancellable(ICancellationSignal cancellation); } public RemoteCredentialService(@NonNull Context context, @@ -117,43 +119,54 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr * @param callback the callback to be used to send back the provider response to the * {@link ProviderGetSession} class that maintains provider state */ - public ICancellationSignal onBeginGetCredential(@NonNull BeginGetCredentialRequest request, + public void onBeginGetCredential(@NonNull BeginGetCredentialRequest request, ProviderCallbacks<BeginGetCredentialResponse> callback) { - Log.i(TAG, "In onGetCredentials in RemoteCredentialService"); AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); + AtomicReference<CompletableFuture<BeginGetCredentialResponse>> futureRef = + new AtomicReference<>(); + CompletableFuture<BeginGetCredentialResponse> connectThenExecute = postAsync(service -> { CompletableFuture<BeginGetCredentialResponse> getCredentials = new CompletableFuture<>(); final long originalCallingUidToken = Binder.clearCallingIdentity(); try { - ICancellationSignal cancellationSignal = - service.onBeginGetCredential(request, - new IBeginGetCredentialCallback.Stub() { - @Override - public void onSuccess(BeginGetCredentialResponse response) { - getCredentials.complete(response); - } + service.onBeginGetCredential(request, + new IBeginGetCredentialCallback.Stub() { + @Override + public void onSuccess(BeginGetCredentialResponse response) { + getCredentials.complete(response); + } - @Override - public void onFailure(String errorType, CharSequence message) { - Log.i(TAG, "In onFailure in RemoteCredentialService"); - String errorMsg = message == null ? "" : String.valueOf( - message); - getCredentials.completeExceptionally( - new GetCredentialException(errorType, errorMsg)); - } - }); - cancellationSink.set(cancellationSignal); + @Override + public void onFailure(String errorType, CharSequence message) { + String errorMsg = message == null ? "" : String.valueOf( + message); + getCredentials.completeExceptionally( + new GetCredentialException(errorType, errorMsg)); + } + + @Override + public void onCancellable(ICancellationSignal cancellation) { + CompletableFuture<BeginGetCredentialResponse> future = + futureRef.get(); + if (future != null && future.isCancelled()) { + dispatchCancellationSignal(cancellation); + } else { + cancellationSink.set(cancellation); + callback.onProviderCancellable(cancellation); + } + } + }); return getCredentials; } finally { Binder.restoreCallingIdentity(originalCallingUidToken); } }).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS); + futureRef.set(connectThenExecute); connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); - return cancellationSink.get(); } /** @@ -164,10 +177,11 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr * @param callback the callback to be used to send back the provider response to the * {@link ProviderCreateSession} class that maintains provider state */ - public ICancellationSignal onCreateCredential(@NonNull BeginCreateCredentialRequest request, + public void onBeginCreateCredential(@NonNull BeginCreateCredentialRequest request, ProviderCallbacks<BeginCreateCredentialResponse> callback) { - Log.i(TAG, "In onCreateCredential in RemoteCredentialService"); AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); + AtomicReference<CompletableFuture<BeginCreateCredentialResponse>> futureRef = + new AtomicReference<>(); CompletableFuture<BeginCreateCredentialResponse> connectThenExecute = postAsync(service -> { @@ -175,35 +189,42 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr new CompletableFuture<>(); final long originalCallingUidToken = Binder.clearCallingIdentity(); try { - ICancellationSignal cancellationSignal = service.onBeginCreateCredential( + service.onBeginCreateCredential( request, new IBeginCreateCredentialCallback.Stub() { @Override public void onSuccess(BeginCreateCredentialResponse response) { - Log.i(TAG, "In onSuccess onBeginCreateCredential " - + "in RemoteCredentialService"); createCredentialFuture.complete(response); } @Override public void onFailure(String errorType, CharSequence message) { - Log.i(TAG, "In onFailure in RemoteCredentialService"); String errorMsg = message == null ? "" : String.valueOf( message); createCredentialFuture.completeExceptionally( new CreateCredentialException(errorType, errorMsg)); } + + @Override + public void onCancellable(ICancellationSignal cancellation) { + CompletableFuture<BeginCreateCredentialResponse> future = + futureRef.get(); + if (future != null && future.isCancelled()) { + dispatchCancellationSignal(cancellation); + } else { + cancellationSink.set(cancellation); + callback.onProviderCancellable(cancellation); + } + } }); - cancellationSink.set(cancellationSignal); return createCredentialFuture; } finally { Binder.restoreCallingIdentity(originalCallingUidToken); } }).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS); + futureRef.set(connectThenExecute); connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); - - return cancellationSink.get(); } /** @@ -214,10 +235,10 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr * @param callback the callback to be used to send back the provider response to the * {@link ProviderClearSession} class that maintains provider state */ - public ICancellationSignal onClearCredentialState(@NonNull ClearCredentialStateRequest request, + public void onClearCredentialState(@NonNull ClearCredentialStateRequest request, ProviderCallbacks<Void> callback) { - Log.i(TAG, "In onClearCredentialState in RemoteCredentialService"); AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); + AtomicReference<CompletableFuture<Void>> futureRef = new AtomicReference<>(); CompletableFuture<Void> connectThenExecute = postAsync(service -> { @@ -225,36 +246,42 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr new CompletableFuture<>(); final long originalCallingUidToken = Binder.clearCallingIdentity(); try { - ICancellationSignal cancellationSignal = service.onClearCredentialState( + service.onClearCredentialState( request, new IClearCredentialStateCallback.Stub() { @Override public void onSuccess() { - Log.i(TAG, "In onSuccess onClearCredentialState " - + "in RemoteCredentialService"); clearCredentialFuture.complete(null); } @Override public void onFailure(String errorType, CharSequence message) { - Log.i(TAG, "In onFailure in RemoteCredentialService"); String errorMsg = message == null ? "" : String.valueOf(message); clearCredentialFuture.completeExceptionally( new ClearCredentialStateException(errorType, errorMsg)); } + + @Override + public void onCancellable(ICancellationSignal cancellation) { + CompletableFuture<Void> future = futureRef.get(); + if (future != null && future.isCancelled()) { + dispatchCancellationSignal(cancellation); + } else { + cancellationSink.set(cancellation); + callback.onProviderCancellable(cancellation); + } + } }); - cancellationSink.set(cancellationSignal); return clearCredentialFuture; } finally { Binder.restoreCallingIdentity(originalCallingUidToken); } }).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS); + futureRef.set(connectThenExecute); connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() -> handleExecutionResponse(result, error, cancellationSink, callback))); - - return cancellationSink.get(); } private <T> void handleExecutionResponse(T result, @@ -262,35 +289,29 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr AtomicReference<ICancellationSignal> cancellationSink, ProviderCallbacks<T> callback) { if (error == null) { - Log.i(TAG, "In RemoteCredentialService execute error is null"); callback.onProviderResponseSuccess(result); } else { if (error instanceof TimeoutException) { - Log.i(TAG, "In RemoteCredentialService execute error is timeout"); + Slog.d(TAG, "Remote provider response timed tuo for: " + mComponentName); dispatchCancellationSignal(cancellationSink.get()); callback.onProviderResponseFailure( CredentialProviderErrors.ERROR_TIMEOUT, null); } else if (error instanceof CancellationException) { - Log.i(TAG, "In RemoteCredentialService execute error is cancellation"); + Slog.d(TAG, "Cancellation exception for remote provider: " + mComponentName); dispatchCancellationSignal(cancellationSink.get()); callback.onProviderResponseFailure( CredentialProviderErrors.ERROR_TASK_CANCELED, null); } else if (error instanceof GetCredentialException) { - Log.i(TAG, "In RemoteCredentialService execute error is provider get" - + "error"); callback.onProviderResponseFailure( CredentialProviderErrors.ERROR_PROVIDER_FAILURE, (GetCredentialException) error); } else if (error instanceof CreateCredentialException) { - Log.i(TAG, "In RemoteCredentialService execute error is provider create " - + "error"); callback.onProviderResponseFailure( CredentialProviderErrors.ERROR_PROVIDER_FAILURE, (CreateCredentialException) error); } else { - Log.i(TAG, "In RemoteCredentialService execute error is unknown"); callback.onProviderResponseFailure( CredentialProviderErrors.ERROR_UNKNOWN, (Exception) error); diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java index ed175ed9601f..15a30e427688 100644 --- a/services/credentials/java/com/android/server/credentials/RequestSession.java +++ b/services/credentials/java/com/android/server/credentials/RequestSession.java @@ -18,6 +18,7 @@ package com.android.server.credentials; import android.annotation.NonNull; import android.annotation.UserIdInt; +import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -32,7 +33,6 @@ import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.service.credentials.CallingAppInfo; -import android.util.Log; import android.util.Slog; import com.android.internal.R; @@ -43,6 +43,7 @@ import com.android.server.credentials.metrics.RequestSessionMetric; import java.util.ArrayList; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** @@ -88,6 +89,10 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential protected final SessionLifetime mSessionCallback; + private final Set<ComponentName> mEnabledProviders; + + protected PendingIntent mPendingIntent; + @NonNull protected RequestSessionStatus mRequestSessionStatus = RequestSessionStatus.IN_PROGRESS; @@ -108,6 +113,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential @NonNull T clientRequest, U clientCallback, @NonNull String requestType, CallingAppInfo callingAppInfo, + Set<ComponentName> enabledProviders, CancellationSignal cancellationSignal, long timestampStarted) { mContext = context; mLock = lock; @@ -118,11 +124,12 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential mClientCallback = clientCallback; mRequestType = requestType; mClientAppInfo = callingAppInfo; + mEnabledProviders = enabledProviders; mCancellationSignal = cancellationSignal; mHandler = new Handler(Looper.getMainLooper(), null, true); mRequestId = new Binder(); mCredentialManagerUi = new CredentialManagerUi(mContext, - mUserId, this); + mUserId, this, mEnabledProviders); mHybridService = context.getResources().getString( R.string.config_defaultCredentialManagerHybridService); mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mRequestId, @@ -174,7 +181,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential @Override // from CredentialManagerUiCallbacks public void onUiSelection(UserSelectionDialogResult selection) { if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { - Log.i(TAG, "Request has already been completed. This is strange."); + Slog.w(TAG, "Request has already been completed. This is strange."); return; } if (isSessionCancelled()) { @@ -182,13 +189,11 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential return; } String providerId = selection.getProviderId(); - Log.i(TAG, "onUiSelection, providerId: " + providerId); ProviderSession providerSession = mProviders.get(providerId); if (providerSession == null) { - Log.i(TAG, "providerSession not found in onUiSelection"); + Slog.w(TAG, "providerSession not found in onUiSelection. This is strange."); return; } - Log.i(TAG, "Provider session found"); mRequestSessionMetric.collectMetricPerBrowsingSelect(selection, providerSession.mProviderSessionMetric.getCandidatePhasePerProviderMetric()); providerSession.onUiEntrySelected(selection.getEntryKey(), @@ -200,11 +205,23 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential if (propagateCancellation) { mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession); } + cancelExistingPendingIntent(); mRequestSessionStatus = RequestSessionStatus.COMPLETE; mProviders.clear(); clearRequestSessionLocked(); } + void cancelExistingPendingIntent() { + if (mPendingIntent != null) { + try { + mPendingIntent.cancel(); + mPendingIntent = null; + } catch (Exception e) { + Slog.e(TAG, "Unable to cancel existing pending intent", e); + } + } + } + private void clearRequestSessionLocked() { synchronized (mLock) { mSessionCallback.onFinishRequestSession(mUserId, mRequestId); @@ -242,15 +259,13 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential void getProviderDataAndInitiateUi() { ArrayList<ProviderData> providerDataList = getProviderDataForUi(); if (!providerDataList.isEmpty()) { - Log.i(TAG, "provider list not empty about to initiate ui"); launchUiWithProviderData(providerDataList); } } @NonNull protected ArrayList<ProviderData> getProviderDataForUi() { - Log.i(TAG, "In getProviderDataAndInitiateUi"); - Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size()); + Slog.d(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size()); ArrayList<ProviderData> providerDataList = new ArrayList<>(); mRequestSessionMetric.logCandidatePhaseMetrics(mProviders); @@ -260,10 +275,8 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential } for (ProviderSession session : mProviders.values()) { - Log.i(TAG, "preparing data for : " + session.getComponentName()); ProviderData providerData = session.prepareUiData(); if (providerData != null) { - Log.i(TAG, "Provider data is not null"); providerDataList.add(providerData); } } @@ -279,7 +292,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(/*has_exception=*/ false, ProviderStatusForMetrics.FINAL_SUCCESS); if (mRequestSessionStatus == RequestSessionStatus.COMPLETE) { - Log.i(TAG, "Request has already been completed. This is strange."); + Slog.w(TAG, "Request has already been completed. This is strange."); return; } if (isSessionCancelled()) { @@ -295,7 +308,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential } catch (RemoteException e) { mRequestSessionMetric.collectFinalPhaseProviderMetricStatus( /*has_exception=*/ true, ProviderStatusForMetrics.FINAL_FAILURE); - Log.i(TAG, "Issue while responding to client with a response : " + e.getMessage()); + Slog.e(TAG, "Issue while responding to client with a response : " + e); mRequestSessionMetric.logApiCalledAtFinish( /*apiStatus=*/ ApiStatus.FAILURE.getMetricCode()); } @@ -306,13 +319,13 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential * 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 + * @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."); + Slog.w(TAG, "Request has already been completed. This is strange."); return; } if (isSessionCancelled()) { @@ -325,7 +338,7 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential try { invokeClientCallbackError(errorType, errorMsg); } catch (RemoteException e) { - Log.i(TAG, "Issue while responding to client with error : " + e.getMessage()); + Slog.e(TAG, "Issue while responding to client with error : " + e); } boolean isUserCanceled = errorType.contains(MetricUtilities.USER_CANCELED_SUBSTRING); mRequestSessionMetric.logFailureOrUserCancel(isUserCanceled); diff --git a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java index a73495fa384f..0210b14943db 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java @@ -42,6 +42,10 @@ public class InitialPhaseMetric { // over to the next latency object. private long mCredentialServiceBeginQueryTimeNanoseconds = -1; + // Indicates if the origin was specified when making this API request + // TODO(b/271135048) - Emit once metrics approved + private boolean mOriginSpecified = false; + public InitialPhaseMetric() { } @@ -115,4 +119,12 @@ public class InitialPhaseMetric { public int getCountRequestClassType() { return mCountRequestClassType; } + + public void setOriginSpecified(boolean originSpecified) { + mOriginSpecified = originSpecified; + } + + public boolean isOriginSpecified() { + return mOriginSpecified; + } } diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java index 325b7e1731af..10bf56c853f5 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java @@ -149,13 +149,28 @@ public class RequestSessionMetric { } /** - * Collects request class type count in the RequestSession flow. + * Collects initializations for Create flow metrics. + * + * @param origin indicates if an origin was passed in or not + */ + public void collectCreateFlowInitialMetricInfo(boolean origin) { + try { + mInitialPhaseMetric.setOriginSpecified(origin); + } catch (Exception e) { + Log.w(TAG, "Unexpected error during metric logging: " + e); + } + } + + /** + * Collects initializations for Get flow metrics. * * @param requestClassTypeCount the number of class types in the request + * @param origin indicates if an origin was passed in or not */ - public void collectGetFlowInitialMetricInfo(int requestClassTypeCount) { + public void collectGetFlowInitialMetricInfo(int requestClassTypeCount, boolean origin) { try { mInitialPhaseMetric.setCountRequestClassType(requestClassTypeCount); + mInitialPhaseMetric.setOriginSpecified(origin); } catch (Exception e) { Log.w(TAG, "Unexpected error during metric logging: " + e); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java index 474df98cb1e6..950ec77f5ba8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java @@ -32,22 +32,25 @@ import java.util.Objects; final class BooleanPolicySerializer extends PolicySerializer<Boolean> { + private static final String ATTR_VALUE = "value"; + + private static final String TAG = "BooleanPolicySerializer"; + @Override - void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, String attributeName, - @NonNull Boolean value) + void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull Boolean value) throws IOException { Objects.requireNonNull(value); - serializer.attributeBoolean(/* namespace= */ null, attributeName, value); + serializer.attributeBoolean(/* namespace= */ null, ATTR_VALUE, value); } @Nullable @Override - BooleanPolicyValue readFromXml(TypedXmlPullParser parser, String attributeName) { + BooleanPolicyValue readFromXml(TypedXmlPullParser parser) { try { return new BooleanPolicyValue( - parser.getAttributeBoolean(/* namespace= */ null, attributeName)); + parser.getAttributeBoolean(/* namespace= */ null, ATTR_VALUE)); } catch (XmlPullParserException e) { - Log.e(DevicePolicyEngine.TAG, "Error parsing Boolean policy value", e); + Log.e(TAG, "Error parsing Boolean policy value", e); return null; } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java index c79aac722bd7..ee73f8afabd2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java @@ -53,6 +53,10 @@ import java.util.Objects; // rather than in its own files. final class BundlePolicySerializer extends PolicySerializer<Bundle> { + private static final String TAG = "BundlePolicySerializer"; + + private static final String ATTR_FILE_NAME = "file-name"; + private static final String RESTRICTIONS_FILE_PREFIX = "AppRestrictions_"; private static final String XML_SUFFIX = ".xml"; @@ -72,7 +76,7 @@ final class BundlePolicySerializer extends PolicySerializer<Bundle> { @Override void saveToXml(@NonNull PolicyKey policyKey, TypedXmlSerializer serializer, - String attributeName, @NonNull Bundle value) throws IOException { + @NonNull Bundle value) throws IOException { Objects.requireNonNull(value); Objects.requireNonNull(policyKey); if (!(policyKey instanceof PackagePolicyKey)) { @@ -82,13 +86,13 @@ final class BundlePolicySerializer extends PolicySerializer<Bundle> { String packageName = ((PackagePolicyKey) policyKey).getPackageName(); String fileName = packageToRestrictionsFileName(packageName, value); writeApplicationRestrictionsLAr(fileName, value); - serializer.attribute(/* namespace= */ null, attributeName, fileName); + serializer.attribute(/* namespace= */ null, ATTR_FILE_NAME, fileName); } @Nullable @Override - BundlePolicyValue readFromXml(TypedXmlPullParser parser, String attributeName) { - String fileName = parser.getAttributeValue(/* namespace= */ null, attributeName); + BundlePolicyValue readFromXml(TypedXmlPullParser parser) { + String fileName = parser.getAttributeValue(/* namespace= */ null, ATTR_FILE_NAME); return new BundlePolicyValue(readApplicationRestrictions(fileName)); } @@ -119,7 +123,7 @@ final class BundlePolicySerializer extends PolicySerializer<Bundle> { final TypedXmlPullParser parser = Xml.resolvePullParser(fis); XmlUtils.nextElement(parser); if (parser.getEventType() != XmlPullParser.START_TAG) { - Slog.e(DevicePolicyEngine.TAG, "Unable to read restrictions file " + Slog.e(TAG, "Unable to read restrictions file " + restrictionsFile.getBaseFile()); return restrictions; } @@ -127,7 +131,7 @@ final class BundlePolicySerializer extends PolicySerializer<Bundle> { readEntry(restrictions, values, parser); } } catch (IOException | XmlPullParserException e) { - Slog.w(DevicePolicyEngine.TAG, "Error parsing " + restrictionsFile.getBaseFile(), e); + Slog.w(TAG, "Error parsing " + restrictionsFile.getBaseFile(), e); } finally { IoUtils.closeQuietly(fis); } @@ -209,7 +213,7 @@ final class BundlePolicySerializer extends PolicySerializer<Bundle> { restrictionsFile.finishWrite(fos); } catch (Exception e) { restrictionsFile.failWrite(fos); - Slog.e(DevicePolicyEngine.TAG, "Error writing application restrictions list", e); + Slog.e(TAG, "Error writing application restrictions list", e); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java index d1c6bcb8b48c..6303a1a8b860 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/ComponentNamePolicySerializer.java @@ -30,30 +30,31 @@ import java.io.IOException; import java.util.Objects; final class ComponentNamePolicySerializer extends PolicySerializer<ComponentName> { - private static final String ATTR_PACKAGE_NAME = ":package-name"; - private static final String ATTR_CLASS_NAME = ":class-name"; + + private static final String TAG = "ComponentNamePolicySerializer"; + + private static final String ATTR_PACKAGE_NAME = "package-name"; + private static final String ATTR_CLASS_NAME = "class-name"; @Override - void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, String attributeNamePrefix, + void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull ComponentName value) throws IOException { Objects.requireNonNull(value); serializer.attribute( - /* namespace= */ null, - attributeNamePrefix + ATTR_PACKAGE_NAME, value.getPackageName()); + /* namespace= */ null, ATTR_PACKAGE_NAME, value.getPackageName()); serializer.attribute( - /* namespace= */ null, - attributeNamePrefix + ATTR_CLASS_NAME, value.getClassName()); + /* namespace= */ null, ATTR_CLASS_NAME, value.getClassName()); } @Nullable @Override - ComponentNamePolicyValue readFromXml(TypedXmlPullParser parser, String attributeNamePrefix) { + ComponentNamePolicyValue readFromXml(TypedXmlPullParser parser) { String packageName = parser.getAttributeValue( - /* namespace= */ null, attributeNamePrefix + ATTR_PACKAGE_NAME); + /* namespace= */ null, ATTR_PACKAGE_NAME); String className = parser.getAttributeValue( - /* namespace= */ null, attributeNamePrefix + ATTR_CLASS_NAME); + /* namespace= */ null, ATTR_CLASS_NAME); if (packageName == null || className == null) { - Log.e(DevicePolicyEngine.TAG, "Error parsing ComponentName policy."); + Log.e(TAG, "Error parsing ComponentName policy."); return null; } return new ComponentNamePolicyValue(new ComponentName(packageName, className)); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java index d4f4b72fbb2b..702602adf1b3 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java @@ -27,6 +27,7 @@ import static android.content.pm.UserProperties.INHERIT_DEVICE_POLICY_FROM_PAREN import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.BroadcastOptions; import android.app.admin.DevicePolicyIdentifiers; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyState; @@ -353,6 +354,7 @@ final class DevicePolicyEngine { policyDefinition, userId); } + sendDevicePolicyChangedToSystem(userId); } /** @@ -478,6 +480,8 @@ final class DevicePolicyEngine { enforcingAdmin, policyDefinition, UserHandle.USER_ALL); + + sendDevicePolicyChangedToSystem(UserHandle.USER_ALL); } /** @@ -699,7 +703,7 @@ final class DevicePolicyEngine { if (policyDefinition.isGlobalOnlyPolicy()) { throw new IllegalArgumentException(policyDefinition.getPolicyKey() + " is a global only" - + "policy."); + + " policy."); } if (!mLocalPolicies.contains(userId)) { @@ -724,7 +728,7 @@ final class DevicePolicyEngine { private <V> PolicyState<V> getGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition) { if (policyDefinition.isLocalOnlyPolicy()) { throw new IllegalArgumentException(policyDefinition.getPolicyKey() + " is a local only" - + "policy."); + + " policy."); } if (!mGlobalPolicies.containsKey(policyDefinition.getPolicyKey())) { @@ -761,6 +765,20 @@ final class DevicePolicyEngine { policyValue == null ? null : policyValue.getValue(), mContext, userId); } + private void sendDevicePolicyChangedToSystem(int userId) { + Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); + intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + Bundle options = new BroadcastOptions() + .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) + .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) + .toBundle(); + Binder.withCleanCallingIdentity(() -> mContext.sendBroadcastAsUser( + intent, + new UserHandle(userId), + /* receiverPermissions= */ null, + options)); + } + private <V> void sendPolicyResultToAdmin( EnforcingAdmin admin, PolicyDefinition<V> policyDefinition, int result, int userId) { Intent intent = new Intent(PolicyUpdateReceiver.ACTION_DEVICE_POLICY_SET_RESULT); @@ -774,7 +792,7 @@ final class DevicePolicyEngine { admin.getUserId()); if (receivers.isEmpty()) { Log.i(TAG, "Couldn't find any receivers that handle ACTION_DEVICE_POLICY_SET_RESULT" - + "in package " + admin.getPackageName()); + + " in package " + admin.getPackageName()); return; } @@ -827,7 +845,7 @@ final class DevicePolicyEngine { admin.getUserId()); if (receivers.isEmpty()) { Log.i(TAG, "Couldn't find any receivers that handle ACTION_DEVICE_POLICY_CHANGED" - + "in package " + admin.getPackageName()); + + " in package " + admin.getPackageName()); return; } @@ -850,7 +868,7 @@ final class DevicePolicyEngine { for (ResolveInfo resolveInfo : receivers) { if (!Manifest.permission.BIND_DEVICE_ADMIN.equals( resolveInfo.activityInfo.permission)) { - Log.w(TAG, "Receiver " + resolveInfo.activityInfo + " is not protected by" + Log.w(TAG, "Receiver " + resolveInfo.activityInfo + " is not protected by " + "BIND_DEVICE_ADMIN permission!"); continue; } @@ -892,7 +910,7 @@ final class DevicePolicyEngine { mDeviceAdminServiceController.stopServicesForUser( userId, actionForLog); } else { - for (EnforcingAdmin admin : getEnforcingAdminsForUser(userId)) { + for (EnforcingAdmin admin : getEnforcingAdminsOnUser(userId)) { // DPCs are handled separately in DPMS, no need to reestablish the connection here. if (admin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) { continue; @@ -903,6 +921,51 @@ final class DevicePolicyEngine { } } + /** + * Handles internal state related to a user getting started. + */ + void handleStartUser(int userId) { + updateDeviceAdminsServicesForUser( + userId, /* enable= */ true, /* actionForLog= */ "start-user"); + } + + /** + * Handles internal state related to a user getting started. + */ + void handleUnlockUser(int userId) { + updateDeviceAdminsServicesForUser( + userId, /* enable= */ true, /* actionForLog= */ "unlock-user"); + } + + /** + * Handles internal state related to a user getting stopped. + */ + void handleStopUser(int userId) { + updateDeviceAdminsServicesForUser( + userId, /* enable= */ false, /* actionForLog= */ "stop-user"); + } + + /** + * Handles internal state related to packages getting updated. + */ + void handlePackageChanged(@Nullable String updatedPackage, int userId) { + if (updatedPackage == null) { + return; + } + updateDeviceAdminServiceOnPackageChanged(updatedPackage, userId); + } + + /** + * Handles internal state related to a user getting removed. + */ + void handleUserRemoved(int userId) { + removeLocalPoliciesForUser(userId); + removePoliciesForAdminsOnUser(userId); + } + + /** + * Handles internal state related to a user getting created. + */ void handleUserCreated(UserInfo user) { enforcePoliciesOnInheritableProfilesIfApplicable(user); } @@ -945,40 +1008,6 @@ final class DevicePolicyEngine { } /** - * Handles internal state related to a user getting started. - */ - void handleStartUser(int userId) { - updateDeviceAdminsServicesForUser( - userId, /* enable= */ true, /* actionForLog= */ "start-user"); - } - - /** - * Handles internal state related to a user getting started. - */ - void handleUnlockUser(int userId) { - updateDeviceAdminsServicesForUser( - userId, /* enable= */ true, /* actionForLog= */ "unlock-user"); - } - - /** - * Handles internal state related to a user getting stopped. - */ - void handleStopUser(int userId) { - updateDeviceAdminsServicesForUser( - userId, /* enable= */ false, /* actionForLog= */ "stop-user"); - } - - /** - * Handles internal state related to packages getting updated. - */ - void handlePackageChanged(@Nullable String updatedPackage, int userId) { - if (updatedPackage == null) { - return; - } - updateDeviceAdminServiceOnPackageChanged(updatedPackage, userId); - } - - /** * Returns all current enforced policies set on the device, and the individual values set by * each admin. Global policies are returned under {@link UserHandle#ALL}. */ @@ -1006,6 +1035,68 @@ final class DevicePolicyEngine { return new DevicePolicyState(policies); } + + /** + * Removes all local and global policies set by that admin. + */ + void removePoliciesForAdmin(EnforcingAdmin admin) { + Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet()); + for (PolicyKey policy : globalPolicies) { + PolicyState<?> policyState = mGlobalPolicies.get(policy); + if (policyState.getPoliciesSetByAdmins().containsKey(admin)) { + removeGlobalPolicy(policyState.getPolicyDefinition(), admin); + } + } + + for (int i = 0; i < mLocalPolicies.size(); i++) { + Set<PolicyKey> localPolicies = new HashSet<>( + mLocalPolicies.get(mLocalPolicies.keyAt(i)).keySet()); + for (PolicyKey policy : localPolicies) { + PolicyState<?> policyState = mLocalPolicies.get( + mLocalPolicies.keyAt(i)).get(policy); + if (policyState.getPoliciesSetByAdmins().containsKey(admin)) { + removeLocalPolicy( + policyState.getPolicyDefinition(), admin, mLocalPolicies.keyAt(i)); + } + } + } + } + + /** + * Removes all local policies for the provided {@code userId}. + */ + private void removeLocalPoliciesForUser(int userId) { + if (!mLocalPolicies.contains(userId)) { + // No policies on user + return; + } + + Set<PolicyKey> localPolicies = new HashSet<>(mLocalPolicies.get(userId).keySet()); + for (PolicyKey policy : localPolicies) { + PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy); + Set<EnforcingAdmin> admins = new HashSet<>( + policyState.getPoliciesSetByAdmins().keySet()); + for (EnforcingAdmin admin : admins) { + removeLocalPolicy( + policyState.getPolicyDefinition(), admin, userId); + } + } + + mLocalPolicies.remove(userId); + } + + /** + * Removes all local and global policies for admins installed in the provided + * {@code userId}. + */ + private void removePoliciesForAdminsOnUser(int userId) { + Set<EnforcingAdmin> admins = getEnforcingAdminsOnUser(userId); + + for (EnforcingAdmin admin : admins) { + removePoliciesForAdmin(admin); + } + } + /** * Reestablishes the service that handles * {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} in the enforcing admin if the package @@ -1013,7 +1104,7 @@ final class DevicePolicyEngine { */ private void updateDeviceAdminServiceOnPackageChanged( @NonNull String updatedPackage, int userId) { - for (EnforcingAdmin admin : getEnforcingAdminsForUser(userId)) { + for (EnforcingAdmin admin : getEnforcingAdminsOnUser(userId)) { // DPCs are handled separately in DPMS, no need to reestablish the connection here. if (admin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) { continue; @@ -1102,7 +1193,7 @@ final class DevicePolicyEngine { } @NonNull - private Set<EnforcingAdmin> getEnforcingAdminsForUser(int userId) { + private Set<EnforcingAdmin> getEnforcingAdminsOnUser(int userId) { return mEnforcingAdmins.contains(userId) ? mEnforcingAdmins.get(userId) : Collections.emptySet(); } @@ -1141,12 +1232,6 @@ final class DevicePolicyEngine { } } - // TODO: we need to listen for user removal and package removal and update out internal policy - // map and enforcing admins for this is be accurate. - boolean hasActivePolicies() { - return mEnforcingAdmins.size() > 0; - } - private <V> boolean checkFor2gFailure(@NonNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin) { if (!policyDefinition.getPolicyKey().getIdentifier().equals( @@ -1181,7 +1266,8 @@ final class DevicePolicyEngine { private static final String DEVICE_POLICIES_XML = "device_policy_state.xml"; private static final String TAG_LOCAL_POLICY_ENTRY = "local-policy-entry"; private static final String TAG_GLOBAL_POLICY_ENTRY = "global-policy-entry"; - private static final String TAG_ADMINS_POLICY_ENTRY = "admins-policy-entry"; + private static final String TAG_POLICY_STATE_ENTRY = "policy-state-entry"; + private static final String TAG_POLICY_KEY_ENTRY = "policy-key-entry"; private static final String TAG_ENFORCING_ADMINS_ENTRY = "enforcing-admins-entry"; private static final String ATTR_USER_ID = "user-id"; @@ -1236,11 +1322,14 @@ final class DevicePolicyEngine { serializer.startTag(/* namespace= */ null, TAG_LOCAL_POLICY_ENTRY); serializer.attributeInt(/* namespace= */ null, ATTR_USER_ID, userId); + + serializer.startTag(/* namespace= */ null, TAG_POLICY_KEY_ENTRY); policy.getKey().saveToXml(serializer); + serializer.endTag(/* namespace= */ null, TAG_POLICY_KEY_ENTRY); - serializer.startTag(/* namespace= */ null, TAG_ADMINS_POLICY_ENTRY); + serializer.startTag(/* namespace= */ null, TAG_POLICY_STATE_ENTRY); policy.getValue().saveToXml(serializer); - serializer.endTag(/* namespace= */ null, TAG_ADMINS_POLICY_ENTRY); + serializer.endTag(/* namespace= */ null, TAG_POLICY_STATE_ENTRY); serializer.endTag(/* namespace= */ null, TAG_LOCAL_POLICY_ENTRY); } @@ -1253,11 +1342,13 @@ final class DevicePolicyEngine { for (Map.Entry<PolicyKey, PolicyState<?>> policy : mGlobalPolicies.entrySet()) { serializer.startTag(/* namespace= */ null, TAG_GLOBAL_POLICY_ENTRY); + serializer.startTag(/* namespace= */ null, TAG_POLICY_KEY_ENTRY); policy.getKey().saveToXml(serializer); + serializer.endTag(/* namespace= */ null, TAG_POLICY_KEY_ENTRY); - serializer.startTag(/* namespace= */ null, TAG_ADMINS_POLICY_ENTRY); + serializer.startTag(/* namespace= */ null, TAG_POLICY_STATE_ENTRY); policy.getValue().saveToXml(serializer); - serializer.endTag(/* namespace= */ null, TAG_ADMINS_POLICY_ENTRY); + serializer.endTag(/* namespace= */ null, TAG_POLICY_STATE_ENTRY); serializer.endTag(/* namespace= */ null, TAG_GLOBAL_POLICY_ENTRY); } @@ -1323,28 +1414,56 @@ final class DevicePolicyEngine { private void readLocalPoliciesInner(TypedXmlPullParser parser) throws XmlPullParserException, IOException { int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID); - PolicyKey policyKey = PolicyDefinition.readPolicyKeyFromXml(parser); - if (!mLocalPolicies.contains(userId)) { - mLocalPolicies.put(userId, new HashMap<>()); + PolicyKey policyKey = null; + PolicyState<?> policyState = null; + int outerDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, outerDepth)) { + String tag = parser.getName(); + switch (tag) { + case TAG_POLICY_KEY_ENTRY: + policyKey = PolicyDefinition.readPolicyKeyFromXml(parser); + break; + case TAG_POLICY_STATE_ENTRY: + policyState = PolicyState.readFromXml(parser); + break; + default: + Log.e(TAG, "Unknown tag for local policy entry" + tag); + } } - PolicyState<?> adminsPolicy = parseAdminsPolicy(parser); - if (adminsPolicy != null) { - mLocalPolicies.get(userId).put(policyKey, adminsPolicy); + + if (policyKey != null && policyState != null) { + if (!mLocalPolicies.contains(userId)) { + mLocalPolicies.put(userId, new HashMap<>()); + } + mLocalPolicies.get(userId).put(policyKey, policyState); } else { - Log.e(TAG, - "Error parsing file, " + policyKey + "doesn't have an " + "AdminsPolicy."); + Log.e(TAG, "Error parsing local policy"); } } private void readGlobalPoliciesInner(TypedXmlPullParser parser) throws IOException, XmlPullParserException { - PolicyKey policyKey = PolicyDefinition.readPolicyKeyFromXml(parser); - PolicyState<?> adminsPolicy = parseAdminsPolicy(parser); - if (adminsPolicy != null) { - mGlobalPolicies.put(policyKey, adminsPolicy); + PolicyKey policyKey = null; + PolicyState<?> policyState = null; + int outerDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, outerDepth)) { + String tag = parser.getName(); + switch (tag) { + case TAG_POLICY_KEY_ENTRY: + policyKey = PolicyDefinition.readPolicyKeyFromXml(parser); + break; + case TAG_POLICY_STATE_ENTRY: + policyState = PolicyState.readFromXml(parser); + break; + default: + Log.e(TAG, "Unknown tag for local policy entry" + tag); + } + } + + if (policyKey != null && policyState != null) { + mGlobalPolicies.put(policyKey, policyState); } else { - Log.e(TAG, - "Error parsing file, " + policyKey + "doesn't have an " + "AdminsPolicy."); + Log.e(TAG, "Error parsing global policy"); } } @@ -1356,20 +1475,5 @@ final class DevicePolicyEngine { } mEnforcingAdmins.get(admin.getUserId()).add(admin); } - - @Nullable - private PolicyState<?> parseAdminsPolicy(TypedXmlPullParser parser) - throws XmlPullParserException, IOException { - int outerDepth = parser.getDepth(); - while (XmlUtils.nextElementWithin(parser, outerDepth)) { - String tag = parser.getName(); - if (tag.equals(TAG_ADMINS_POLICY_ENTRY)) { - return PolicyState.readFromXml(parser); - } - Log.e(TAG, "Unknown tag " + tag); - } - Log.e(TAG, "Error parsing file, AdminsPolicy not found"); - return null; - } } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b2156414b122..5cad4e208b3f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -19,6 +19,7 @@ package com.android.server.devicepolicy; import static android.Manifest.permission.BIND_DEVICE_ADMIN; import static android.Manifest.permission.LOCK_DEVICE; import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; +import static android.Manifest.permission.MANAGE_DEFAULT_APPLICATIONS; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL; @@ -59,6 +60,7 @@ import static android.Manifest.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTI import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS; +import static android.Manifest.permission.MANAGE_DEVICE_POLICY_RUN_IN_BACKGROUND; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SCREEN_CONTENT; @@ -441,7 +443,6 @@ import android.util.AtomicFile; import android.util.DebugUtils; import android.util.IndentingPrintWriter; import android.util.IntArray; -import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -563,6 +564,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final int REQUEST_PROFILE_OFF_DEADLINE = 5572; + private static final int MAX_PROFILE_NAME_LENGTH = 200; + private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1); private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms @@ -853,7 +856,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String ENABLE_DEVICE_POLICY_ENGINE_FOR_FINANCE_FLAG = "enable_device_policy_engine"; - private static final boolean DEFAULT_ENABLE_DEVICE_POLICY_ENGINE_FOR_FINANCE_FLAG = false; + private static final boolean DEFAULT_ENABLE_DEVICE_POLICY_ENGINE_FOR_FINANCE_FLAG = true; // TODO(b/265683382) remove the flag after rollout. private static final String KEEP_PROFILES_RUNNING_FLAG = "enable_keep_profiles_running"; @@ -1175,6 +1178,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Resume logging if all remaining users are affiliated. maybeResumeDeviceWideLoggingLocked(); } + if (isPolicyEngineForFinanceFlagEnabled() || isPermissionCheckFlagEnabled()) { + mDevicePolicyEngine.handleUserRemoved(userHandle); + } } } else if (Intent.ACTION_USER_STARTED.equals(action)) { sendDeviceOwnerUserCommand(DeviceAdminReceiver.ACTION_USER_STARTED, userHandle); @@ -3661,6 +3667,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } for (Integer userId : deletedUsers) { removeUserData(userId); + if (isPolicyEngineForFinanceFlagEnabled() || isPermissionCheckFlagEnabled()) { + mDevicePolicyEngine.handleUserRemoved(userId); + } } } @@ -4150,6 +4159,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mInjector.binderWithCleanCallingIdentity(() -> removeActiveAdminLocked(adminReceiver, userHandle)); + if (isPolicyEngineForFinanceFlagEnabled() || isPermissionCheckFlagEnabled()) { + mDevicePolicyEngine.removePoliciesForAdmin( + EnforcingAdmin.createEnterpriseEnforcingAdmin( + adminReceiver, userHandle, admin)); + } } } @@ -7765,12 +7779,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Explicit behaviour if (factoryReset) { // TODO(b/254031494) Replace with new factory reset permission checks - boolean hasPermission = isDeviceOwnerUserId(userId) - || (isOrganizationOwnedDeviceWithManagedProfile() - && calledOnParentInstance); - Preconditions.checkState(hasPermission, - "Admin %s does not have permission to factory reset the device.", - userId); + if (!isPermissionCheckFlagEnabled()) { + boolean hasPermission = isDeviceOwnerUserId(userId) + || (isOrganizationOwnedDeviceWithManagedProfile() + && calledOnParentInstance); + Preconditions.checkCallAuthorization(hasPermission, + "Admin %s does not have permission to factory reset the device.", + userId); + } wipeDevice = true; } else { Preconditions.checkCallAuthorization(!isSystemUser, @@ -9987,6 +10003,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { toggleBackupServiceActive(UserHandle.USER_SYSTEM, true); pushUserControlDisabledPackagesLocked(userId); setGlobalSettingDeviceOwnerType(DEVICE_OWNER_TYPE_DEFAULT); + + if (isPolicyEngineForFinanceFlagEnabled() || isPermissionCheckFlagEnabled()) { + mDevicePolicyEngine.removePoliciesForAdmin( + EnforcingAdmin.createEnterpriseEnforcingAdmin( + admin.info.getComponent(), userId, admin)); + } } private void clearApplicationRestrictions(int userId) { @@ -10134,6 +10156,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { toggleBackupServiceActive(userId, true); applyProfileRestrictionsIfDeviceOwnerLocked(); setNetworkLoggingActiveInternal(false); + + if (isPolicyEngineForFinanceFlagEnabled() || isPermissionCheckFlagEnabled()) { + mDevicePolicyEngine.removePoliciesForAdmin( + EnforcingAdmin.createEnterpriseEnforcingAdmin( + admin.info.getComponent(), userId, admin)); + } } @Override @@ -10380,8 +10408,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkCallAuthorization( isDefaultDeviceOwner(caller) || isProfileOwner(caller)); + final String truncatedProfileName = + profileName.substring(0, Math.min(profileName.length(), MAX_PROFILE_NAME_LENGTH)); mInjector.binderWithCleanCallingIdentity(() -> { - mUserManager.setUserName(caller.getUserId(), profileName); + mUserManager.setUserName(caller.getUserId(), truncatedProfileName); DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_PROFILE_NAME) .setAdmin(caller.getComponentName()) @@ -11387,7 +11417,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { for (PolicyKey key : keys) { if (!(key instanceof IntentFilterPolicyKey)) { throw new IllegalStateException("PolicyKey for PERSISTENT_PREFERRED_ACTIVITY is not" - + "of type PersistentPreferredActivityPolicyKey"); + + "of type IntentFilterPolicyKey"); } IntentFilterPolicyKey parsedKey = (IntentFilterPolicyKey) key; @@ -13127,19 +13157,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } int userId = caller.getUserId(); - if (!UserRestrictionsUtils.isValidRestriction(key)) { - return; - } checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION); if (isPolicyEngineForFinanceFlagEnabled()) { - int affectedUserId = parent ? getProfileParentId(userId) : userId; - EnforcingAdmin admin = enforcePermissionForUserRestriction( - who, - key, - caller.getPackageName(), - affectedUserId); - if (mInjector.isChangeEnabled(ENABLE_COEXISTENCE_CHANGE, callerPackage, userId)) { + if (!isDeviceOwner(caller) && !isProfileOwner(caller)) { + if (!mInjector.isChangeEnabled(ENABLE_COEXISTENCE_CHANGE, callerPackage, userId)) { + throw new IllegalStateException("Calling package is not targeting Android U."); + } + if (!UserRestrictionsUtils.isValidRestriction(key)) { + throw new IllegalArgumentException("Invalid restriction key: " + key); + } + int affectedUserId = parent ? getProfileParentId(userId) : userId; + EnforcingAdmin admin = enforcePermissionForUserRestriction( + who, + key, + caller.getPackageName(), + affectedUserId); PolicyDefinition<Boolean> policyDefinition = PolicyDefinition.getPolicyDefinitionForUserRestriction(key); if (enabledFromThisOwner) { @@ -13151,7 +13184,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { setGlobalUserRestrictionInternal(admin, key, /* enabled= */ false); } if (!policyDefinition.isGlobalOnlyPolicy()) { - setLocalUserRestrictionInternal(admin, key, /* enabled= */ false, userId); + setLocalUserRestrictionInternal(admin, key, /* enabled= */ false, + userId); int parentUserId = getProfileParentId(userId); if (parentUserId != userId) { @@ -13161,49 +13195,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } else { + if (!UserRestrictionsUtils.isValidRestriction(key)) { + return; + } + Objects.requireNonNull(who, "ComponentName is null"); + EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackage); + checkAdminCanSetRestriction(caller, parent, key); setBackwardCompatibleUserRestriction( caller, admin, key, enabledFromThisOwner, parent); } } else { - Objects.requireNonNull(who, "ComponentName is null"); - if (parent) { - Preconditions.checkCallAuthorization( - isProfileOwnerOfOrganizationOwnedDevice(caller)); - } else { - Preconditions.checkCallAuthorization( - isDeviceOwner(caller) || isProfileOwner(caller)); - } - synchronized (getLockObject()) { - if (isDefaultDeviceOwner(caller)) { - if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) { - throw new SecurityException("Device owner cannot set user restriction " - + key); - } - Preconditions.checkArgument(!parent, - "Cannot use the parent instance in Device Owner mode"); - } else if (isFinancedDeviceOwner(caller)) { - if (!UserRestrictionsUtils.canFinancedDeviceOwnerChange(key)) { - throw new SecurityException("Cannot set user restriction " + key - + " when managing a financed device"); - } - Preconditions.checkArgument(!parent, - "Cannot use the parent instance in Financed Device Owner" - + " mode"); - } else { - boolean profileOwnerCanChangeOnItself = !parent - && UserRestrictionsUtils.canProfileOwnerChange( - key, userId == getMainUserId()); - boolean orgOwnedProfileOwnerCanChangeGlobally = parent - && isProfileOwnerOfOrganizationOwnedDevice(caller) - && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange( - key); - - if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) { - throw new SecurityException("Profile owner cannot set user restriction " - + key); - } - } + if (!UserRestrictionsUtils.isValidRestriction(key)) { + return; } + Objects.requireNonNull(who, "ComponentName is null"); + checkAdminCanSetRestriction(caller, parent, key); synchronized (getLockObject()) { final ActiveAdmin activeAdmin = getParentOfAdminIfRequired( getProfileOwnerOrDeviceOwnerLocked(userId), parent); @@ -13220,6 +13226,46 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { logUserRestrictionCall(key, enabledFromThisOwner, parent, caller); } + private void checkAdminCanSetRestriction(CallerIdentity caller, boolean parent, String key) { + if (parent) { + Preconditions.checkCallAuthorization( + isProfileOwnerOfOrganizationOwnedDevice(caller)); + } else { + Preconditions.checkCallAuthorization( + isDeviceOwner(caller) || isProfileOwner(caller)); + } + synchronized (getLockObject()) { + if (isDefaultDeviceOwner(caller)) { + if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) { + throw new SecurityException("Device owner cannot set user restriction " + + key); + } + Preconditions.checkArgument(!parent, + "Cannot use the parent instance in Device Owner mode"); + } else if (isFinancedDeviceOwner(caller)) { + if (!UserRestrictionsUtils.canFinancedDeviceOwnerChange(key)) { + throw new SecurityException("Cannot set user restriction " + key + + " when managing a financed device"); + } + Preconditions.checkArgument(!parent, + "Cannot use the parent instance in Financed Device Owner" + + " mode"); + } else { + boolean profileOwnerCanChangeOnItself = !parent + && UserRestrictionsUtils.canProfileOwnerChange( + key, caller.getUserId() == getMainUserId()); + boolean orgOwnedProfileOwnerCanChangeGlobally = parent + && isProfileOwnerOfOrganizationOwnedDevice(caller) + && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange( + key); + + if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) { + throw new SecurityException("Profile owner cannot set user restriction " + + key); + } + } + } + } private void setBackwardCompatibleUserRestriction( CallerIdentity caller, EnforcingAdmin admin, String key, boolean enabled, boolean parent) { @@ -13241,6 +13287,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ? getProfileParentId(caller.getUserId()) : caller.getUserId(); setLocalUserRestrictionInternal(admin, key, enabled, affectedUserId); } + } else { + throw new IllegalStateException("Non-DO/Non-PO cannot set restriction " + key + + " while targetSdkVersion is less than UPSIDE_DOWN_CAKE"); } } } @@ -13248,33 +13297,34 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setUserRestrictionGlobally(String callerPackage, String key) { final CallerIdentity caller = getCallerIdentity(callerPackage); - if (!UserRestrictionsUtils.isValidRestriction(key)) { - return; - } checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION); if (!isPolicyEngineForFinanceFlagEnabled()) { throw new IllegalStateException("Feature flag is not enabled."); } - + if (isDeviceOwner(caller) || isProfileOwner(caller)) { + throw new IllegalStateException("Admins are not allowed to call this API."); + } if (!mInjector.isChangeEnabled( ENABLE_COEXISTENCE_CHANGE, callerPackage, caller.getUserId())) { throw new IllegalStateException("Calling package is not targeting Android U."); } + if (!UserRestrictionsUtils.isValidRestriction(key)) { + throw new IllegalArgumentException("Invalid restriction key: " + key); + } EnforcingAdmin admin = enforcePermissionForUserRestriction( /* who= */ null, key, caller.getPackageName(), - caller.getUserId() + UserHandle.USER_ALL ); setGlobalUserRestrictionInternal(admin, key, /* enabled= */ true); logUserRestrictionCall(key, /* enabled= */ true, /* parent= */ false, caller); } - private void setLocalUserRestrictionInternal( EnforcingAdmin admin, String key, boolean enabled, int userId) { PolicyDefinition<Boolean> policyDefinition = @@ -13292,7 +13342,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { userId); } } - private void setGlobalUserRestrictionInternal( EnforcingAdmin admin, String key, boolean enabled) { PolicyDefinition<Boolean> policyDefinition = @@ -13412,14 +13461,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int targetUserId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId(); EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackage); - Bundle restrictions = getUserRestrictionsFromPolicyEngine(admin, targetUserId); - // Add global restrictions set by the admin as well if admin is not targeting Android U. - if (!mInjector.isChangeEnabled( - ENABLE_COEXISTENCE_CHANGE, callerPackage, caller.getUserId())) { + if (isDeviceOwner(caller) || isProfileOwner(caller)) { + Objects.requireNonNull(who, "ComponentName is null"); + Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) + || isFinancedDeviceOwner(caller) + || isProfileOwner(caller) + || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller))); + + Bundle restrictions = getUserRestrictionsFromPolicyEngine(admin, targetUserId); + // Add global restrictions set by the admin as well. restrictions.putAll( getUserRestrictionsFromPolicyEngine(admin, UserHandle.USER_ALL)); + return restrictions; + } else { + if (!mInjector.isChangeEnabled( + ENABLE_COEXISTENCE_CHANGE, callerPackage, caller.getUserId())) { + throw new IllegalStateException("Calling package is not targeting Android U."); + } + return getUserRestrictionsFromPolicyEngine(admin, targetUserId); } - return restrictions; } else { Objects.requireNonNull(who, "ComponentName is null"); Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) @@ -13435,164 +13495,162 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } // Map of user restriction to permission. - private static final HashMap<String, String> USER_RESTRICTION_PERMISSIONS = new HashMap<>(); + private static final HashMap<String, String[]> USER_RESTRICTION_PERMISSIONS = new HashMap<>(); { USER_RESTRICTION_PERMISSIONS.put( - UserManager.ENSURE_VERIFY_APPS, MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES); + UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, new String[]{MANAGE_DEVICE_POLICY_PROFILES}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_WIFI_TETHERING, MANAGE_DEVICE_POLICY_WIFI); + UserManager.DISALLOW_ADD_CLONE_PROFILE, new String[]{MANAGE_DEVICE_POLICY_PROFILES}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_WIFI_DIRECT, MANAGE_DEVICE_POLICY_WIFI); + UserManager.DISALLOW_ADD_USER, new String[]{MANAGE_DEVICE_POLICY_USERS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_USER_SWITCH, MANAGE_DEVICE_POLICY_USERS); + UserManager.DISALLOW_ADD_WIFI_CONFIG, new String[]{MANAGE_DEVICE_POLICY_WIFI}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_USB_FILE_TRANSFER, MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER); + UserManager.DISALLOW_ADJUST_VOLUME, new String[]{MANAGE_DEVICE_POLICY_AUDIO_OUTPUT}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_UNMUTE_MICROPHONE, MANAGE_DEVICE_POLICY_MICROPHONE); + UserManager.DISALLOW_AIRPLANE_MODE, new String[]{MANAGE_DEVICE_POLICY_AIRPLANE_MODE}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_UNMUTE_DEVICE, MANAGE_DEVICE_POLICY_AUDIO_OUTPUT); + UserManager.DISALLOW_AMBIENT_DISPLAY, new String[]{MANAGE_DEVICE_POLICY_DISPLAY}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_UNINSTALL_APPS, MANAGE_DEVICE_POLICY_APPS_CONTROL); + UserManager.DISALLOW_APPS_CONTROL, new String[]{MANAGE_DEVICE_POLICY_APPS_CONTROL}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_UNIFIED_PASSWORD, MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS); + UserManager.DISALLOW_AUTOFILL, new String[]{MANAGE_DEVICE_POLICY_AUTOFILL}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS); + UserManager.DISALLOW_BLUETOOTH, new String[]{MANAGE_DEVICE_POLICY_BLUETOOTH}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_SMS, MANAGE_DEVICE_POLICY_SMS); + UserManager.DISALLOW_BLUETOOTH_SHARING, new String[]{MANAGE_DEVICE_POLICY_BLUETOOTH}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, MANAGE_DEVICE_POLICY_WIFI); + UserManager.DISALLOW_CAMERA, new String[]{MANAGE_DEVICE_POLICY_CAMERA}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_SHARE_LOCATION, MANAGE_DEVICE_POLICY_LOCATION); + UserManager.DISALLOW_CAMERA_TOGGLE, new String[]{MANAGE_DEVICE_POLICY_CAMERA_TOGGLE}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, - MANAGE_DEVICE_POLICY_PROFILE_INTERACTION); + UserManager.DISALLOW_CELLULAR_2G, new String[]{MANAGE_DEVICE_POLICY_MOBILE_NETWORK}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_SET_WALLPAPER, MANAGE_DEVICE_POLICY_WALLPAPER); + UserManager.DISALLOW_CHANGE_WIFI_STATE, new String[]{MANAGE_DEVICE_POLICY_WIFI}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_SET_USER_ICON, MANAGE_DEVICE_POLICY_USERS); + UserManager.DISALLOW_CONFIG_BLUETOOTH, new String[]{MANAGE_DEVICE_POLICY_BLUETOOTH}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_SAFE_BOOT, MANAGE_DEVICE_POLICY_SAFE_BOOT); + UserManager.DISALLOW_CONFIG_BRIGHTNESS, new String[]{MANAGE_DEVICE_POLICY_DISPLAY}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_RUN_IN_BACKGROUND, MANAGE_DEVICE_POLICY_SAFE_BOOT); + UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, new String[]{MANAGE_DEVICE_POLICY_MOBILE_NETWORK}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_REMOVE_USER, MANAGE_DEVICE_POLICY_USERS); + UserManager.DISALLOW_CONFIG_CREDENTIALS, new String[]{MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_PRINTING, MANAGE_DEVICE_POLICY_PRINTING); + UserManager.DISALLOW_CONFIG_DATE_TIME, new String[]{MANAGE_DEVICE_POLICY_TIME}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_OUTGOING_CALLS, MANAGE_DEVICE_POLICY_CALLS); + UserManager.DISALLOW_CONFIG_DEFAULT_APPS, new String[]{MANAGE_DEFAULT_APPLICATIONS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_OUTGOING_BEAM, MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION); + UserManager.DISALLOW_CONFIG_LOCALE, new String[]{MANAGE_DEVICE_POLICY_LOCALE}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_NETWORK_RESET, MANAGE_DEVICE_POLICY_MOBILE_NETWORK); + UserManager.DISALLOW_CONFIG_LOCATION, new String[]{MANAGE_DEVICE_POLICY_LOCATION}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA); + UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, new String[]{MANAGE_DEVICE_POLICY_MOBILE_NETWORK}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_MODIFY_ACCOUNTS, MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT); + UserManager.DISALLOW_CONFIG_PRIVATE_DNS, new String[]{MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_MICROPHONE_TOGGLE, MANAGE_DEVICE_POLICY_MICROPHONE); + UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, new String[]{MANAGE_DEVICE_POLICY_DISPLAY}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, - MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES); + UserManager.DISALLOW_CONFIG_TETHERING, new String[]{MANAGE_DEVICE_POLICY_MOBILE_NETWORK}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, - MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES); + UserManager.DISALLOW_CONFIG_VPN, new String[]{MANAGE_DEVICE_POLICY_VPN}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_INSTALL_APPS, MANAGE_DEVICE_POLICY_APPS_CONTROL); + UserManager.DISALLOW_CONFIG_WIFI, new String[]{MANAGE_DEVICE_POLICY_WIFI}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_FUN, MANAGE_DEVICE_POLICY_FUN); + UserManager.DISALLOW_CONTENT_CAPTURE, new String[]{MANAGE_DEVICE_POLICY_SCREEN_CONTENT}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_FACTORY_RESET, MANAGE_DEVICE_POLICY_FACTORY_RESET); + UserManager.DISALLOW_CONTENT_SUGGESTIONS, new String[]{MANAGE_DEVICE_POLICY_SCREEN_CONTENT}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_DEBUGGING_FEATURES, MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES); + UserManager.DISALLOW_CREATE_WINDOWS, new String[]{MANAGE_DEVICE_POLICY_WINDOWS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_DATA_ROAMING, MANAGE_DEVICE_POLICY_MOBILE_NETWORK); + UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, new String[]{MANAGE_DEVICE_POLICY_PROFILE_INTERACTION}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, - MANAGE_DEVICE_POLICY_PROFILE_INTERACTION); + UserManager.DISALLOW_DATA_ROAMING, new String[]{MANAGE_DEVICE_POLICY_MOBILE_NETWORK}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CREATE_WINDOWS, MANAGE_DEVICE_POLICY_WINDOWS); + UserManager.DISALLOW_DEBUGGING_FEATURES, new String[]{MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONTENT_SUGGESTIONS, MANAGE_DEVICE_POLICY_SCREEN_CONTENT); + UserManager.DISALLOW_FACTORY_RESET, new String[]{MANAGE_DEVICE_POLICY_FACTORY_RESET}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONTENT_CAPTURE, MANAGE_DEVICE_POLICY_SCREEN_CONTENT); + UserManager.DISALLOW_FUN, new String[]{MANAGE_DEVICE_POLICY_FUN}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_WIFI, MANAGE_DEVICE_POLICY_WIFI); + UserManager.DISALLOW_INSTALL_APPS, new String[]{MANAGE_DEVICE_POLICY_APPS_CONTROL}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_VPN, MANAGE_DEVICE_POLICY_VPN); + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, new String[]{MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_TETHERING, MANAGE_DEVICE_POLICY_MOBILE_NETWORK); + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, new String[]{MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, MANAGE_DEVICE_POLICY_DISPLAY); + UserManager.DISALLOW_MICROPHONE_TOGGLE, new String[]{MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_PRIVATE_DNS, MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS); + UserManager.DISALLOW_MODIFY_ACCOUNTS, new String[]{MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, MANAGE_DEVICE_POLICY_MOBILE_NETWORK); + UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, new String[]{MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_LOCATION, MANAGE_DEVICE_POLICY_LOCATION); + UserManager.DISALLOW_NETWORK_RESET, new String[]{MANAGE_DEVICE_POLICY_MOBILE_NETWORK}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_LOCALE, MANAGE_DEVICE_POLICY_LOCALE); + UserManager.DISALLOW_OUTGOING_BEAM, new String[]{MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_DATE_TIME, MANAGE_DEVICE_POLICY_TIME); + UserManager.DISALLOW_OUTGOING_CALLS, new String[]{MANAGE_DEVICE_POLICY_CALLS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_CREDENTIALS, MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS); + UserManager.DISALLOW_PRINTING, new String[]{MANAGE_DEVICE_POLICY_PRINTING}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, MANAGE_DEVICE_POLICY_MOBILE_NETWORK); + UserManager.DISALLOW_REMOVE_USER, new String[]{MANAGE_DEVICE_POLICY_USERS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_BRIGHTNESS, MANAGE_DEVICE_POLICY_DISPLAY); + UserManager.DISALLOW_RUN_IN_BACKGROUND, new String[]{MANAGE_DEVICE_POLICY_RUN_IN_BACKGROUND}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_BLUETOOTH, MANAGE_DEVICE_POLICY_BLUETOOTH); + UserManager.DISALLOW_SAFE_BOOT, new String[]{MANAGE_DEVICE_POLICY_SAFE_BOOT}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CHANGE_WIFI_STATE, MANAGE_DEVICE_POLICY_WIFI); + UserManager.DISALLOW_SET_USER_ICON, new String[]{MANAGE_DEVICE_POLICY_USERS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CAMERA_TOGGLE, MANAGE_DEVICE_POLICY_CAMERA); + UserManager.DISALLOW_SET_WALLPAPER, new String[]{MANAGE_DEVICE_POLICY_WALLPAPER}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CAMERA, MANAGE_DEVICE_POLICY_CAMERA); + UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, new String[]{MANAGE_DEVICE_POLICY_PROFILE_INTERACTION}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_BLUETOOTH_SHARING, MANAGE_DEVICE_POLICY_BLUETOOTH); + UserManager.DISALLOW_SHARE_LOCATION, new String[]{MANAGE_DEVICE_POLICY_LOCATION}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_BLUETOOTH, MANAGE_DEVICE_POLICY_BLUETOOTH); + UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, new String[]{MANAGE_DEVICE_POLICY_WIFI}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_BIOMETRIC, MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS); + UserManager.DISALLOW_SMS, new String[]{MANAGE_DEVICE_POLICY_SMS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_AUTOFILL, MANAGE_DEVICE_POLICY_AUTOFILL); + UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, new String[]{MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_APPS_CONTROL, MANAGE_DEVICE_POLICY_APPS_CONTROL); + UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, new String[]{MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_AMBIENT_DISPLAY, MANAGE_DEVICE_POLICY_DISPLAY); + UserManager.DISALLOW_UNIFIED_PASSWORD, new String[]{MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_AIRPLANE_MODE, MANAGE_DEVICE_POLICY_AIRPLANE_MODE); + UserManager.DISALLOW_UNINSTALL_APPS, new String[]{MANAGE_DEVICE_POLICY_APPS_CONTROL}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_ADJUST_VOLUME, MANAGE_DEVICE_POLICY_AUDIO_OUTPUT); + UserManager.DISALLOW_UNMUTE_DEVICE, new String[]{MANAGE_DEVICE_POLICY_AUDIO_OUTPUT}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_ADD_WIFI_CONFIG, MANAGE_DEVICE_POLICY_WIFI); + UserManager.DISALLOW_UNMUTE_MICROPHONE, new String[]{MANAGE_DEVICE_POLICY_MICROPHONE}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_ADD_USER, MANAGE_DEVICE_POLICY_USERS); + UserManager.DISALLOW_USB_FILE_TRANSFER, new String[]{MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_ADD_CLONE_PROFILE, MANAGE_DEVICE_POLICY_PROFILES); + UserManager.DISALLOW_USER_SWITCH, new String[]{MANAGE_DEVICE_POLICY_USERS}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, MANAGE_DEVICE_POLICY_PROFILES); + UserManager.DISALLOW_WIFI_DIRECT, new String[]{MANAGE_DEVICE_POLICY_WIFI}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CELLULAR_2G, MANAGE_DEVICE_POLICY_MOBILE_NETWORK); + UserManager.DISALLOW_WIFI_TETHERING, new String[]{MANAGE_DEVICE_POLICY_WIFI}); USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, - MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION); + UserManager.ENSURE_VERIFY_APPS, new String[]{MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES}); // Restrictions not allowed to be set by admins. USER_RESTRICTION_PERMISSIONS.put( UserManager.DISALLOW_RECORD_AUDIO, null); USER_RESTRICTION_PERMISSIONS.put( UserManager.DISALLOW_WALLPAPER, null); - USER_RESTRICTION_PERMISSIONS.put( - UserManager.DISALLOW_CONFIG_DEFAULT_APPS, null); } private EnforcingAdmin enforcePermissionForUserRestriction(ComponentName who, String userRestriction, String callerPackageName, int userId) { - String permission = USER_RESTRICTION_PERMISSIONS.get(userRestriction); - if (permission != null) { - return enforcePermissionAndGetEnforcingAdmin(who, permission, callerPackageName, - userId); - } + String[] permissions = USER_RESTRICTION_PERMISSIONS.get(userRestriction); + if (permissions.length > 0) { + try { + return enforcePermissionsAndGetEnforcingAdmin(who, permissions, callerPackageName, + userId); + } catch (SecurityException e) { + throw new SecurityException("Caller does not hold the required permission for this " + + "user restriction: " + userRestriction + ".\n" + e.getMessage()); + } + } throw new SecurityException("Admins are not permitted to set User Restriction: " + userRestriction); } @@ -14013,9 +14071,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final CallerIdentity caller = getCallerIdentity(who, callerPackage); if (isPolicyEngineForFinanceFlagEnabled()) { - EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin( + EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin( who, - MANAGE_DEVICE_POLICY_APPS_CONTROL, + new String[]{ + MANAGE_DEVICE_POLICY_APPS_CONTROL, + MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL + }, caller.getPackageName(), caller.getUserId()); mDevicePolicyEngine.setLocalPolicy( @@ -14664,7 +14725,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } final int userId = mInjector.userHandleGetCallingUserId(); - if (isPermissionCheckFlagEnabled()) { + if (isPolicyEngineForFinanceFlagEnabled()) { LockTaskPolicy policy = mDevicePolicyEngine.getResolvedPolicy( PolicyDefinition.LOCK_TASK, userId); if (policy == null) { @@ -16051,6 +16112,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else { long ident = mInjector.binderClearCallingIdentity(); try { + // TODO(b/277908283): check in the policy engine instead of calling user manager. List<UserManager.EnforcingUser> sources = mUserManager .getUserRestrictionSources(restriction, UserHandle.of(userId)); if (sources == null) { @@ -16082,27 +16144,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } final UserManager.EnforcingUser enforcingUser = sources.get(0); final int sourceType = enforcingUser.getUserRestrictionSource(); - final int enforcingUserId = enforcingUser.getUserHandle().getIdentifier(); - if (sourceType == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) { - // Restriction was enforced by PO - final ComponentName profileOwner = mOwners.getProfileOwnerComponent( - enforcingUserId); - if (profileOwner != null) { - result = new Bundle(); - result.putInt(Intent.EXTRA_USER_ID, enforcingUserId); - result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, - profileOwner); - return result; - } - } else if (sourceType == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) { - // Restriction was enforced by DO - final Pair<Integer, ComponentName> deviceOwner = - mOwners.getDeviceOwnerUserIdAndComponent(); - if (deviceOwner != null) { + if (sourceType == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER + || sourceType == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) { + ActiveAdmin admin = getMostProbableDPCAdminForLocalPolicy(userId); + if (admin != null) { result = new Bundle(); - result.putInt(Intent.EXTRA_USER_ID, deviceOwner.first); + result.putInt(Intent.EXTRA_USER_ID, admin.getUserHandle().getIdentifier()); result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, - deviceOwner.second); + admin.info.getComponent()); return result; } } else if (sourceType == UserManager.RESTRICTION_SOURCE_SYSTEM) { @@ -16622,10 +16671,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { SENSOR_PERMISSIONS.add(Manifest.permission.BACKGROUND_CAMERA); SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_BACKGROUND_AUDIO); SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND); - SENSOR_PERMISSIONS.add( - Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE); - SENSOR_PERMISSIONS.add( - Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND); } private boolean canGrantPermission(CallerIdentity caller, String permission, @@ -17320,6 +17365,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { caller.getUserId()); admin = enforcingAdmin.getActiveAdmin(); } else { + Objects.requireNonNull(who, "ComponentName is null"); Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)); } @@ -17351,6 +17397,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { caller.getUserId()); admin = enforcingAdmin.getActiveAdmin(); } else { + Objects.requireNonNull(who, "ComponentName is null"); Preconditions.checkCallingUser(isManagedProfile(caller.getUserId())); Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)); @@ -22418,6 +22465,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { }); } + // Permission that will need to be created in V. + private static final String MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL = + "manage_device_policy_block_uninstall"; + private static final String MANAGE_DEVICE_POLICY_CAMERA_TOGGLE = + "manage_device_policy_camera_toggle"; + private static final String MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE = + "manage_device_policy_microphone_toggle"; + // DPC types private static final int DEFAULT_DEVICE_OWNER = 0; private static final int FINANCED_DEVICE_OWNER = 1; @@ -22508,53 +22563,53 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ); /** - * All the permisisons granted to a profile owner. + * All the permissions granted to a profile owner. */ private static final List<String> PROFILE_OWNER_PERMISSIONS = List.of( - MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, - MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL, - MANAGE_DEVICE_POLICY_APPS_CONTROL, - MANAGE_DEVICE_POLICY_APP_RESTRICTIONS, - MANAGE_DEVICE_POLICY_AUDIO_OUTPUT, - MANAGE_DEVICE_POLICY_AUTOFILL, - MANAGE_DEVICE_POLICY_CALLS, - MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES, - MANAGE_DEVICE_POLICY_DISPLAY, - MANAGE_DEVICE_POLICY_FACTORY_RESET, - MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES, - MANAGE_DEVICE_POLICY_KEYGUARD, - MANAGE_DEVICE_POLICY_LOCALE, - MANAGE_DEVICE_POLICY_LOCATION, - MANAGE_DEVICE_POLICY_LOCK, - MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, - MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION, - MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY, - MANAGE_DEVICE_POLICY_PACKAGE_STATE, - MANAGE_DEVICE_POLICY_PRINTING, - MANAGE_DEVICE_POLICY_PROFILES, - MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, - MANAGE_DEVICE_POLICY_RESET_PASSWORD, - MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, - MANAGE_DEVICE_POLICY_SCREEN_CAPTURE, - MANAGE_DEVICE_POLICY_SCREEN_CONTENT, - MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, - MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS, - MANAGE_DEVICE_POLICY_TIME, - MANAGE_DEVICE_POLICY_VPN, - MANAGE_DEVICE_POLICY_WIPE_DATA + MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, + MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL, + MANAGE_DEVICE_POLICY_APPS_CONTROL, + MANAGE_DEVICE_POLICY_APP_RESTRICTIONS, + MANAGE_DEVICE_POLICY_AUDIO_OUTPUT, + MANAGE_DEVICE_POLICY_AUTOFILL, + MANAGE_DEVICE_POLICY_BLUETOOTH, + MANAGE_DEVICE_POLICY_CALLS, + MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES, + MANAGE_DEVICE_POLICY_DISPLAY, + MANAGE_DEVICE_POLICY_FACTORY_RESET, + MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES, + MANAGE_DEVICE_POLICY_KEYGUARD, + MANAGE_DEVICE_POLICY_LOCALE, + MANAGE_DEVICE_POLICY_LOCATION, + MANAGE_DEVICE_POLICY_LOCK, + MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, + MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION, + MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY, + MANAGE_DEVICE_POLICY_PACKAGE_STATE, + MANAGE_DEVICE_POLICY_PRINTING, + MANAGE_DEVICE_POLICY_PROFILES, + MANAGE_DEVICE_POLICY_PROFILE_INTERACTION, + MANAGE_DEVICE_POLICY_RESET_PASSWORD, + MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, + MANAGE_DEVICE_POLICY_SCREEN_CAPTURE, + MANAGE_DEVICE_POLICY_SCREEN_CONTENT, + MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, + MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS, + MANAGE_DEVICE_POLICY_TIME, + MANAGE_DEVICE_POLICY_VPN, + MANAGE_DEVICE_POLICY_WIPE_DATA ); /** - * All the additional permissions granted to an organisation owned profile owner. - */ + * All the additional permissions granted to an organisation owned profile owner. + */ private static final List<String> ADDITIONAL_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS = - List.of( + List.of( MANAGE_DEVICE_POLICY_ACROSS_USERS, MANAGE_DEVICE_POLICY_AIRPLANE_MODE, MANAGE_DEVICE_POLICY_APPS_CONTROL, - MANAGE_DEVICE_POLICY_BLUETOOTH, MANAGE_DEVICE_POLICY_CAMERA, MANAGE_DEVICE_POLICY_CERTIFICATES, MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE, @@ -22575,13 +22630,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { MANAGE_DEVICE_POLICY_WIFI, SET_TIME, SET_TIME_ZONE - ); + ); private static final List<String> ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS = List.of( MANAGE_DEVICE_POLICY_AIRPLANE_MODE, - MANAGE_DEVICE_POLICY_BLUETOOTH, MANAGE_DEVICE_POLICY_CAMERA, MANAGE_DEVICE_POLICY_DISPLAY, MANAGE_DEVICE_POLICY_FUN, @@ -22641,7 +22695,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { { DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, DELEGATION_PERMISSION_GRANT); DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS, DELEGATION_APP_RESTRICTIONS); - DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_APPS_CONTROL, DELEGATION_BLOCK_UNINSTALL); + DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL, DELEGATION_BLOCK_UNINSTALL); DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, DELEGATION_SECURITY_LOGGING); DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE, DELEGATION_PACKAGE_ACCESS); } @@ -22720,6 +22774,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUTOFILL, MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); + CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL, + MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); + CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_CAMERA_TOGGLE, + MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE, MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES, @@ -22736,6 +22794,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_TASK, MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); + CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE, + MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY, MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL); CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILES, @@ -22766,13 +22826,34 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Checks if the calling process has been granted permission to apply a device policy on a + * specific user. Only one permission provided in the list needs to be granted to pass this + * check. + * The given permissions will be checked along with their associated cross-user permissions if + * they exists and the target user is different to the calling user. + * Returns an {@link EnforcingAdmin} for the caller. + * + * @param admin the component name of the admin. + * @param callerPackageName The package name of the calling application. + * @param permissions an array of permission names to be checked. + * @param targetUserId The userId of the user which the caller needs permission to act on. + * @throws SecurityException if the caller has not been granted the given permission, + * the associated cross-user permission if the caller's user is different to the target user. + */ + private EnforcingAdmin enforcePermissionsAndGetEnforcingAdmin(@Nullable ComponentName admin, + String[] permissions, String callerPackageName, int targetUserId) { + enforcePermissions(permissions, callerPackageName, targetUserId); + return getEnforcingAdminForCaller(admin, callerPackageName); + } + + /** + * Checks if the calling process has been granted permission to apply a device policy on a * specific user. * The given permission will be checked along with its associated cross-user permission if it * exists and the target user is different to the calling user. * Returns an {@link EnforcingAdmin} for the caller. * * @param admin the component name of the admin. - * @param callerPackageName The package name of the calling application. + * @param callerPackageName The package name of the calling application. * @param permission The name of the permission being checked. * @param targetUserId The userId of the user which the caller needs permission to act on. * @throws SecurityException if the caller has not been granted the given permission, @@ -22830,6 +22911,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { new HashMap<>(); /** + * Checks if the calling process has been granted permission to apply a device policy. + * + * @param callerPackageName The package name of the calling application. + * @param permission The name of the permission being checked. + * @throws SecurityException if the caller has not been granted the given permission, + * the associated cross-user permission if the caller's user is different to the target user. + */ + private void enforcePermission(String permission, String callerPackageName) + throws SecurityException { + if (!hasPermission(permission, callerPackageName)) { + throw new SecurityException("Caller does not have the required permissions for " + + "this user. Permission required: " + + permission + + "."); + } + } + + + /** * Checks if the calling process has been granted permission to apply a device policy on a * specific user. * The given permission will be checked along with its associated cross-user permission if it @@ -22843,17 +22943,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ private void enforcePermission(String permission, String callerPackageName, int targetUserId) throws SecurityException { - if (!hasPermission(permission, callerPackageName, targetUserId)) { - // TODO(b/276920002): Split the error messages so that the cross-user permission - // is only mentioned when it is needed. + enforcePermission(permission, callerPackageName); + if (targetUserId != getCallerIdentity(callerPackageName).getUserId()) { + enforcePermission(CROSS_USER_PERMISSIONS.get(permission), callerPackageName); + } + } + + /** + * Checks if the calling process has been granted permission to apply a device policy on a + * specific user. Only one of the given permissions will be required to be held to pass this + * check. + * The given permissions will be checked along with their associated cross-user permissions if + * they exist and the target user is different to the calling user. + * + * @param permissions An array of the names of the permissions being checked. + * @param callerPackageName The package name of the calling application. + * @param targetUserId The userId of the user which the caller needs permission to act on. + * @throws SecurityException if the caller has not been granted the given permission, + * the associated cross-user permission if the caller's user is different to the target user. + */ + private void enforcePermissions(String[] permissions, String callerPackageName, + int targetUserId) throws SecurityException { + String heldPermission = ""; + for (String permission : permissions) { + if (hasPermission(permission, callerPackageName)) { + heldPermission = permission; + break; + } + } + if (heldPermission.isEmpty()) { throw new SecurityException("Caller does not have the required permissions for " - + "this user. Permissions required: {" - + permission - + ", " - + CROSS_USER_PERMISSIONS.get(permission) - + "(if calling cross-user)" - + "}"); + + "this user. One of the following permission required: " + + Arrays.toString(permissions)); } + enforcePermission(heldPermission, callerPackageName, targetUserId); } /** @@ -22863,25 +22986,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * exists and the target user is different to the calling user. * * @param callerPackageName The package name of the calling application. + * @param adminPolicy The admin policy that should grant holders permission. * @param permission The name of the permission being checked. * @param targetUserId The userId of the user which the caller needs permission to act on. * @throws SecurityException if the caller has not been granted the given permission, * the associated cross-user permission if the caller's user is different to the target user. */ private void enforcePermission(String permission, int adminPolicy, - String callerPackageName, int targetUserId) - throws SecurityException { - if (!hasPermissionOrAdminPolicy(permission, callerPackageName, adminPolicy, targetUserId)) { - // TODO(b/276920002): Split the error messages so that the cross-user permission - // is only mentioned when it is needed. - throw new SecurityException("Caller does not have the required permissions for " - + "this user. Permissions required: {" - + permission - + ", " - + CROSS_USER_PERMISSIONS.get(permission) - + "(if calling cross-user)" - + "}"); + String callerPackageName, int targetUserId) throws SecurityException { + if (hasAdminPolicy(adminPolicy, callerPackageName)) { + return; } + enforcePermission(permission, callerPackageName, targetUserId); } /** @@ -22905,6 +23021,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforcePermission(permission, callerPackageName, targetUserId); } + private boolean hasAdminPolicy(int adminPolicy, String callerPackageName) { + CallerIdentity caller = getCallerIdentity(callerPackageName); + ActiveAdmin deviceAdmin = getActiveAdminForCaller(null, caller); + return deviceAdmin != null && deviceAdmin.info.usesPolicy(adminPolicy); + } + /** * Return whether the calling process has been granted permission to apply a device policy on * a specific user. @@ -22917,24 +23039,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { CallerIdentity caller = getCallerIdentity(callerPackageName); boolean hasPermissionOnOwnUser = hasPermission(permission, caller.getPackageName()); boolean hasPermissionOnTargetUser = true; - if (hasPermissionOnOwnUser & caller.getUserId() != targetUserId) { - hasPermissionOnTargetUser = hasPermission(CROSS_USER_PERMISSIONS.get(permission), - caller.getPackageName()); + if (hasPermissionOnOwnUser && caller.getUserId() != targetUserId) { + hasPermissionOnTargetUser = hasPermissionOnTargetUser + && hasPermission(CROSS_USER_PERMISSIONS.get(permission), + caller.getPackageName()); } return hasPermissionOnOwnUser && hasPermissionOnTargetUser; } - private boolean hasPermissionOrAdminPolicy(String permission, String callerPackageName, - int adminPolicy, int targetUserId) { - CallerIdentity caller = getCallerIdentity(callerPackageName); - if (hasPermission(permission, caller.getPackageName(), targetUserId)) { - return true; - } - ActiveAdmin deviceAdmin = getActiveAdminForCaller(null, caller); - return deviceAdmin != null && deviceAdmin.info.usesPolicy(adminPolicy); - } - /** * Return whether the calling process has been granted the given permission. * diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java index bff6d3288dca..45a2d2a7bda1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java @@ -32,21 +32,25 @@ import java.util.Objects; final class IntegerPolicySerializer extends PolicySerializer<Integer> { + private static final String TAG = "IntegerPolicySerializer"; + + private static final String ATTR_VALUE = "value"; + @Override - void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, String attributeName, + void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull Integer value) throws IOException { Objects.requireNonNull(value); - serializer.attributeInt(/* namespace= */ null, attributeName, value); + serializer.attributeInt(/* namespace= */ null, ATTR_VALUE, value); } @Nullable @Override - IntegerPolicyValue readFromXml(TypedXmlPullParser parser, String attributeName) { + IntegerPolicyValue readFromXml(TypedXmlPullParser parser) { try { return new IntegerPolicyValue( - parser.getAttributeInt(/* namespace= */ null, attributeName)); + parser.getAttributeInt(/* namespace= */ null, ATTR_VALUE)); } catch (XmlPullParserException e) { - Log.e(DevicePolicyEngine.TAG, "Error parsing Integer policy value", e); + Log.e(TAG, "Error parsing Integer policy value", e); return null; } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java index 3265b61a3543..0f6f3c5a5921 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicySerializer.java @@ -32,12 +32,14 @@ import java.util.Set; final class LockTaskPolicySerializer extends PolicySerializer<LockTaskPolicy> { - private static final String ATTR_PACKAGES = ":packages"; + private static final String TAG = "LockTaskPolicySerializer"; + + private static final String ATTR_PACKAGES = "packages"; private static final String ATTR_PACKAGES_SEPARATOR = ";"; - private static final String ATTR_FLAGS = ":flags"; + private static final String ATTR_FLAGS = "flags"; @Override - void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, String attributeNamePrefix, + void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull LockTaskPolicy value) throws IOException { Objects.requireNonNull(value); if (value.getPackages() == null || value.getPackages().isEmpty()) { @@ -46,31 +48,31 @@ final class LockTaskPolicySerializer extends PolicySerializer<LockTaskPolicy> { } serializer.attribute( /* namespace= */ null, - attributeNamePrefix + ATTR_PACKAGES, + ATTR_PACKAGES, String.join(ATTR_PACKAGES_SEPARATOR, value.getPackages())); serializer.attributeInt( /* namespace= */ null, - attributeNamePrefix + ATTR_FLAGS, + ATTR_FLAGS, value.getFlags()); } @Override - LockTaskPolicy readFromXml(TypedXmlPullParser parser, String attributeNamePrefix) { + LockTaskPolicy readFromXml(TypedXmlPullParser parser) { String packagesStr = parser.getAttributeValue( /* namespace= */ null, - attributeNamePrefix + ATTR_PACKAGES); + ATTR_PACKAGES); if (packagesStr == null) { - Log.e(DevicePolicyEngine.TAG, "Error parsing LockTask policy value."); + Log.e(TAG, "Error parsing LockTask policy value."); return null; } Set<String> packages = Set.of(packagesStr.split(ATTR_PACKAGES_SEPARATOR)); try { int flags = parser.getAttributeInt( /* namespace= */ null, - attributeNamePrefix + ATTR_FLAGS); + ATTR_FLAGS); return new LockTaskPolicy(packages, flags); } catch (XmlPullParserException e) { - Log.e(DevicePolicyEngine.TAG, "Error parsing LockTask policy value", e); + Log.e(TAG, "Error parsing LockTask policy value", e); return null; } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java index f77d051cab86..522c4b5e84be 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java @@ -32,21 +32,25 @@ import java.util.Objects; final class LongPolicySerializer extends PolicySerializer<Long> { + private static final String TAG = "LongPolicySerializer"; + + private static final String ATTR_VALUE = "value"; + @Override - void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, String attributeName, + void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull Long value) throws IOException { Objects.requireNonNull(value); - serializer.attributeLong(/* namespace= */ null, attributeName, value); + serializer.attributeLong(/* namespace= */ null, ATTR_VALUE, value); } @Nullable @Override - LongPolicyValue readFromXml(TypedXmlPullParser parser, String attributeName) { + LongPolicyValue readFromXml(TypedXmlPullParser parser) { try { return new LongPolicyValue( - parser.getAttributeLong(/* namespace= */ null, attributeName)); + parser.getAttributeLong(/* namespace= */ null, ATTR_VALUE)); } catch (XmlPullParserException e) { - Log.e(DevicePolicyEngine.TAG, "Error parsing Long policy value", e); + Log.e(TAG, "Error parsing Long policy value", e); return null; } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java index a15aa53be96c..8c2468af1146 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java @@ -284,6 +284,7 @@ final class PolicyDefinition<V> { private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>(); private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>(); + // TODO(b/277218360): Revisit policies that should be marked as global-only. static { POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE); POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY, @@ -312,8 +313,9 @@ final class PolicyDefinition<V> { USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_WIFI_TETHERING, POLICY_FLAG_GLOBAL_ONLY_POLICY); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_GRANT_ADMIN, /* flags= */ 0); + // TODO: set as global only once we get rid of the mapping USER_RESTRICTION_FLAGS.put( - UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, POLICY_FLAG_GLOBAL_ONLY_POLICY); + UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, /* flags= */ 0); USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_WIFI_DIRECT, POLICY_FLAG_GLOBAL_ONLY_POLICY); USER_RESTRICTION_FLAGS.put( @@ -333,8 +335,10 @@ final class PolicyDefinition<V> { USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BLUETOOTH, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH_SHARING, /* flags= */ 0); + // This effectively always applies globally, but it can be set on the profile + // parent, check the javadocs on the restriction for more info. USER_RESTRICTION_FLAGS.put( - UserManager.DISALLOW_USB_FILE_TRANSFER, POLICY_FLAG_GLOBAL_ONLY_POLICY); + UserManager.DISALLOW_USB_FILE_TRANSFER, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CREDENTIALS, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_USER, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, /* flags= */ 0); @@ -344,8 +348,10 @@ final class PolicyDefinition<V> { USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DATE_TIME, /* flags= */ 0); USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_CONFIG_TETHERING, /* flags= */ 0); + // This effectively always applies globally, but it can be set on the profile + // parent, check the javadocs on the restriction for more info. USER_RESTRICTION_FLAGS.put( - UserManager.DISALLOW_NETWORK_RESET, POLICY_FLAG_GLOBAL_ONLY_POLICY); + UserManager.DISALLOW_NETWORK_RESET, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FACTORY_RESET, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_USER, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_MANAGED_PROFILE, /* flags= */ 0); @@ -376,8 +382,7 @@ final class PolicyDefinition<V> { USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_DEVICE, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DATA_ROAMING, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_USER_ICON, /* flags= */ 0); - // TODO: double check flags - USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OEM_UNLOCK, POLICY_FLAG_GLOBAL_ONLY_POLICY); + USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OEM_UNLOCK, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNIFIED_PASSWORD, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, /* flags= */ 0); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AUTOFILL, /* flags= */ 0); @@ -390,6 +395,7 @@ final class PolicyDefinition<V> { USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_CONFIG_PRIVATE_DNS, POLICY_FLAG_GLOBAL_ONLY_POLICY); USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MICROPHONE_TOGGLE, /* flags= */ 0); + // TODO: According the UserRestrictionsUtils, this is global only, need to confirm. USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA_TOGGLE, /* flags= */ 0); // TODO: check if its global only USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BIOMETRIC, /* flags= */ 0); @@ -531,7 +537,6 @@ final class PolicyDefinition<V> { } void saveToXml(TypedXmlSerializer serializer) throws IOException { - // TODO: here and elsewhere, add tags to ensure attributes aren't overridden by duplication. mPolicyKey.saveToXml(serializer); } @@ -554,14 +559,14 @@ final class PolicyDefinition<V> { return genericPolicyDefinition.mPolicyKey.readFromXml(parser); } - void savePolicyValueToXml(TypedXmlSerializer serializer, String attributeName, V value) + void savePolicyValueToXml(TypedXmlSerializer serializer, V value) throws IOException { - mPolicySerializer.saveToXml(mPolicyKey, serializer, attributeName, value); + mPolicySerializer.saveToXml(mPolicyKey, serializer, value); } @Nullable - PolicyValue<V> readPolicyValueFromXml(TypedXmlPullParser parser, String attributeName) { - return mPolicySerializer.readFromXml(parser, attributeName); + PolicyValue<V> readPolicyValueFromXml(TypedXmlPullParser parser) { + return mPolicySerializer.readFromXml(parser); } @Override diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java index 0ef431f6ff90..5af2fa285483 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java @@ -26,8 +26,7 @@ import com.android.modules.utils.TypedXmlSerializer; import java.io.IOException; abstract class PolicySerializer<V> { - abstract void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, - String attributeName, @NonNull V value) + abstract void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull V value) throws IOException; - abstract PolicyValue<V> readFromXml(TypedXmlPullParser parser, String attributeName); + abstract PolicyValue<V> readFromXml(TypedXmlPullParser parser); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java index 3a792d82d2ba..741f209a90c3 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java @@ -35,11 +35,14 @@ import java.util.Objects; * Class containing all values set for a certain policy by different admins. */ final class PolicyState<V> { + + private static final String TAG = "PolicyState"; private static final String TAG_ADMIN_POLICY_ENTRY = "admin-policy-entry"; - private static final String TAG_ENFORCING_ADMIN_ENTRY = "enforcing-admin-entry"; - private static final String ATTR_POLICY_VALUE = "policy-value"; - private static final String ATTR_RESOLVED_POLICY = "resolved-policy"; + private static final String TAG_POLICY_DEFINITION_ENTRY = "policy-definition-entry"; + private static final String TAG_RESOLVED_VALUE_ENTRY = "resolved-value-entry"; + private static final String TAG_ENFORCING_ADMIN_ENTRY = "enforcing-admin-entry"; + private static final String TAG_POLICY_VALUE_ENTRY = "policy-value-entry"; private final PolicyDefinition<V> mPolicyDefinition; private final LinkedHashMap<EnforcingAdmin, PolicyValue<V>> mPoliciesSetByAdmins = new LinkedHashMap<>(); @@ -193,18 +196,24 @@ final class PolicyState<V> { } void saveToXml(TypedXmlSerializer serializer) throws IOException { + serializer.startTag(/* namespace= */ null, TAG_POLICY_DEFINITION_ENTRY); mPolicyDefinition.saveToXml(serializer); + serializer.endTag(/* namespace= */ null, TAG_POLICY_DEFINITION_ENTRY); if (mCurrentResolvedPolicy != null) { + serializer.startTag(/* namespace= */ null, TAG_RESOLVED_VALUE_ENTRY); mPolicyDefinition.savePolicyValueToXml( - serializer, ATTR_RESOLVED_POLICY, mCurrentResolvedPolicy.getValue()); + serializer, mCurrentResolvedPolicy.getValue()); + serializer.endTag(/* namespace= */ null, TAG_RESOLVED_VALUE_ENTRY); } for (EnforcingAdmin admin : mPoliciesSetByAdmins.keySet()) { serializer.startTag(/* namespace= */ null, TAG_ADMIN_POLICY_ENTRY); + serializer.startTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY); mPolicyDefinition.savePolicyValueToXml( - serializer, ATTR_POLICY_VALUE, mPoliciesSetByAdmins.get(admin).getValue()); + serializer, mPoliciesSetByAdmins.get(admin).getValue()); + serializer.endTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY); serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMIN_ENTRY); admin.saveToXml(serializer); @@ -217,32 +226,57 @@ final class PolicyState<V> { static <V> PolicyState<V> readFromXml(TypedXmlPullParser parser) throws IOException, XmlPullParserException { - PolicyDefinition<V> policyDefinition = PolicyDefinition.readFromXml(parser); + PolicyDefinition<V> policyDefinition = null; - PolicyValue<V> currentResolvedPolicy = policyDefinition.readPolicyValueFromXml( - parser, ATTR_RESOLVED_POLICY); + PolicyValue<V> currentResolvedPolicy = null; LinkedHashMap<EnforcingAdmin, PolicyValue<V>> policiesSetByAdmins = new LinkedHashMap<>(); int outerDepth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, outerDepth)) { String tag = parser.getName(); - if (TAG_ADMIN_POLICY_ENTRY.equals(tag)) { - PolicyValue<V> value = policyDefinition.readPolicyValueFromXml( - parser, ATTR_POLICY_VALUE); - EnforcingAdmin admin; - int adminPolicyDepth = parser.getDepth(); - if (XmlUtils.nextElementWithin(parser, adminPolicyDepth) - && parser.getName().equals(TAG_ENFORCING_ADMIN_ENTRY)) { - admin = EnforcingAdmin.readFromXml(parser); - policiesSetByAdmins.put(admin, value); - } - } else { - Log.e(DevicePolicyEngine.TAG, "Unknown tag: " + tag); + switch (tag) { + case TAG_ADMIN_POLICY_ENTRY: + PolicyValue<V> value = null; + EnforcingAdmin admin = null; + int adminPolicyDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, adminPolicyDepth)) { + String adminPolicyTag = parser.getName(); + switch (adminPolicyTag) { + case TAG_ENFORCING_ADMIN_ENTRY: + admin = EnforcingAdmin.readFromXml(parser); + break; + case TAG_POLICY_VALUE_ENTRY: + value = policyDefinition.readPolicyValueFromXml(parser); + break; + } + } + if (admin != null && value != null) { + policiesSetByAdmins.put(admin, value); + } else { + Log.e(TAG, "Error Parsing TAG_ADMIN_POLICY_ENTRY"); + } + break; + case TAG_POLICY_DEFINITION_ENTRY: + policyDefinition = PolicyDefinition.readFromXml(parser); + break; + + case TAG_RESOLVED_VALUE_ENTRY: + currentResolvedPolicy = policyDefinition.readPolicyValueFromXml(parser); + break; + default: + Log.e(TAG, "Unknown tag: " + tag); } } - return new PolicyState<V>(policyDefinition, policiesSetByAdmins, currentResolvedPolicy); + if (policyDefinition != null) { + return new PolicyState<V>(policyDefinition, policiesSetByAdmins, currentResolvedPolicy); + } else { + Log.e("PolicyState", "Error parsing policyState"); + return null; + } } + + PolicyDefinition<V> getPolicyDefinition() { return mPolicyDefinition; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/StringSetPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/StringSetPolicySerializer.java index dc6592d73116..24d0521471f7 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/StringSetPolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/StringSetPolicySerializer.java @@ -36,21 +36,17 @@ final class StringSetPolicySerializer extends PolicySerializer<Set<String>> { private static final String ATTR_VALUES_SEPARATOR = ";"; @Override - void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, String attributeNamePrefix, + void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, @NonNull Set<String> value) throws IOException { Objects.requireNonNull(value); serializer.attribute( - /* namespace= */ null, - attributeNamePrefix + ATTR_VALUES, - String.join(ATTR_VALUES_SEPARATOR, value)); + /* namespace= */ null, ATTR_VALUES, String.join(ATTR_VALUES_SEPARATOR, value)); } @Nullable @Override - PolicyValue<Set<String>> readFromXml(TypedXmlPullParser parser, String attributeNamePrefix) { - String valuesStr = parser.getAttributeValue( - /* namespace= */ null, - attributeNamePrefix + ATTR_VALUES); + PolicyValue<Set<String>> readFromXml(TypedXmlPullParser parser) { + String valuesStr = parser.getAttributeValue(/* namespace= */ null, ATTR_VALUES); if (valuesStr == null) { Log.e(DevicePolicyEngine.TAG, "Error parsing StringSet policy value."); return null; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 492d477fe23a..b1d613109e09 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -125,6 +125,7 @@ import com.android.server.compat.PlatformCompatNative; import com.android.server.connectivity.PacProxyService; import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.coverage.CoverageService; +import com.android.server.cpu.CpuMonitorService; import com.android.server.devicepolicy.DevicePolicyManagerService; import com.android.server.devicestate.DeviceStateManagerService; import com.android.server.display.DisplayManagerService; @@ -1405,6 +1406,15 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(RemoteProvisioningService.class); t.traceEnd(); + // TODO(b/277600174): Start CpuMonitorService on all builds and not just on debuggable + // builds once the Android JobScheduler starts using this service. + if (Build.IS_DEBUGGABLE || Build.IS_ENG) { + // Service for CPU monitor. + t.traceBegin("CpuMonitorService"); + mSystemServiceManager.startService(CpuMonitorService.class); + t.traceEnd(); + } + t.traceEnd(); // startCoreServices } diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java index 9829e57c6ef8..bb3a4766d249 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java @@ -36,7 +36,7 @@ import android.content.Context; import android.content.pm.PackageManagerInternal; import android.hardware.display.DisplayManagerInternal; import android.hardware.input.IInputManager; -import android.hardware.input.InputManager; +import android.hardware.input.InputManagerGlobal; import android.os.Binder; import android.os.IBinder; import android.os.Process; @@ -178,7 +178,7 @@ public class InputMethodManagerServiceTestBase { // Injecting and mocked InputMethodBindingController and InputMethod. mMockInputMethodInvoker = IInputMethodInvoker.create(mMockInputMethod); - InputManager.resetInstance(mMockIInputManager); + InputManagerGlobal.resetInstance(mMockIInputManager); synchronized (ImfLock.class) { when(mMockInputMethodBindingController.getCurMethod()) .thenReturn(mMockInputMethodInvoker); diff --git a/services/tests/PackageManagerServiceTests/TEST_MAPPING b/services/tests/PackageManagerServiceTests/TEST_MAPPING index e98acb2bb6a9..5d96af9df1fb 100644 --- a/services/tests/PackageManagerServiceTests/TEST_MAPPING +++ b/services/tests/PackageManagerServiceTests/TEST_MAPPING @@ -55,23 +55,10 @@ // TODO(b/204133664) "exclude-filter": "com.android.server.pm.test.SdCardEjectionTests" }, - { - // TODO(b/272575212) - "exclude-filter": "com.android.server.pm.test.SettingsTest#testWriteCorruptDataBinaryXml" - }, - { - "exclude-filter": "com.android.server.pm.test.SettingsTest#testWriteCorruptDataTextXml" - }, - { - "exclude-filter": "com.android.server.pm.test.SettingsTest#testWriteCorruptHeaderBinaryXml" - }, - { - "exclude-filter": "com.android.server.pm.test.SettingsTest#testWriteCorruptHeaderTextXml" - }, - { + { // TODO(b/272714903) "exclude-filter": "com.android.server.pm.test.OverlayPathsUninstallSystemUpdatesTest#verify" - } + } ] } ], diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java index 1a7517098d18..7b771aff0055 100644 --- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java @@ -567,36 +567,36 @@ public class RescuePartyTest { // Ensure that no action is taken for cases where the failure reason is unknown assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN, 1), - PackageHealthObserverImpact.USER_IMPACT_NONE); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_0); // Ensure the correct user impact is returned for each mitigation count. assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1), - PackageHealthObserverImpact.USER_IMPACT_LOW); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2), - PackageHealthObserverImpact.USER_IMPACT_LOW); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3), - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_50); assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4), - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_50); } @Test public void testBootLoopLevels() { RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); - assertEquals(observer.onBootLoop(0), PackageHealthObserverImpact.USER_IMPACT_NONE); - assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LOW); - assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LOW); - assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_HIGH); - assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_HIGH); - assertEquals(observer.onBootLoop(5), PackageHealthObserverImpact.USER_IMPACT_HIGH); + assertEquals(observer.onBootLoop(0), PackageHealthObserverImpact.USER_IMPACT_LEVEL_0); + assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); + assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); + assertEquals(observer.onBootLoop(3), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50); + assertEquals(observer.onBootLoop(4), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50); + assertEquals(observer.onBootLoop(5), PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); } @Test 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 318067ee8681..3fb7fb4e6aea 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -74,16 +74,17 @@ import android.os.BundleMerger; import android.os.DropBoxManager; import android.os.HandlerThread; import android.os.SystemClock; +import android.os.TestLooperManager; import android.os.UserHandle; import android.provider.Settings; import android.util.IndentingPrintWriter; import android.util.Pair; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.internal.util.FrameworkStatsLog; import com.android.server.ExtendedMockitoRule; -import com.android.server.am.BroadcastQueueTest.SyncBarrier; import org.junit.After; import org.junit.Before; @@ -96,6 +97,7 @@ import java.io.Writer; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; +import java.util.Objects; @SmallTest public final class BroadcastQueueModernImplTest { @@ -111,6 +113,7 @@ public final class BroadcastQueueModernImplTest { @Mock BroadcastProcessQueue mQueue4; HandlerThread mHandlerThread; + TestLooperManager mLooper; BroadcastConstants mConstants; BroadcastQueueModernImpl mImpl; @@ -127,6 +130,10 @@ public final class BroadcastQueueModernImplTest { mHandlerThread = new HandlerThread(getClass().getSimpleName()); mHandlerThread.start(); + // Pause all event processing until a test chooses to resume + mLooper = Objects.requireNonNull(InstrumentationRegistry.getInstrumentation() + .acquireLooperManager(mHandlerThread.getLooper())); + mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS); mConstants.DELAY_URGENT_MILLIS = -120_000; mConstants.DELAY_NORMAL_MILLIS = 10_000; @@ -167,6 +174,17 @@ public final class BroadcastQueueModernImplTest { mHandlerThread.quit(); } + /** + * Un-pause our handler to process pending events, wait for our queue to go + * idle, and then re-pause the handler. + */ + private void waitForIdle() throws Exception { + mLooper.release(); + mImpl.waitForIdle(LOG_WRITER_INFO); + mLooper = Objects.requireNonNull(InstrumentationRegistry.getInstrumentation() + .acquireLooperManager(mHandlerThread.getLooper())); + } + private static void assertOrphan(BroadcastProcessQueue queue) { assertNull(queue.runnableAtNext); assertNull(queue.runnableAtPrev); @@ -237,9 +255,23 @@ public final class BroadcastQueueModernImplTest { } private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, + BroadcastRecord record, int recordIndex) { + enqueueOrReplaceBroadcast(queue, record, recordIndex, false, 42_000_000L); + } + + private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, BroadcastRecord record, int recordIndex, long enqueueTime) { - queue.enqueueOrReplaceBroadcast(record, recordIndex, false); + enqueueOrReplaceBroadcast(queue, record, recordIndex, false, enqueueTime); + } + + private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, + BroadcastRecord record, int recordIndex, boolean wouldBeSkipped, long enqueueTime) { + queue.enqueueOrReplaceBroadcast(record, recordIndex, wouldBeSkipped, (r, i) -> { + throw new UnsupportedOperationException(); + }); record.enqueueTime = enqueueTime; + record.enqueueRealTime = enqueueTime; + record.enqueueClockTime = enqueueTime; } @Test @@ -370,7 +402,7 @@ public final class BroadcastQueueModernImplTest { .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, options, List.of(makeMockRegisteredReceiver()), false); - queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); queue.setProcessAndUidCached(null, false); final long notCachedRunnableAt = queue.getRunnableAt(); @@ -397,7 +429,7 @@ public final class BroadcastQueueModernImplTest { .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_NONE); final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, options, List.of(makeMockRegisteredReceiver()), false); - queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); queue.setProcessAndUidCached(null, false); final long notCachedRunnableAt = queue.getRunnableAt(); @@ -406,7 +438,7 @@ public final class BroadcastQueueModernImplTest { assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt); assertTrue(queue.isRunnable()); assertEquals(BroadcastProcessQueue.REASON_CACHED, queue.getRunnableAtReason()); - assertEquals(ProcessList.SCHED_GROUP_BACKGROUND, queue.getPreferredSchedulingGroupLocked()); + assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked()); } /** @@ -421,12 +453,12 @@ public final class BroadcastQueueModernImplTest { // enqueue a bg-priority broadcast then a fg-priority one final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED); final BroadcastRecord timezoneRecord = makeBroadcastRecord(timezone); - queue.enqueueOrReplaceBroadcast(timezoneRecord, 0, false); + enqueueOrReplaceBroadcast(queue, timezoneRecord, 0); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane); - queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); // verify that: // (a) the queue is immediately runnable by existence of a fg-priority broadcast @@ -434,13 +466,13 @@ public final class BroadcastQueueModernImplTest { queue.setProcessAndUidCached(null, false); assertTrue(queue.isRunnable()); assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime); - assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked()); + assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked()); assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord); queue.setProcessAndUidCached(null, true); assertTrue(queue.isRunnable()); assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime); - assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked()); + assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked()); assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord); } @@ -457,13 +489,14 @@ public final class BroadcastQueueModernImplTest { final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, null, List.of(withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10), withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 0)), true); - queue.enqueueOrReplaceBroadcast(airplaneRecord, 1, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 1); assertFalse(queue.isRunnable()); assertEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason()); // Bumping past barrier makes us now runnable - airplaneRecord.terminalCount++; + airplaneRecord.setDeliveryState(0, BroadcastRecord.DELIVERY_DELIVERED, + "testRunnableAt_Ordered"); queue.invalidateRunnableAt(); assertTrue(queue.isRunnable()); assertNotEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason()); @@ -480,7 +513,7 @@ public final class BroadcastQueueModernImplTest { final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, List.of(makeMockRegisteredReceiver())); - queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); mConstants.MAX_PENDING_BROADCASTS = 128; queue.invalidateRunnableAt(); @@ -506,11 +539,11 @@ public final class BroadcastQueueModernImplTest { new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of(makeMockRegisteredReceiver())); - queue.enqueueOrReplaceBroadcast(lazyRecord, 0, false); + enqueueOrReplaceBroadcast(queue, lazyRecord, 0); assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime); assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason); - queue.enqueueOrReplaceBroadcast(testRecord, 0, false); + enqueueOrReplaceBroadcast(queue, testRecord, 0); assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime); assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason); } @@ -572,22 +605,22 @@ public final class BroadcastQueueModernImplTest { BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN)); - queue.enqueueOrReplaceBroadcast( + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false); - queue.enqueueOrReplaceBroadcast( - makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0, false); - queue.enqueueOrReplaceBroadcast( + .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0); + enqueueOrReplaceBroadcast(queue, + makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false); - queue.enqueueOrReplaceBroadcast( + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false); - queue.enqueueOrReplaceBroadcast( - makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, false); - queue.enqueueOrReplaceBroadcast( + .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0); + enqueueOrReplaceBroadcast(queue, + makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false); + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0); queue.makeActiveNextPending(); assertEquals(Intent.ACTION_LOCKED_BOOT_COMPLETED, queue.getActive().intent.getAction()); @@ -821,9 +854,6 @@ public final class BroadcastQueueModernImplTest { optionsAlarmVolumeChanged.setDeliveryGroupMatchingKey("audio", String.valueOf(AudioManager.STREAM_ALARM)); - // Halt all processing so that we get a consistent view - mHandlerThread.getLooper().getQueue().postSyncBarrier(); - mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged, optionsMusicVolumeChanged)); @@ -890,9 +920,6 @@ public final class BroadcastQueueModernImplTest { String.valueOf(TEST_UID2)); optionsPackageChangedForUid.setDeliveryGroupExtrasMerger(extrasMerger); - // Halt all processing so that we get a consistent view - mHandlerThread.getLooper().getQueue().postSyncBarrier(); - mImpl.enqueueBroadcastLocked(makeBroadcastRecord(packageChangedForUid, optionsPackageChangedForUid)); mImpl.enqueueBroadcastLocked(makeBroadcastRecord(packageChangedForUid2, @@ -940,9 +967,6 @@ public final class BroadcastQueueModernImplTest { BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT); optionsAlarmVolumeChanged.setDeliveryGroupMatchingFilter(filterAlarmVolumeChanged); - // Halt all processing so that we get a consistent view - mHandlerThread.getLooper().getQueue().postSyncBarrier(); - mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged, optionsMusicVolumeChanged)); @@ -989,9 +1013,6 @@ public final class BroadcastQueueModernImplTest { final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast3 = createDropboxBroadcast( "TAG_A", now + 2000, 7); - // Halt all processing so that we get a consistent view - mHandlerThread.getLooper().getQueue().postSyncBarrier(); - mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast1.first, dropboxEntryBroadcast1.second)); mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast2.first, @@ -1021,9 +1042,6 @@ public final class BroadcastQueueModernImplTest { .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( @@ -1073,9 +1091,6 @@ public final class BroadcastQueueModernImplTest { final Intent userPresent = new Intent(Intent.ACTION_USER_PRESENT); userPresent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - // Halt all processing so that we get a consistent view - mHandlerThread.getLooper().getQueue().postSyncBarrier(); - final BroadcastRecord userPresentRecord1 = makeBroadcastRecord(userPresent); final BroadcastRecord userPresentRecord2 = makeBroadcastRecord(userPresent); @@ -1114,8 +1129,6 @@ public final class BroadcastQueueModernImplTest { makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW) )); - // Halt all processing so that we get a consistent view - mHandlerThread.getLooper().getQueue().postSyncBarrier(); mImpl.enqueueBroadcastLocked(record1); mImpl.enqueueBroadcastLocked(record2); @@ -1137,12 +1150,9 @@ public final class BroadcastQueueModernImplTest { final BroadcastOptions optionsTimeTick = BroadcastOptions.makeBasic(); optionsTimeTick.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT); - // Halt all processing so that we get a consistent view - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); - mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); - } - mImpl.waitForIdle(LOG_WRITER_INFO); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); + mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick)); + waitForIdle(); // Verify that there is only one delivery event reported since one of the broadcasts // should have been skipped. @@ -1154,6 +1164,41 @@ public final class BroadcastQueueModernImplTest { times(1)); } + @Test + public void testGetPreferredSchedulingGroup() throws Exception { + final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, + PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN)); + + assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked()); + + final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(timeTick, + List.of(makeMockRegisteredReceiver())), 0); + assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked()); + + // Make the foreground broadcast as active. + queue.makeActiveNextPending(); + assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked()); + + queue.makeActiveIdle(); + assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked()); + + final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(airplane, + List.of(makeMockRegisteredReceiver())), 0); + + // Make the background broadcast as active. + queue.makeActiveNextPending(); + assertEquals(ProcessList.SCHED_GROUP_BACKGROUND, queue.getPreferredSchedulingGroupLocked()); + + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(timeTick, + List.of(makeMockRegisteredReceiver())), 0); + // Even though the active broadcast is not a foreground one, scheduling group will be + // DEFAULT since there is a foreground broadcast waiting to be delivered. + assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked()); + } + private Intent createPackageChangedIntent(int uid, List<String> componentNameList) { final Intent packageChangedIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED); packageChangedIntent.putExtra(Intent.EXTRA_UID, uid); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java index b6bc02a41c21..7be1d7cde27f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -16,6 +16,8 @@ package com.android.server.am; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER; import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO; @@ -39,7 +41,6 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -76,6 +77,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.PowerExemptionManager; import android.os.SystemClock; +import android.os.TestLooperManager; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; @@ -145,6 +147,7 @@ public class BroadcastQueueTest { private Context mContext; private HandlerThread mHandlerThread; + private TestLooperManager mLooper; private AtomicInteger mNextPid; @Mock @@ -205,6 +208,11 @@ public class BroadcastQueueTest { mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); + + // Pause all event processing until a test chooses to resume + mLooper = Objects.requireNonNull(InstrumentationRegistry.getInstrumentation() + .acquireLooperManager(mHandlerThread.getLooper())); + mNextPid = new AtomicInteger(100); LocalServices.removeServiceForTest(DropBoxManagerInternal.class); @@ -359,25 +367,6 @@ public class BroadcastQueueTest { } } - /** - * Helper that leverages try-with-resources to pause dispatch of - * {@link #mHandlerThread} until released. - */ - static class SyncBarrier implements AutoCloseable { - private final int mToken; - private HandlerThread mThread; - - SyncBarrier(HandlerThread thread) { - mThread = thread; - mToken = mThread.getLooper().getQueue().postSyncBarrier(); - } - - @Override - public void close() throws Exception { - mThread.getLooper().getQueue().removeSyncBarrier(mToken); - } - } - private enum ProcessStartBehavior { /** Process starts successfully */ SUCCESS, @@ -463,7 +452,7 @@ public class BroadcastQueueTest { doAnswer((invocation) -> { Log.v(TAG, "Intercepting scheduleReceiver() for " - + Arrays.toString(invocation.getArguments())); + + Arrays.toString(invocation.getArguments()) + " package " + ai.packageName); assertHealth(); final Intent intent = invocation.getArgument(0); final Bundle extras = invocation.getArgument(5); @@ -485,7 +474,7 @@ public class BroadcastQueueTest { doAnswer((invocation) -> { Log.v(TAG, "Intercepting scheduleRegisteredReceiver() for " - + Arrays.toString(invocation.getArguments())); + + Arrays.toString(invocation.getArguments()) + " package " + ai.packageName); assertHealth(); final Intent intent = invocation.getArgument(1); final Bundle extras = invocation.getArgument(4); @@ -670,8 +659,15 @@ public class BroadcastQueueTest { } } + /** + * Un-pause our handler to process pending events, wait for our queue to go + * idle, and then re-pause the handler. + */ private void waitForIdle() throws Exception { + mLooper.release(); mQueue.waitForIdle(LOG_WRITER_INFO); + mLooper = Objects.requireNonNull(InstrumentationRegistry.getInstrumentation() + .acquireLooperManager(mHandlerThread.getLooper())); } private void verifyScheduleReceiver(ProcessRecord app, Intent intent) throws Exception { @@ -961,7 +957,7 @@ public class BroadcastQueueTest { } else { // Confirm that app was thawed verify(mAms.mOomAdjuster, atLeastOnce()).unfreezeTemporarily( - eq(receiverApp), eq(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER)); + eq(receiverApp), eq(OOM_ADJ_REASON_START_RECEIVER)); // Confirm that we added package to process verify(receiverApp, atLeastOnce()).addPackage(eq(receiverApp.info.packageName), @@ -1155,23 +1151,21 @@ public class BroadcastQueueTest { final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, new ArrayList<>( - List.of(makeRegisteredReceiver(receiverApp), - makeManifestReceiver(PACKAGE_GREEN, CLASS_RED), - makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), - makeManifestReceiver(PACKAGE_GREEN, CLASS_BLUE))))); - - synchronized (mAms) { - mQueue.cleanupDisabledPackageReceiversLocked(PACKAGE_GREEN, Set.of(CLASS_GREEN), - UserHandle.USER_SYSTEM); - - // Also try clearing out other unrelated things that should leave - // the final receiver intact - mQueue.cleanupDisabledPackageReceiversLocked(PACKAGE_RED, null, - UserHandle.USER_SYSTEM); - mQueue.cleanupDisabledPackageReceiversLocked(null, null, USER_GUEST); - } + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, new ArrayList<>( + List.of(makeRegisteredReceiver(receiverApp), + makeManifestReceiver(PACKAGE_GREEN, CLASS_RED), + makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), + makeManifestReceiver(PACKAGE_GREEN, CLASS_BLUE))))); + + synchronized (mAms) { + mQueue.cleanupDisabledPackageReceiversLocked(PACKAGE_GREEN, Set.of(CLASS_GREEN), + UserHandle.USER_SYSTEM); + + // Also try clearing out other unrelated things that should leave + // the final receiver intact + mQueue.cleanupDisabledPackageReceiversLocked(PACKAGE_RED, null, + UserHandle.USER_SYSTEM); + mQueue.cleanupDisabledPackageReceiversLocked(null, null, USER_GUEST); // To maximize test coverage, dump current state; we're not worried // about the actual output, just that we don't crash @@ -1199,21 +1193,19 @@ public class BroadcastQueueTest { final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final Intent timeZone = new Intent(Intent.ACTION_TIMEZONE_CHANGED); - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, USER_GUEST, new ArrayList<>( - List.of(makeRegisteredReceiver(callerApp), - makeManifestReceiver(PACKAGE_GREEN, CLASS_RED, USER_GUEST), - makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN, USER_GUEST), - makeManifestReceiver(PACKAGE_YELLOW, CLASS_BLUE, USER_GUEST))))); - enqueueBroadcast(makeBroadcastRecord(timeZone, callerApp, USER_GUEST, new ArrayList<>( - List.of(makeRegisteredReceiver(callerApp), - makeManifestReceiver(PACKAGE_GREEN, CLASS_RED, USER_GUEST), - makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN, USER_GUEST), - makeManifestReceiver(PACKAGE_YELLOW, CLASS_BLUE, USER_GUEST))))); - - synchronized (mAms) { - mQueue.cleanupDisabledPackageReceiversLocked(null, null, USER_GUEST); - } + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, USER_GUEST, new ArrayList<>( + List.of(makeRegisteredReceiver(callerApp), + makeManifestReceiver(PACKAGE_GREEN, CLASS_RED, USER_GUEST), + makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN, USER_GUEST), + makeManifestReceiver(PACKAGE_YELLOW, CLASS_BLUE, USER_GUEST))))); + enqueueBroadcast(makeBroadcastRecord(timeZone, callerApp, USER_GUEST, new ArrayList<>( + List.of(makeRegisteredReceiver(callerApp), + makeManifestReceiver(PACKAGE_GREEN, CLASS_RED, USER_GUEST), + makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN, USER_GUEST), + makeManifestReceiver(PACKAGE_YELLOW, CLASS_BLUE, USER_GUEST))))); + + synchronized (mAms) { + mQueue.cleanupDisabledPackageReceiversLocked(null, null, USER_GUEST); } waitForIdle(); @@ -1239,15 +1231,12 @@ public class BroadcastQueueTest { final ProcessRecord oldApp = makeActiveProcessRecord(PACKAGE_GREEN); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, new ArrayList<>( - List.of(makeRegisteredReceiver(oldApp), - makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))))); - - synchronized (mAms) { - oldApp.killLocked(TAG, 42, false); - mQueue.onApplicationCleanupLocked(oldApp); - } + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, new ArrayList<>( + List.of(makeRegisteredReceiver(oldApp), + makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))))); + synchronized (mAms) { + oldApp.killLocked(TAG, 42, false); + mQueue.onApplicationCleanupLocked(oldApp); } waitForIdle(); @@ -1404,7 +1393,7 @@ public class BroadcastQueueTest { // Finally, verify that we thawed the final receiver verify(mAms.mOomAdjuster).unfreezeTemporarily(eq(callerApp), - eq(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER)); + eq(OOM_ADJ_REASON_FINISH_RECEIVER)); } /** @@ -1620,17 +1609,14 @@ public class BroadcastQueueTest { final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - enqueueBroadcast(makeBroadcastRecord(timezone, callerApp, - List.of(makeRegisteredReceiver(receiverBlueApp, 10), - makeRegisteredReceiver(receiverGreenApp, 10), - makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), - makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW), - makeRegisteredReceiver(receiverYellowApp, -10)))); - enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, - List.of(makeRegisteredReceiver(receiverBlueApp)))); - } - + enqueueBroadcast(makeBroadcastRecord(timezone, callerApp, + List.of(makeRegisteredReceiver(receiverBlueApp, 10), + makeRegisteredReceiver(receiverGreenApp, 10), + makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), + makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW), + makeRegisteredReceiver(receiverYellowApp, -10)))); + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, + List.of(makeRegisteredReceiver(receiverBlueApp)))); waitForIdle(); // Ignore the final foreground broadcast @@ -1744,17 +1730,15 @@ public class BroadcastQueueTest { final IIntentReceiver resultToFirst = mock(IIntentReceiver.class); final IIntentReceiver resultToSecond = mock(IIntentReceiver.class); - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - enqueueBroadcast(makeOrderedBroadcastRecord(timezoneFirst, callerApp, - List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), - makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN)), - resultToFirst, null)); - enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, - List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_RED)))); - enqueueBroadcast(makeOrderedBroadcastRecord(timezoneSecond, callerApp, - List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN)), - resultToSecond, null)); - } + enqueueBroadcast(makeOrderedBroadcastRecord(timezoneFirst, callerApp, + List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), + makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN)), + resultToFirst, null)); + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, + List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_RED)))); + enqueueBroadcast(makeOrderedBroadcastRecord(timezoneSecond, callerApp, + List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN)), + resultToSecond, null)); waitForIdle(); final IApplicationThread blueThread = mAms.getProcessRecordLocked(PACKAGE_BLUE, @@ -1835,14 +1819,12 @@ public class BroadcastQueueTest { timeTickFirst.putExtra(Intent.EXTRA_INDEX, "third"); timeTickThird.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - enqueueBroadcast(makeBroadcastRecord(timeTickFirst, callerApp, - List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE)))); - enqueueBroadcast(makeBroadcastRecord(timeTickSecond, callerApp, - List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE)))); - enqueueBroadcast(makeBroadcastRecord(timeTickThird, callerApp, - List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE)))); - } + enqueueBroadcast(makeBroadcastRecord(timeTickFirst, callerApp, + List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE)))); + enqueueBroadcast(makeBroadcastRecord(timeTickSecond, callerApp, + List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE)))); + enqueueBroadcast(makeBroadcastRecord(timeTickThird, callerApp, + List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE)))); waitForIdle(); final IApplicationThread blueThread = mAms.getProcessRecordLocked(PACKAGE_BLUE, @@ -1877,26 +1859,26 @@ public class BroadcastQueueTest { assertTrue(mQueue.isIdleLocked()); assertTrue(mQueue.isBeyondBarrierLocked(beforeFirst)); - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED); - enqueueBroadcast(makeBroadcastRecord(timezone, callerApp, - List.of(makeRegisteredReceiver(receiverApp)))); - afterFirst = SystemClock.uptimeMillis(); - - assertFalse(mQueue.isIdleLocked()); - assertTrue(mQueue.isBeyondBarrierLocked(beforeFirst)); - assertFalse(mQueue.isBeyondBarrierLocked(afterFirst)); - - final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, - List.of(makeRegisteredReceiver(receiverApp)))); - afterSecond = SystemClock.uptimeMillis() + 10; - - assertFalse(mQueue.isIdleLocked()); - assertTrue(mQueue.isBeyondBarrierLocked(beforeFirst)); - assertFalse(mQueue.isBeyondBarrierLocked(afterFirst)); - assertFalse(mQueue.isBeyondBarrierLocked(afterSecond)); - } + final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED); + enqueueBroadcast(makeBroadcastRecord(timezone, callerApp, + List.of(makeRegisteredReceiver(receiverApp)))); + afterFirst = SystemClock.uptimeMillis(); + + assertFalse(mQueue.isIdleLocked()); + assertTrue(mQueue.isBeyondBarrierLocked(beforeFirst)); + assertFalse(mQueue.isBeyondBarrierLocked(afterFirst)); + + final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, + List.of(makeRegisteredReceiver(receiverApp)))); + afterSecond = SystemClock.uptimeMillis() + 10; + + assertFalse(mQueue.isIdleLocked()); + assertTrue(mQueue.isBeyondBarrierLocked(beforeFirst)); + assertFalse(mQueue.isBeyondBarrierLocked(afterFirst)); + assertFalse(mQueue.isBeyondBarrierLocked(afterSecond)); + + mLooper.release(); mQueue.waitForBarrier(LOG_WRITER_INFO); assertTrue(mQueue.isBeyondBarrierLocked(afterFirst)); @@ -1980,6 +1962,46 @@ public class BroadcastQueueTest { } /** + * Confirm how many times a pathological broadcast pattern results in OOM + * adjusts; watches for performance regressions. + */ + @Test + public void testOomAdjust_TriggerCount() throws Exception { + final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED); + + // Send 8 broadcasts, 4 receivers in the first process, + // and 2 alternating in each of the remaining processes + synchronized (mAms) { + for (int i = 0; i < 8; i++) { + final Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); + mQueue.enqueueBroadcastLocked(makeBroadcastRecord(intent, callerApp, + List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), + makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), + makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), + makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), + makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), + makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW), + makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), + makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW)))); + } + } + waitForIdle(); + + final int expectedTimes; + switch (mImpl) { + // Original stack requested for every single receiver; yikes + case DEFAULT: expectedTimes = 64; break; + // Modern stack requests once each time we promote a process to + // running; we promote "green" twice, and "blue" and "yellow" once + case MODERN: expectedTimes = 4; break; + default: throw new UnsupportedOperationException(); + } + + verify(mAms, times(expectedTimes)) + .updateOomAdjPendingTargetsLocked(eq(OOM_ADJ_REASON_START_RECEIVER)); + } + + /** * Verify that expected events are triggered when a broadcast is finished. */ @Test @@ -2007,25 +2029,23 @@ public class BroadcastQueueTest { final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - try (SyncBarrier b = new SyncBarrier(mHandlerThread)) { - final Object greenReceiver = makeRegisteredReceiver(receiverGreenApp); - final Object blueReceiver = makeRegisteredReceiver(receiverBlueApp); - final Object yellowReceiver = makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW); - final Object orangeReceiver = makeManifestReceiver(PACKAGE_ORANGE, CLASS_ORANGE); - enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, - List.of(greenReceiver, blueReceiver, yellowReceiver, orangeReceiver))); - - doAnswer(invocation -> { - final BroadcastRecord r = invocation.getArgument(0); - final Object o = invocation.getArgument(1); - if (airplane.getAction().equals(r.intent.getAction()) - && (isReceiverEquals(o, greenReceiver) - || isReceiverEquals(o, orangeReceiver))) { - return "test skipped receiver"; - } - return null; - }).when(mSkipPolicy).shouldSkipMessage(any(BroadcastRecord.class), any()); - } + final Object greenReceiver = makeRegisteredReceiver(receiverGreenApp); + final Object blueReceiver = makeRegisteredReceiver(receiverBlueApp); + final Object yellowReceiver = makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW); + final Object orangeReceiver = makeManifestReceiver(PACKAGE_ORANGE, CLASS_ORANGE); + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, + List.of(greenReceiver, blueReceiver, yellowReceiver, orangeReceiver))); + + doAnswer(invocation -> { + final BroadcastRecord r = invocation.getArgument(0); + final Object o = invocation.getArgument(1); + if (airplane.getAction().equals(r.intent.getAction()) + && (isReceiverEquals(o, greenReceiver) + || isReceiverEquals(o, orangeReceiver))) { + return "test skipped receiver"; + } + return null; + }).when(mSkipPolicy).shouldSkipMessage(any(BroadcastRecord.class), any()); waitForIdle(); // Verify that only blue and yellow receiver apps received the broadcast. diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java index 2b6f2174d49b..08952eab071f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java @@ -24,7 +24,12 @@ import static android.content.Intent.ACTION_TIME_CHANGED; import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_ALL; import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY; import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_NONE; -import static com.android.server.am.BroadcastRecord.calculateBlockedUntilTerminalCount; +import static com.android.server.am.BroadcastRecord.DELIVERY_DEFERRED; +import static com.android.server.am.BroadcastRecord.DELIVERY_DELIVERED; +import static com.android.server.am.BroadcastRecord.DELIVERY_PENDING; +import static com.android.server.am.BroadcastRecord.DELIVERY_SKIPPED; +import static com.android.server.am.BroadcastRecord.DELIVERY_TIMEOUT; +import static com.android.server.am.BroadcastRecord.calculateBlockedUntilBeyondCount; import static com.android.server.am.BroadcastRecord.calculateDeferUntilActive; import static com.android.server.am.BroadcastRecord.calculateUrgent; import static com.android.server.am.BroadcastRecord.isReceiverEquals; @@ -58,7 +63,6 @@ import androidx.test.filters.SmallTest; import com.android.server.am.BroadcastDispatcher.DeferredBootCompletedBroadcastPerUser; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -79,6 +83,7 @@ import java.util.function.BiFunction; @SmallTest @RunWith(MockitoJUnitRunner.class) public class BroadcastRecordTest { + private static final String TAG = "BroadcastRecordTest"; private static final int USER0 = UserHandle.USER_SYSTEM; private static final int USER1 = USER0 + 1; @@ -120,13 +125,13 @@ public class BroadcastRecordTest { assertFalse(isPrioritized(List.of(createResolveInfo(PACKAGE1, getAppId(1), 10)))); assertArrayEquals(new int[] {-1}, - calculateBlockedUntilTerminalCount(List.of( + calculateBlockedUntilBeyondCount(List.of( createResolveInfo(PACKAGE1, getAppId(1), 0)), false)); assertArrayEquals(new int[] {-1}, - calculateBlockedUntilTerminalCount(List.of( + calculateBlockedUntilBeyondCount(List.of( createResolveInfo(PACKAGE1, getAppId(1), -10)), false)); assertArrayEquals(new int[] {-1}, - calculateBlockedUntilTerminalCount(List.of( + calculateBlockedUntilBeyondCount(List.of( createResolveInfo(PACKAGE1, getAppId(1), 10)), false)); } @@ -142,12 +147,12 @@ public class BroadcastRecordTest { createResolveInfo(PACKAGE3, getAppId(3), 10)))); assertArrayEquals(new int[] {-1,-1,-1}, - calculateBlockedUntilTerminalCount(List.of( + calculateBlockedUntilBeyondCount(List.of( createResolveInfo(PACKAGE1, getAppId(1), 0), createResolveInfo(PACKAGE2, getAppId(2), 0), createResolveInfo(PACKAGE3, getAppId(3), 0)), false)); assertArrayEquals(new int[] {-1,-1,-1}, - calculateBlockedUntilTerminalCount(List.of( + calculateBlockedUntilBeyondCount(List.of( createResolveInfo(PACKAGE1, getAppId(1), 10), createResolveInfo(PACKAGE2, getAppId(2), 10), createResolveInfo(PACKAGE3, getAppId(3), 10)), false)); @@ -156,26 +161,176 @@ public class BroadcastRecordTest { @Test public void testIsPrioritized_Yes() { assertTrue(isPrioritized(List.of( - createResolveInfo(PACKAGE1, getAppId(1), -10), + createResolveInfo(PACKAGE1, getAppId(1), 10), createResolveInfo(PACKAGE2, getAppId(2), 0), - createResolveInfo(PACKAGE3, getAppId(3), 10)))); + createResolveInfo(PACKAGE3, getAppId(3), -10)))); assertTrue(isPrioritized(List.of( - createResolveInfo(PACKAGE1, getAppId(1), 0), + createResolveInfo(PACKAGE1, getAppId(1), 10), createResolveInfo(PACKAGE2, getAppId(2), 0), - createResolveInfo(PACKAGE3, getAppId(3), 10)))); + createResolveInfo(PACKAGE3, getAppId(3), 0)))); assertArrayEquals(new int[] {0,1,2}, - calculateBlockedUntilTerminalCount(List.of( - createResolveInfo(PACKAGE1, getAppId(1), -10), + calculateBlockedUntilBeyondCount(List.of( + createResolveInfo(PACKAGE1, getAppId(1), 10), createResolveInfo(PACKAGE2, getAppId(2), 0), - createResolveInfo(PACKAGE3, getAppId(3), 10)), false)); + createResolveInfo(PACKAGE3, getAppId(3), -10)), false)); assertArrayEquals(new int[] {0,0,2,3,3}, - calculateBlockedUntilTerminalCount(List.of( - createResolveInfo(PACKAGE1, getAppId(1), 0), - createResolveInfo(PACKAGE2, getAppId(2), 0), + calculateBlockedUntilBeyondCount(List.of( + createResolveInfo(PACKAGE1, getAppId(1), 20), + createResolveInfo(PACKAGE2, getAppId(2), 20), createResolveInfo(PACKAGE3, getAppId(3), 10), - createResolveInfo(PACKAGE3, getAppId(3), 20), - createResolveInfo(PACKAGE3, getAppId(3), 20)), false)); + createResolveInfo(PACKAGE3, getAppId(3), 0), + createResolveInfo(PACKAGE3, getAppId(3), 0)), false)); + } + + @Test + public void testSetDeliveryState_Single() { + final BroadcastRecord r = createBroadcastRecord( + new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of( + createResolveInfoWithPriority(0))); + assertEquals(DELIVERY_PENDING, r.getDeliveryState(0)); + assertBlocked(r, false); + assertTerminalDeferredBeyond(r, 0, 0, 0); + + r.setDeliveryState(0, DELIVERY_DEFERRED, TAG); + assertEquals(DELIVERY_DEFERRED, r.getDeliveryState(0)); + assertBlocked(r, false); + assertTerminalDeferredBeyond(r, 0, 1, 1); + + // Identical state change has no effect + r.setDeliveryState(0, DELIVERY_DEFERRED, TAG); + assertEquals(DELIVERY_DEFERRED, r.getDeliveryState(0)); + assertBlocked(r, false); + assertTerminalDeferredBeyond(r, 0, 1, 1); + + // Moving to terminal state updates counters + r.setDeliveryState(0, DELIVERY_DELIVERED, TAG); + assertEquals(DELIVERY_DELIVERED, r.getDeliveryState(0)); + assertBlocked(r, false); + assertTerminalDeferredBeyond(r, 1, 0, 1); + + // Trying to change terminal state has no effect + r.setDeliveryState(0, DELIVERY_TIMEOUT, TAG); + assertEquals(DELIVERY_DELIVERED, r.getDeliveryState(0)); + assertBlocked(r, false); + assertTerminalDeferredBeyond(r, 1, 0, 1); + } + + @Test + public void testSetDeliveryState_Unordered() { + final BroadcastRecord r = createBroadcastRecord( + new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of( + createResolveInfoWithPriority(0), + createResolveInfoWithPriority(0), + createResolveInfoWithPriority(0))); + assertBlocked(r, false, false, false); + assertTerminalDeferredBeyond(r, 0, 0, 0); + + // Even though we finish a middle item in the tranche, we're not + // "beyond" it because there is still unfinished work before it + r.setDeliveryState(1, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false); + assertTerminalDeferredBeyond(r, 1, 0, 0); + + r.setDeliveryState(0, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false); + assertTerminalDeferredBeyond(r, 2, 0, 2); + + r.setDeliveryState(2, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false); + assertTerminalDeferredBeyond(r, 3, 0, 3); + } + + @Test + public void testSetDeliveryState_Ordered() { + final BroadcastRecord r = createOrderedBroadcastRecord( + new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of( + createResolveInfoWithPriority(0), + createResolveInfoWithPriority(0), + createResolveInfoWithPriority(0))); + assertBlocked(r, false, true, true); + assertTerminalDeferredBeyond(r, 0, 0, 0); + + r.setDeliveryState(0, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, true); + assertTerminalDeferredBeyond(r, 1, 0, 1); + + r.setDeliveryState(1, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false); + assertTerminalDeferredBeyond(r, 2, 0, 2); + + r.setDeliveryState(2, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false); + assertTerminalDeferredBeyond(r, 3, 0, 3); + } + + @Test + public void testSetDeliveryState_DeferUntilActive() { + final BroadcastRecord r = createBroadcastRecord( + new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of( + createResolveInfoWithPriority(10), + createResolveInfoWithPriority(10), + createResolveInfoWithPriority(10), + createResolveInfoWithPriority(0), + createResolveInfoWithPriority(0), + createResolveInfoWithPriority(0), + createResolveInfoWithPriority(-10), + createResolveInfoWithPriority(-10), + createResolveInfoWithPriority(-10))); + assertBlocked(r, false, false, false, true, true, true, true, true, true); + assertTerminalDeferredBeyond(r, 0, 0, 0); + + r.setDeliveryState(0, DELIVERY_PENDING, TAG); + r.setDeliveryState(1, DELIVERY_DEFERRED, TAG); + r.setDeliveryState(2, DELIVERY_PENDING, TAG); + r.setDeliveryState(3, DELIVERY_DEFERRED, TAG); + r.setDeliveryState(4, DELIVERY_DEFERRED, TAG); + r.setDeliveryState(5, DELIVERY_DEFERRED, TAG); + r.setDeliveryState(6, DELIVERY_DEFERRED, TAG); + r.setDeliveryState(7, DELIVERY_PENDING, TAG); + r.setDeliveryState(8, DELIVERY_DEFERRED, TAG); + + // Verify deferred counts ratchet up, but we're not "beyond" the first + // still-pending receiver + assertBlocked(r, false, false, false, true, true, true, true, true, true); + assertTerminalDeferredBeyond(r, 0, 6, 0); + + // We're still not "beyond" the first still-pending receiver, even when + // we finish a receiver later in the first tranche + r.setDeliveryState(2, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false, true, true, true, true, true, true); + assertTerminalDeferredBeyond(r, 1, 6, 0); + + // Completing that last item in first tranche means we now unblock the + // second tranche, and since it's entirely deferred, the third traunche + // is unblocked too + r.setDeliveryState(0, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false, false, false, false, false, false, false); + assertTerminalDeferredBeyond(r, 2, 6, 7); + + // Moving a deferred item in an earlier tranche back to being pending + // doesn't change the fact that we've already moved beyond it + r.setDeliveryState(1, DELIVERY_PENDING, TAG); + assertBlocked(r, false, false, false, false, false, false, false, false, false); + assertTerminalDeferredBeyond(r, 2, 5, 7); + r.setDeliveryState(1, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false, false, false, false, false, false, false); + assertTerminalDeferredBeyond(r, 3, 5, 7); + + // Completing middle pending item is enough to fast-forward to end + r.setDeliveryState(7, DELIVERY_DELIVERED, TAG); + assertBlocked(r, false, false, false, false, false, false, false, false, false); + assertTerminalDeferredBeyond(r, 4, 5, 9); + + // Moving everyone else directly into a finished state updates all the + // terminal counters + r.setDeliveryState(3, DELIVERY_SKIPPED, TAG); + r.setDeliveryState(4, DELIVERY_SKIPPED, TAG); + r.setDeliveryState(5, DELIVERY_SKIPPED, TAG); + r.setDeliveryState(6, DELIVERY_SKIPPED, TAG); + r.setDeliveryState(8, DELIVERY_SKIPPED, TAG); + assertBlocked(r, false, false, false, false, false, false, false, false, false); + assertTerminalDeferredBeyond(r, 9, 0, 9); } @Test @@ -688,6 +843,10 @@ public class BroadcastRecordTest { : errorMsg.insert(0, "Contains unexpected receiver: ").toString(); } + private static ResolveInfo createResolveInfoWithPriority(int priority) { + return createResolveInfo(PACKAGE1, getAppId(1), priority); + } + private static ResolveInfo createResolveInfo(String packageName, int uid) { return createResolveInfo(packageName, uid, 0); } @@ -738,21 +897,40 @@ public class BroadcastRecordTest { return excludedList; } + private BroadcastRecord createBroadcastRecord(Intent intent, + List<ResolveInfo> receivers) { + return createBroadcastRecord(receivers, USER0, intent, null /* filterExtrasForReceiver */, + null /* options */, false); + } + + private BroadcastRecord createOrderedBroadcastRecord(Intent intent, + List<ResolveInfo> receivers) { + return createBroadcastRecord(receivers, USER0, intent, null /* filterExtrasForReceiver */, + null /* options */, true); + } + private BroadcastRecord createBroadcastRecord(List<ResolveInfo> receivers, int userId, Intent intent) { return createBroadcastRecord(receivers, userId, intent, null /* filterExtrasForReceiver */, - null /* options */); + null /* options */, false); } private BroadcastRecord createBroadcastRecord(List<ResolveInfo> receivers, int userId, Intent intent, BroadcastOptions options) { return createBroadcastRecord(receivers, userId, intent, null /* filterExtrasForReceiver */, - options); + options, false); } private BroadcastRecord createBroadcastRecord(List<ResolveInfo> receivers, int userId, Intent intent, BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver, BroadcastOptions options) { + return createBroadcastRecord(receivers, userId, intent, filterExtrasForReceiver, + options, false); + } + + private BroadcastRecord createBroadcastRecord(List<ResolveInfo> receivers, int userId, + Intent intent, BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver, + BroadcastOptions options, boolean ordered) { return new BroadcastRecord( mQueue /* queue */, intent, @@ -774,7 +952,7 @@ public class BroadcastRecordTest { 0 /* resultCode */, null /* resultData */, null /* resultExtras */, - false /* serialized */, + ordered /* serialized */, false /* sticky */, false /* initialSticky */, userId, @@ -789,6 +967,20 @@ public class BroadcastRecordTest { private static boolean isPrioritized(List<Object> receivers) { return BroadcastRecord.isPrioritized( - calculateBlockedUntilTerminalCount(receivers, false), false); + calculateBlockedUntilBeyondCount(receivers, false), false); + } + + private static void assertBlocked(BroadcastRecord r, boolean... blocked) { + assertEquals(r.receivers.size(), blocked.length); + for (int i = 0; i < blocked.length; i++) { + assertEquals("blocked " + i, blocked[i], r.isBlocked(i)); + } + } + + private static void assertTerminalDeferredBeyond(BroadcastRecord r, + int expectedTerminalCount, int expectedDeferredCount, int expectedBeyondCount) { + assertEquals("terminal", expectedTerminalCount, r.terminalCount); + assertEquals("deferred", expectedDeferredCount, r.deferredCount); + assertEquals("beyond", expectedBeyondCount, r.beyondCount); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 485ce33dfb7d..cda5456723fb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -38,11 +38,12 @@ import static android.app.ActivityManager.PROCESS_STATE_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING; import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_NONE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_ACTIVITY; import static com.android.server.am.ProcessList.BACKUP_APP_ADJ; import static com.android.server.am.ProcessList.CACHED_APP_MAX_ADJ; import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ; @@ -254,12 +255,13 @@ public class MockingOomAdjusterTests { * - If there's only one process, then it calls updateOomAdjLocked(ProcessRecord, int). * - Otherwise, sets the processes to the LRU and run updateOomAdjLocked(int). */ + @SuppressWarnings("GuardedBy") private void updateOomAdj(ProcessRecord... apps) { if (apps.length == 1) { - sService.mOomAdjuster.updateOomAdjLocked(apps[0], OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE); } else { setProcessesToLru(apps); - sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE); sService.mProcessList.getLruProcessesLOSP().clear(); } } @@ -658,7 +660,7 @@ public class MockingOomAdjusterTests { ServiceRecord s = bindService(app, system, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class)); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ + 1, SCHED_GROUP_DEFAULT); @@ -1226,7 +1228,7 @@ public class MockingOomAdjusterTests { mock(IBinder.class)); client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj()); } @@ -1243,7 +1245,7 @@ public class MockingOomAdjusterTests { mock(IBinder.class)); client.mState.setMaxAdj(PERSISTENT_PROC_ADJ); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE); doReturn(false).when(wpc).isHeavyWeightProcess(); assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj()); @@ -1497,7 +1499,7 @@ public class MockingOomAdjusterTests { client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - sService.mOomAdjuster.updateOomAdjLocked(client2, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(client2, OOM_ADJ_REASON_NONE); assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.mState.getSetProcState()); assertEquals(PROCESS_STATE_CACHED_EMPTY, client.mState.getSetProcState()); @@ -1919,7 +1921,7 @@ public class MockingOomAdjusterTests { doReturn(client2).when(sService).getTopApp(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - sService.mOomAdjuster.updateOomAdjLocked(app2, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(app2, OOM_ADJ_REASON_NONE); assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_DEFAULT); } @@ -2029,7 +2031,7 @@ public class MockingOomAdjusterTests { setServiceMap(s3, MOCKAPP5_UID, cn3); setServiceMap(c2s, MOCKAPP3_UID, cn4); app2UidRecord.setIdle(false); - sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE); assertProcStates(app1, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, SCHED_GROUP_DEFAULT); @@ -2055,7 +2057,7 @@ public class MockingOomAdjusterTests { anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); doNothing().when(sService.mServices) .scheduleServiceTimeoutLocked(any(ProcessRecord.class)); - sService.mOomAdjuster.updateOomAdjLocked(client1, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(client1, OOM_ADJ_REASON_NONE); assertEquals(PROCESS_STATE_CACHED_EMPTY, client1.mState.getSetProcState()); assertEquals(PROCESS_STATE_SERVICE, app1.mState.getSetProcState()); @@ -2427,7 +2429,7 @@ public class MockingOomAdjusterTests { app2.mState.setHasShownUi(false); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); - sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE); assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-ui-services"); assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj2, "cch-started-services"); @@ -2436,7 +2438,7 @@ public class MockingOomAdjusterTests { app.mState.setAdjType(null); app.mState.setSetAdj(UNKNOWN_ADJ); app.mState.setHasShownUi(false); - sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE); assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services"); @@ -2445,7 +2447,7 @@ public class MockingOomAdjusterTests { app.mState.setAdjType(null); app.mState.setSetAdj(UNKNOWN_ADJ); s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1; - sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE); assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services"); @@ -2463,7 +2465,7 @@ public class MockingOomAdjusterTests { s.lastActivity = now; app.mServices.startService(s); - sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE); assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services"); assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services"); @@ -2474,7 +2476,7 @@ public class MockingOomAdjusterTests { app.mState.setSetAdj(UNKNOWN_ADJ); app.mState.setHasShownUi(false); s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1; - sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE); assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services"); assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services"); @@ -2482,7 +2484,7 @@ public class MockingOomAdjusterTests { doReturn(userOther).when(sService.mUserController).getCurrentUserId(); sService.mOomAdjuster.handleUserSwitchedLocked(); - sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE); assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services"); assertProcStates(app2, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services"); } diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupAndRestoreFeatureFlagsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAndRestoreFeatureFlagsTest.java index 201da359aeb6..9f685b479d47 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/BackupAndRestoreFeatureFlagsTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAndRestoreFeatureFlagsTest.java @@ -104,4 +104,24 @@ public class BackupAndRestoreFeatureFlagsTest { assertThat(BackupAndRestoreFeatureFlags.getFullBackupUtilsRouteBufferSizeBytes()) .isEqualTo(5678); } + + @Test + public void getUnifiedRestoreContinueAfterTransportFailureInKvRestore_notSet_returnsDefault() { + assertThat( + BackupAndRestoreFeatureFlags + .getUnifiedRestoreContinueAfterTransportFailureInKvRestore()) + .isEqualTo(true); + } + + @Test + public void getUnifiedRestoreContinueAfterTransportFailureInKvRestore_set_returnsSetValue() { + DeviceConfig.setProperty(/*namespace=*/ "backup_and_restore", + /*name=*/ "unified_restore_continue_after_transport_failure_in_kv_restore", + /*value=*/ "false", /*makeDefault=*/ false); + + assertThat( + BackupAndRestoreFeatureFlags + .getUnifiedRestoreContinueAfterTransportFailureInKvRestore()) + .isEqualTo(false); + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java index 017c93975286..c84797febcfd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java @@ -25,20 +25,33 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; -import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; +import android.app.backup.BackupTransport; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.os.Message; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.provider.DeviceConfig; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; +import com.android.modules.utils.testing.TestableDeviceConfig; import com.android.server.backup.UserBackupManagerService; +import com.android.server.backup.internal.BackupHandler; +import com.android.server.backup.transport.BackupTransportClient; +import com.android.server.backup.transport.TransportConnection; +import com.android.server.backup.transport.TransportNotAvailableException; 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.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -62,9 +75,14 @@ public class PerformUnifiedRestoreTaskTest { private static final String SYSTEM_PACKAGE_NAME = "android"; private static final String NON_SYSTEM_PACKAGE_NAME = "package"; - @Mock private BackupDataInput mBackupDataInput; - @Mock private BackupDataOutput mBackupDataOutput; - @Mock private UserBackupManagerService mBackupManagerService; + @Mock + private BackupDataInput mBackupDataInput; + @Mock + private BackupDataOutput mBackupDataOutput; + @Mock + private UserBackupManagerService mBackupManagerService; + @Mock + private TransportConnection mTransportConnection; private Set<String> mExcludedkeys = new HashSet<>(); private Map<String, String> mBackupData = new HashMap<>(); @@ -74,12 +92,20 @@ public class PerformUnifiedRestoreTaskTest { private Set<String> mBackupDataDump; private PerformUnifiedRestoreTask mRestoreTask; + @Rule + public TestableDeviceConfig.TestableDeviceConfigRule + mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule(); + + private Context mContext; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); populateTestData(); + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + mBackupDataSource = new ArrayDeque<>(mBackupData.keySet()); when(mBackupDataInput.readNextHeader()).then(new Answer<Boolean>() { @Override @@ -106,7 +132,7 @@ public class PerformUnifiedRestoreTaskTest { } }); - mRestoreTask = new PerformUnifiedRestoreTask(mBackupManagerService); + mRestoreTask = new PerformUnifiedRestoreTask(mBackupManagerService, mTransportConnection); } private void populateTestData() { @@ -179,4 +205,64 @@ public class PerformUnifiedRestoreTaskTest { assertTrue(mRestoreTask.shouldStageBackupData(SYSTEM_PACKAGE_NAME)); } + + @Test + public void testFailedKeyValueRestore_continueAfterFeatureEnabled_nextStateIsRunningQueue() + throws TransportNotAvailableException, RemoteException { + DeviceConfig.setProperty( + "backup_and_restore", + "unified_restore_continue_after_transport_failure_in_kv_restore", + "true", + false); + + setupForRestoreKeyValueState(BackupTransport.TRANSPORT_ERROR); + + mRestoreTask.setCurrentUnifiedRestoreStateForTesting(UnifiedRestoreState.RESTORE_KEYVALUE); + mRestoreTask.setStateDirForTesting(mContext.getCacheDir()); + + PackageInfo testPackageInfo = new PackageInfo(); + testPackageInfo.packageName = "test.package.name"; + mRestoreTask.initiateOneRestoreForTesting(testPackageInfo, 0L); + assertTrue( + mRestoreTask.getCurrentUnifiedRestoreStateForTesting() + == UnifiedRestoreState.RUNNING_QUEUE); + } + + @Test + public void testFailedKeyValueRestore_continueAfterFeatureDisabled_nextStateIsFinal() + throws RemoteException, TransportNotAvailableException { + DeviceConfig.setProperty( + "backup_and_restore", + "unified_restore_continue_after_transport_failure_in_kv_restore", + "false", + false); + + setupForRestoreKeyValueState(BackupTransport.TRANSPORT_ERROR); + + mRestoreTask.setCurrentUnifiedRestoreStateForTesting(UnifiedRestoreState.RESTORE_KEYVALUE); + mRestoreTask.setStateDirForTesting(mContext.getCacheDir()); + + PackageInfo testPackageInfo = new PackageInfo(); + testPackageInfo.packageName = "test.package.name"; + mRestoreTask.initiateOneRestoreForTesting(testPackageInfo, 0L); + assertTrue( + mRestoreTask.getCurrentUnifiedRestoreStateForTesting() + == UnifiedRestoreState.FINAL); + } + + private void setupForRestoreKeyValueState(int transportStatus) + throws RemoteException, TransportNotAvailableException { + // Mock BackupHandler to do nothing when executeNextState() is called + BackupHandler backupHandler = Mockito.mock(BackupHandler.class); + when(backupHandler.obtainMessage(anyInt(), any())).thenReturn(new Message()); + when(backupHandler.sendMessage(any())).thenReturn(true); + + // Return cache directory for any bookkeeping or maintaining persistent state. + when(mBackupManagerService.getDataDir()).thenReturn(mContext.getCacheDir()); + when(mBackupManagerService.getBackupHandler()).thenReturn(backupHandler); + + BackupTransportClient transport = Mockito.mock(BackupTransportClient.class); + when(transport.getRestoreData(any())).thenReturn(transportStatus); + when(mTransportConnection.connectOrThrow(any())).thenReturn(transport); + } } 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 fc503b7a749b..ca857f121624 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java @@ -38,9 +38,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; -import android.content.ContentResolver; import android.content.Context; -import android.content.ContextWrapper; import android.content.res.Resources; import android.hardware.Sensor; import android.hardware.SensorEventListener; @@ -51,18 +49,18 @@ import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.SystemProperties; -import android.os.UserHandle; import android.os.test.TestLooper; import android.provider.Settings; +import android.testing.TestableContext; import android.util.FloatProperty; import android.view.Display; import android.view.DisplayInfo; -import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; -import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.server.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.display.RampAnimator.DualRampAnimator; @@ -74,12 +72,12 @@ import com.android.server.testutils.OffsettableClock; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; @@ -97,11 +95,9 @@ public final class DisplayPowerController2Test { private static final String SECOND_FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_789"; private static final float PROX_SENSOR_MAX_RANGE = 5; - private MockitoSession mSession; private OffsettableClock mClock; private TestLooper mTestLooper; private Handler mHandler; - private Context mContextSpy; private DisplayPowerControllerHolder mHolder; private Sensor mProxSensor; @@ -118,40 +114,44 @@ public final class DisplayPowerController2Test { @Mock private PowerManager mPowerManagerMock; @Mock - private Resources mResourcesMock; - @Mock private ColorDisplayService.ColorDisplayServiceInternal mCdsiMock; @Captor private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; + @Rule + public final TestableContext mContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getContext()); + + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = + new ExtendedMockitoRule.Builder(this) + .setStrictness(Strictness.LENIENT) + .spyStatic(SystemProperties.class) + .spyStatic(BatteryStatsService.class) + .build(); + @Before public void setUp() throws Exception { - mSession = ExtendedMockito.mockitoSession() - .initMocks(this) - .strictness(Strictness.LENIENT) - .spyStatic(SystemProperties.class) - .spyStatic(LocalServices.class) - .spyStatic(BatteryStatsService.class) - .spyStatic(Settings.System.class) - .startMocking(); - mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); mClock = new OffsettableClock.Stopped(); mTestLooper = new TestLooper(mClock::now); mHandler = new Handler(mTestLooper.getLooper()); + + // Put the system into manual brightness by default, just to minimize unexpected events and + // have a consistent starting state + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); + addLocalServiceMock(WindowManagerPolicy.class, mWindowManagerPolicyMock); + addLocalServiceMock(ColorDisplayService.ColorDisplayServiceInternal.class, + mCdsiMock); - when(mContextSpy.getSystemService(eq(PowerManager.class))).thenReturn(mPowerManagerMock); - when(mContextSpy.getResources()).thenReturn(mResourcesMock); + mContext.addMockSystemService(PowerManager.class, mPowerManagerMock); doAnswer((Answer<Void>) invocationOnMock -> null).when(() -> SystemProperties.set(anyString(), any())); - doAnswer((Answer<ColorDisplayService.ColorDisplayServiceInternal>) invocationOnMock -> - mCdsiMock).when(() -> LocalServices.getService( - ColorDisplayService.ColorDisplayServiceInternal.class)); doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService); - doAnswer((Answer<Boolean>) invocationOnMock -> true).when(() -> - Settings.System.putFloatForUser(any(), any(), anyFloat(), anyInt())); setUpSensors(); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); @@ -159,8 +159,8 @@ public final class DisplayPowerController2Test { @After public void tearDown() { - mSession.finishMocking(); LocalServices.removeServiceForTest(WindowManagerPolicy.class); + LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); } @Test @@ -421,11 +421,9 @@ public final class DisplayPowerController2Test { @Test public void testDisplayBrightnessFollowers_AutomaticBrightness() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); final float brightness = 0.4f; final float nits = 300; final float ambientLux = 3000; @@ -436,7 +434,7 @@ public final class DisplayPowerController2Test { when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux); when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - DisplayPowerController followerDpc = mock(DisplayPowerController.class); + DisplayPowerController2 followerDpc = mock(DisplayPowerController2.class); mHolder.dpc.addDisplayBrightnessFollower(followerDpc); DisplayPowerRequest dpr = new DisplayPowerRequest(); @@ -542,11 +540,9 @@ public final class DisplayPowerController2Test { @Test public void testSetScreenOffBrightnessSensorEnabled_DisplayIsOff() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_OFF; @@ -577,17 +573,14 @@ public final class DisplayPowerController2Test { @Test public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_DOZE; - when(mResourcesMock.getBoolean( - com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing)) - .thenReturn(true); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true); mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); // Run updatePowerState @@ -615,12 +608,7 @@ public final class DisplayPowerController2Test { @Test public void testSetScreenOffBrightnessSensorDisabled_AutoBrightnessIsDisabled() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); - + // Tests are set up with manual brightness by default, so no need to set it here. DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_OFF; mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); @@ -632,11 +620,9 @@ public final class DisplayPowerController2Test { @Test public void testSetScreenOffBrightnessSensorDisabled_DisplayIsDisabled() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ false); DisplayPowerRequest dpr = new DisplayPowerRequest(); @@ -690,9 +676,9 @@ public final class DisplayPowerController2Test { public void testBrightnessNitsPersistWhenDisplayDeviceChanges() { float brightness = 0.3f; float nits = 500; - when(mResourcesMock.getBoolean( - com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay)) - .thenReturn(true); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay, + true); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); @@ -753,7 +739,7 @@ public final class DisplayPowerController2Test { any(HysteresisLevels.class), any(HysteresisLevels.class), any(HysteresisLevels.class), - eq(mContextSpy), + eq(mContext), any(HighBrightnessModeController.class), any(BrightnessThrottler.class), isNull(), @@ -804,7 +790,7 @@ public final class DisplayPowerController2Test { when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info); when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled); when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false); - when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn( + when(logicalDisplayMock.getThermalBrightnessThrottlingDataIdLocked()).thenReturn( DisplayDeviceConfig.DEFAULT_ID); when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo); when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId); @@ -862,7 +848,7 @@ public final class DisplayPowerController2Test { setUpDisplay(displayId, uniqueId, display, device, config, isEnabled); final DisplayPowerController2 dpc = new DisplayPowerController2( - mContextSpy, injector, mDisplayPowerCallbacksMock, mHandler, + mContext, injector, mDisplayPowerCallbacksMock, mHandler, mSensorManagerMock, mDisplayBlankerMock, display, mBrightnessTrackerMock, brightnessSetting, () -> {}, hbmMetadata, /* bootCompleted= */ false); diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java index c021ef65a291..0b97c5cb6ca1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -38,9 +38,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; -import android.content.ContentResolver; import android.content.Context; -import android.content.ContextWrapper; import android.content.res.Resources; import android.hardware.Sensor; import android.hardware.SensorEventListener; @@ -51,18 +49,18 @@ import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.SystemProperties; -import android.os.UserHandle; import android.os.test.TestLooper; import android.provider.Settings; +import android.testing.TestableContext; import android.util.FloatProperty; import android.view.Display; import android.view.DisplayInfo; -import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; -import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.server.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.display.RampAnimator.DualRampAnimator; @@ -75,12 +73,12 @@ import com.android.server.testutils.OffsettableClock; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; @@ -98,11 +96,9 @@ public final class DisplayPowerControllerTest { private static final String SECOND_FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_789"; private static final float PROX_SENSOR_MAX_RANGE = 5; - private MockitoSession mSession; private OffsettableClock mClock; private TestLooper mTestLooper; private Handler mHandler; - private Context mContextSpy; private DisplayPowerControllerHolder mHolder; private Sensor mProxSensor; @@ -119,41 +115,45 @@ public final class DisplayPowerControllerTest { @Mock private PowerManager mPowerManagerMock; @Mock - private Resources mResourcesMock; - @Mock private ColorDisplayService.ColorDisplayServiceInternal mCdsiMock; @Captor private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; + @Rule + public final TestableContext mContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getContext()); + + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = + new ExtendedMockitoRule.Builder(this) + .setStrictness(Strictness.LENIENT) + .spyStatic(SystemProperties.class) + .spyStatic(BatteryStatsService.class) + .build(); + @Before public void setUp() throws Exception { - mSession = ExtendedMockito.mockitoSession() - .initMocks(this) - .strictness(Strictness.LENIENT) - .spyStatic(SystemProperties.class) - .spyStatic(LocalServices.class) - .spyStatic(BatteryStatsService.class) - .spyStatic(Settings.System.class) - .startMocking(); - mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); mClock = new OffsettableClock.Stopped(); mTestLooper = new TestLooper(mClock::now); mHandler = new Handler(mTestLooper.getLooper()); + // Put the system into manual brightness by default, just to minimize unexpected events and + // have a consistent starting state + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); + + addLocalServiceMock(WindowManagerPolicy.class, mWindowManagerPolicyMock); + addLocalServiceMock(ColorDisplayService.ColorDisplayServiceInternal.class, + mCdsiMock); - when(mContextSpy.getSystemService(eq(PowerManager.class))).thenReturn(mPowerManagerMock); - when(mContextSpy.getResources()).thenReturn(mResourcesMock); + mContext.addMockSystemService(PowerManager.class, mPowerManagerMock); doAnswer((Answer<Void>) invocationOnMock -> null).when(() -> SystemProperties.set(anyString(), any())); - doAnswer((Answer<ColorDisplayService.ColorDisplayServiceInternal>) invocationOnMock -> - mCdsiMock).when(() -> LocalServices.getService( - ColorDisplayService.ColorDisplayServiceInternal.class)); doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService); - doAnswer((Answer<Boolean>) invocationOnMock -> true).when(() -> - Settings.System.putFloatForUser(any(), any(), anyFloat(), anyInt())); setUpSensors(); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); @@ -161,8 +161,8 @@ public final class DisplayPowerControllerTest { @After public void tearDown() { - mSession.finishMocking(); LocalServices.removeServiceForTest(WindowManagerPolicy.class); + LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); } @Test @@ -425,11 +425,9 @@ public final class DisplayPowerControllerTest { @Test public void testDisplayBrightnessFollowers_AutomaticBrightness() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); final float brightness = 0.4f; final float nits = 300; final float ambientLux = 3000; @@ -547,11 +545,9 @@ public final class DisplayPowerControllerTest { @Test public void testSetScreenOffBrightnessSensorEnabled_DisplayIsOff() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_OFF; @@ -582,17 +578,14 @@ public final class DisplayPowerControllerTest { @Test public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_DOZE; - when(mResourcesMock.getBoolean( - com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing)) - .thenReturn(true); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true); mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); // Run updatePowerState @@ -620,12 +613,7 @@ public final class DisplayPowerControllerTest { @Test public void testSetScreenOffBrightnessSensorDisabled_AutoBrightnessIsDisabled() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); - + // Tests are set up with manual brightness by default, so no need to set it here. DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_OFF; mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); @@ -637,11 +625,10 @@ public final class DisplayPowerControllerTest { @Test public void testSetScreenOffBrightnessSensorDisabled_DisplayIsDisabled() { - doAnswer((Answer<Integer>) invocationOnMock -> - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) - .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), - eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), - eq(UserHandle.USER_CURRENT))); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ false); DisplayPowerRequest dpr = new DisplayPowerRequest(); @@ -695,9 +682,10 @@ public final class DisplayPowerControllerTest { public void testBrightnessNitsPersistWhenDisplayDeviceChanges() { float brightness = 0.3f; float nits = 500; - when(mResourcesMock.getBoolean( - com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay)) - .thenReturn(true); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay, + true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); @@ -758,7 +746,7 @@ public final class DisplayPowerControllerTest { any(HysteresisLevels.class), any(HysteresisLevels.class), any(HysteresisLevels.class), - eq(mContextSpy), + eq(mContext), any(HighBrightnessModeController.class), any(BrightnessThrottler.class), isNull(), @@ -809,7 +797,7 @@ public final class DisplayPowerControllerTest { when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info); when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled); when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false); - when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn( + when(logicalDisplayMock.getThermalBrightnessThrottlingDataIdLocked()).thenReturn( DisplayDeviceConfig.DEFAULT_ID); when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo); when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId); @@ -866,7 +854,7 @@ public final class DisplayPowerControllerTest { setUpDisplay(displayId, uniqueId, display, device, config, isEnabled); final DisplayPowerController dpc = new DisplayPowerController( - mContextSpy, injector, mDisplayPowerCallbacksMock, mHandler, + mContext, injector, mDisplayPowerCallbacksMock, mHandler, mSensorManagerMock, mDisplayBlankerMock, display, mBrightnessTrackerMock, brightnessSetting, () -> {}, hbmMetadata, /* bootCompleted= */ false); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java index 03f667f0d336..e24354f26d8b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java @@ -23,6 +23,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -39,6 +41,7 @@ import android.graphics.drawable.Icon; import android.os.UserHandle; import com.android.server.LocalServices; +import com.android.server.job.controllers.JobStatus; import com.android.server.notification.NotificationManagerInternal; import org.junit.After; @@ -146,7 +149,8 @@ public class JobNotificationCoordinatorTest { .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId), eq(notification), eq(UserHandle.getUserId(uid))); - coordinator.removeNotificationAssociation(jsc, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc, JobParameters.STOP_REASON_UNDEFINED, + jsc.getRunningJobLocked()); verify(mNotificationManagerInternal, never()) .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(), anyInt(), anyInt()); @@ -167,7 +171,8 @@ public class JobNotificationCoordinatorTest { .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId), eq(notification), eq(UserHandle.getUserId(uid))); - coordinator.removeNotificationAssociation(jsc, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc, JobParameters.STOP_REASON_UNDEFINED, + jsc.getRunningJobLocked()); verify(mNotificationManagerInternal) .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId), eq(UserHandle.getUserId(uid))); @@ -289,7 +294,8 @@ public class JobNotificationCoordinatorTest { eq(notificationId2), eq(notification2), eq(UserHandle.getUserId(uid))); // Remove the first job. Only the first notification should be removed. - coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_UNDEFINED, + jsc1.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal) .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId1), eq(UserHandle.getUserId(uid))); @@ -297,7 +303,8 @@ public class JobNotificationCoordinatorTest { .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(), eq(notificationId2), anyInt()); - coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_UNDEFINED, + jsc2.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal) .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId2), eq(UserHandle.getUserId(uid))); @@ -332,12 +339,14 @@ public class JobNotificationCoordinatorTest { eq(notificationId), eq(notification2), eq(UserHandle.getUserId(uid))); // Remove the first job. The notification shouldn't be touched because of the 2nd job. - coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_UNDEFINED, + jsc1.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal, never()) .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(), anyInt(), anyInt()); - coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_UNDEFINED, + jsc2.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal) .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId), eq(UserHandle.getUserId(uid))); @@ -373,7 +382,8 @@ public class JobNotificationCoordinatorTest { eq(notificationId), eq(notification2), eq(UserHandle.getUserId(uid2))); // Remove the first job. Only the first notification should be removed. - coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_UNDEFINED, + jsc1.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal) .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid1), eq(pid), any(), eq(notificationId), eq(UserHandle.getUserId(uid1))); @@ -381,7 +391,8 @@ public class JobNotificationCoordinatorTest { .cancelNotification(anyString(), anyString(), eq(uid2), anyInt(), any(), anyInt(), anyInt()); - coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_UNDEFINED, + jsc2.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal) .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid2), eq(pid), any(), eq(notificationId), eq(UserHandle.getUserId(uid2))); @@ -418,7 +429,8 @@ public class JobNotificationCoordinatorTest { eq(notificationId), eq(notification2), eq(UserHandle.getUserId(uid))); // Remove the first job. Only the first notification should be removed. - coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_UNDEFINED, + jsc1.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal) .cancelNotification(eq(pkg1), eq(pkg1), eq(uid), eq(pid), any(), eq(notificationId), eq(UserHandle.getUserId(uid))); @@ -426,7 +438,8 @@ public class JobNotificationCoordinatorTest { .cancelNotification(anyString(), anyString(), eq(uid), anyInt(), any(), anyInt(), anyInt()); - coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_UNDEFINED); + coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_UNDEFINED, + jsc2.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal) .cancelNotification(eq(pkg2), eq(pkg2), eq(uid), eq(pid), any(), eq(notificationId), eq(UserHandle.getUserId(uid))); @@ -447,7 +460,8 @@ public class JobNotificationCoordinatorTest { .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId), eq(notification), eq(UserHandle.getUserId(uid))); - coordinator.removeNotificationAssociation(jsc, JobParameters.STOP_REASON_USER); + coordinator.removeNotificationAssociation(jsc, JobParameters.STOP_REASON_USER, + jsc.getRunningJobLocked()); verify(mNotificationManagerInternal) .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId), eq(UserHandle.getUserId(uid))); @@ -482,17 +496,57 @@ public class JobNotificationCoordinatorTest { eq(notificationId), eq(notification2), eq(UserHandle.getUserId(uid))); // Remove the first job. The notification shouldn't be touched because of the 2nd job. - coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_USER); + coordinator.removeNotificationAssociation(jsc1, JobParameters.STOP_REASON_USER, + jsc1.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal, never()) .cancelNotification(anyString(), anyString(), anyInt(), anyInt(), any(), anyInt(), anyInt()); - coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_USER); + coordinator.removeNotificationAssociation(jsc2, JobParameters.STOP_REASON_USER, + jsc2.getRunningJobLocked()); inOrder.verify(mNotificationManagerInternal) .cancelNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), eq(notificationId), eq(UserHandle.getUserId(uid))); } + @Test + public void testUserInitiatedJob_hasNotificationFlag() { + final JobNotificationCoordinator coordinator = new JobNotificationCoordinator(); + final JobServiceContext jsc = mock(JobServiceContext.class); + final JobStatus js = mock(JobStatus.class); + js.startedAsUserInitiatedJob = true; + doReturn(js).when(jsc).getRunningJobLocked(); + final Notification notification = createValidNotification(); + final int uid = 10123; + final int pid = 42; + final int notificationId = 23; + + coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId, notification, + JobService.JOB_END_NOTIFICATION_POLICY_REMOVE); + verify(mNotificationManagerInternal) + .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), + eq(notificationId), eq(notification), eq(UserHandle.getUserId(uid))); + assertNotEquals(notification.flags & Notification.FLAG_USER_INITIATED_JOB, 0); + } + + @Test + public void testNonUserInitiatedJob_doesNotHaveNotificationFlag() { + final JobNotificationCoordinator coordinator = new JobNotificationCoordinator(); + final JobServiceContext jsc = mock(JobServiceContext.class); + doReturn(mock(JobStatus.class)).when(jsc).getRunningJobLocked(); + final Notification notification = createValidNotification(); + final int uid = 10123; + final int pid = 42; + final int notificationId = 23; + + coordinator.enqueueNotification(jsc, TEST_PACKAGE, pid, uid, notificationId, notification, + JobService.JOB_END_NOTIFICATION_POLICY_REMOVE); + verify(mNotificationManagerInternal) + .enqueueNotification(eq(TEST_PACKAGE), eq(TEST_PACKAGE), eq(uid), eq(pid), any(), + eq(notificationId), eq(notification), eq(UserHandle.getUserId(uid))); + assertEquals(notification.flags & Notification.FLAG_USER_INITIATED_JOB, 0); + } + private Notification createValidNotification() { final Notification notification = mock(Notification.class); doReturn(mock(Icon.class)).when(notification).getSmallIcon(); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java index 02fdfadb2d8a..754f409b3966 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/restrictions/ThermalStatusRestrictionTest.java @@ -276,9 +276,9 @@ public class ThermalStatusRestrictionTest { assertFalse(mThermalStatusRestriction.isJobRestricted(ejRunning)); assertTrue(mThermalStatusRestriction.isJobRestricted(ejRunningLong)); assertFalse(mThermalStatusRestriction.isJobRestricted(ui)); - assertTrue(mThermalStatusRestriction.isJobRestricted(uiRetried)); + assertFalse(mThermalStatusRestriction.isJobRestricted(uiRetried)); assertFalse(mThermalStatusRestriction.isJobRestricted(uiRunning)); - assertTrue(mThermalStatusRestriction.isJobRestricted(uiRunningLong)); + assertFalse(mThermalStatusRestriction.isJobRestricted(uiRunningLong)); mStatusChangedListener.onThermalStatusChanged(THERMAL_STATUS_SEVERE); diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java new file mode 100644 index 000000000000..e1fa8f527261 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java @@ -0,0 +1,92 @@ +/* + * 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.location.gnss; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.location.LocationManager; +import android.location.LocationManagerInternal; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.LocalServices; +import com.android.server.location.gnss.hal.FakeGnssHal; +import com.android.server.location.gnss.hal.GnssNative; +import com.android.server.location.injector.Injector; +import com.android.server.location.injector.TestInjector; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Objects; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class GnssAntennaInfoProviderTest { + private @Mock Context mContext; + private @Mock LocationManagerInternal mInternal; + private @Mock GnssConfiguration mMockConfiguration; + private @Mock IBinder mBinder; + private GnssNative mGnssNative; + + private GnssAntennaInfoProvider mTestProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + doReturn(true).when(mInternal).isProviderEnabledForUser(eq(LocationManager.GPS_PROVIDER), + anyInt()); + LocalServices.addService(LocationManagerInternal.class, mInternal); + FakeGnssHal fakeGnssHal = new FakeGnssHal(); + GnssNative.setGnssHalForTest(fakeGnssHal); + Injector injector = new TestInjector(mContext); + mGnssNative = spy(Objects.requireNonNull(GnssNative.create(injector, mMockConfiguration))); + mTestProvider = new GnssAntennaInfoProvider(mGnssNative); + mGnssNative.register(); + } + + @After + public void tearDown() { + LocalServices.removeServiceForTest(LocationManagerInternal.class); + } + + @Test + public void testOnHalStarted() { + verify(mGnssNative, times(1)).startAntennaInfoListening(); + } + + @Test + public void testOnHalRestarted() { + mTestProvider.onHalRestarted(); + verify(mGnssNative, times(2)).startAntennaInfoListening(); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java index fd9dfe869d52..bf96b1dec4ac 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java @@ -74,7 +74,6 @@ public class GnssMeasurementsProviderTest { private @Mock Context mContext; private @Mock LocationManagerInternal mInternal; private @Mock GnssConfiguration mMockConfiguration; - private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks; private @Mock IGnssMeasurementsListener mListener1; private @Mock IGnssMeasurementsListener mListener2; private @Mock IBinder mBinder1; @@ -98,7 +97,6 @@ public class GnssMeasurementsProviderTest { Injector injector = new TestInjector(mContext); mGnssNative = spy(Objects.requireNonNull( GnssNative.create(injector, mMockConfiguration))); - mGnssNative.setGeofenceCallbacks(mGeofenceCallbacks); mTestProvider = new GnssMeasurementsProvider(injector, mGnssNative); mGnssNative.register(); } diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssNavigationMessageProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssNavigationMessageProviderTest.java new file mode 100644 index 000000000000..64aa4b3fa2ff --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssNavigationMessageProviderTest.java @@ -0,0 +1,93 @@ +/* + * 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.location.gnss; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.location.IGnssNavigationMessageListener; +import android.location.LocationManager; +import android.location.LocationManagerInternal; +import android.location.util.identity.CallerIdentity; +import android.os.IBinder; + +import com.android.server.LocalServices; +import com.android.server.location.gnss.hal.FakeGnssHal; +import com.android.server.location.gnss.hal.GnssNative; +import com.android.server.location.injector.FakeUserInfoHelper; +import com.android.server.location.injector.Injector; +import com.android.server.location.injector.TestInjector; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Objects; + +public class GnssNavigationMessageProviderTest { + private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID; + private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1000, + "mypackage", "attribution", "listener"); + private @Mock Context mContext; + private @Mock LocationManagerInternal mInternal; + private @Mock GnssConfiguration mMockConfiguration; + private @Mock IGnssNavigationMessageListener mListener; + private @Mock IBinder mBinder; + + private GnssNative mGnssNative; + + private GnssNavigationMessageProvider mTestProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + doReturn(mBinder).when(mListener).asBinder(); + doReturn(true).when(mInternal).isProviderEnabledForUser(eq(LocationManager.GPS_PROVIDER), + anyInt()); + LocalServices.addService(LocationManagerInternal.class, mInternal); + FakeGnssHal fakeGnssHal = new FakeGnssHal(); + GnssNative.setGnssHalForTest(fakeGnssHal); + Injector injector = new TestInjector(mContext); + mGnssNative = spy(Objects.requireNonNull(GnssNative.create(injector, mMockConfiguration))); + mTestProvider = new GnssNavigationMessageProvider(injector, mGnssNative); + mGnssNative.register(); + } + + @After + public void tearDown() { + LocalServices.removeServiceForTest(LocationManagerInternal.class); + } + + @Test + public void testAddListener() { + // add a request + mTestProvider.addListener(IDENTITY, mListener); + verify(mGnssNative, times(1)).startNavigationMessageCollection(); + + // remove a request + mTestProvider.removeListener(mListener); + verify(mGnssNative, times(1)).stopNavigationMessageCollection(); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssNmeaProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssNmeaProviderTest.java new file mode 100644 index 000000000000..49e5e69933f9 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssNmeaProviderTest.java @@ -0,0 +1,104 @@ +/* + * 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.location.gnss; + + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.location.IGnssNmeaListener; +import android.location.LocationManager; +import android.location.LocationManagerInternal; +import android.location.util.identity.CallerIdentity; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.server.LocalServices; +import com.android.server.location.gnss.hal.FakeGnssHal; +import com.android.server.location.gnss.hal.GnssNative; +import com.android.server.location.injector.FakeUserInfoHelper; +import com.android.server.location.injector.Injector; +import com.android.server.location.injector.TestInjector; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Objects; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class GnssNmeaProviderTest { + + private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID; + private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1000, + "mypackage", "attribution", "listener"); + private @Mock Context mContext; + private @Mock LocationManagerInternal mInternal; + private @Mock GnssConfiguration mMockConfiguration; + private @Mock IGnssNmeaListener mListener; + private @Mock IBinder mBinder; + + private GnssNative mGnssNative; + + private GnssNmeaProvider mTestProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + doReturn(mBinder).when(mListener).asBinder(); + doReturn(true).when(mInternal).isProviderEnabledForUser(eq(LocationManager.GPS_PROVIDER), + anyInt()); + LocalServices.addService(LocationManagerInternal.class, mInternal); + FakeGnssHal fakeGnssHal = new FakeGnssHal(); + GnssNative.setGnssHalForTest(fakeGnssHal); + Injector injector = new TestInjector(mContext); + mGnssNative = spy(Objects.requireNonNull(GnssNative.create(injector, mMockConfiguration))); + mTestProvider = new GnssNmeaProvider(injector, mGnssNative); + mGnssNative.register(); + } + + @After + public void tearDown() { + LocalServices.removeServiceForTest(LocationManagerInternal.class); + } + + @Test + public void testAddListener() { + // add a request + mTestProvider.addListener(IDENTITY, mListener); + verify(mGnssNative, times(1)).startNmeaMessageCollection(); + + // remove a request + mTestProvider.removeListener(mListener); + verify(mGnssNative, times(1)).stopNmeaMessageCollection(); + } + +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssStatusProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssStatusProviderTest.java new file mode 100644 index 000000000000..ce2aec7f8d5d --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssStatusProviderTest.java @@ -0,0 +1,103 @@ +/* + * 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.location.gnss; + + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.location.IGnssStatusListener; +import android.location.LocationManager; +import android.location.LocationManagerInternal; +import android.location.util.identity.CallerIdentity; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.server.LocalServices; +import com.android.server.location.gnss.hal.FakeGnssHal; +import com.android.server.location.gnss.hal.GnssNative; +import com.android.server.location.injector.FakeUserInfoHelper; +import com.android.server.location.injector.Injector; +import com.android.server.location.injector.TestInjector; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Objects; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class GnssStatusProviderTest { + private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID; + private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1000, + "mypackage", "attribution", "listener"); + private @Mock Context mContext; + private @Mock LocationManagerInternal mInternal; + private @Mock GnssConfiguration mMockConfiguration; + private @Mock IGnssStatusListener mListener; + private @Mock IBinder mBinder; + + private GnssNative mGnssNative; + + private GnssStatusProvider mTestProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + doReturn(mBinder).when(mListener).asBinder(); + doReturn(true).when(mInternal).isProviderEnabledForUser(eq(LocationManager.GPS_PROVIDER), + anyInt()); + LocalServices.addService(LocationManagerInternal.class, mInternal); + FakeGnssHal fakeGnssHal = new FakeGnssHal(); + GnssNative.setGnssHalForTest(fakeGnssHal); + Injector injector = new TestInjector(mContext); + mGnssNative = spy(Objects.requireNonNull(GnssNative.create(injector, mMockConfiguration))); + mTestProvider = new GnssStatusProvider(injector, mGnssNative); + mGnssNative.register(); + } + + @After + public void tearDown() { + LocalServices.removeServiceForTest(LocationManagerInternal.class); + } + + @Test + public void testAddListener() { + // add a request + mTestProvider.addListener(IDENTITY, mListener); + verify(mGnssNative, times(1)).startSvStatusCollection(); + + // remove a request + mTestProvider.removeListener(mListener); + verify(mGnssNative, times(1)).stopSvStatusCollection(); + } + +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java index b7ab6f80167e..2d962acfe665 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java @@ -562,6 +562,26 @@ public final class FakeGnssHal extends GnssNative.GnssHal { } @Override + protected boolean startSvStatusCollection() { + return true; + } + + @Override + protected boolean stopSvStatusCollection() { + return true; + } + + @Override + public boolean startNmeaMessageCollection() { + return true; + } + + @Override + public boolean stopNmeaMessageCollection() { + return true; + } + + @Override protected int getBatchSize() { return mBatchSize; } diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java index 0be678af12dc..541b07782b29 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java @@ -16,31 +16,65 @@ package com.android.server.rollback; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; + import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; import android.content.pm.VersionedPackage; +import android.content.rollback.PackageRollbackInfo; +import android.content.rollback.RollbackInfo; +import android.content.rollback.RollbackManager; import android.util.Log; import android.util.Xml; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.server.PackageWatchdog; import com.android.server.SystemConfig; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; import org.xmlpull.v1.XmlPullParser; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.List; import java.util.Scanner; + @RunWith(AndroidJUnit4.class) public class RollbackPackageHealthObserverTest { + @Mock + private Context mMockContext; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private PackageWatchdog mMockPackageWatchdog; + @Mock + RollbackManager mRollbackManager; + @Mock + RollbackInfo mRollbackInfo; + @Mock + PackageRollbackInfo mPackageRollbackInfo; + + private MockitoSession mSession; + private static final String APP_A = "com.package.a"; + private static final long VERSION_CODE = 1L; private static final String LOG_TAG = "RollbackPackageHealthObserverTest"; private SystemConfig mSysConfig; @@ -50,17 +84,74 @@ public class RollbackPackageHealthObserverTest { @Before public void setup() { mSysConfig = new SystemConfigTestClass(); + + mSession = ExtendedMockito.mockitoSession() + .initMocks(this) + .strictness(Strictness.LENIENT) + .spyStatic(PackageWatchdog.class) + .startMocking(); + + // Mock PackageWatchdog + doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog) + .when(() -> PackageWatchdog.getInstance(mMockContext)); + + } + + @After + public void tearDown() throws Exception { + mSession.finishMocking(); } /** - * Subclass of SystemConfig without running the constructor. - */ + * Subclass of SystemConfig without running the constructor. + */ private class SystemConfigTestClass extends SystemConfig { SystemConfigTestClass() { - super(false); + super(false); } } + @Test + public void testHealthCheckLevels() { + RollbackPackageHealthObserver observer = + spy(new RollbackPackageHealthObserver(mMockContext)); + VersionedPackage testFailedPackage = new VersionedPackage(APP_A, VERSION_CODE); + + + when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager); + + // Crashes with no rollbacks available + assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0, + observer.onHealthCheckFailed(null, + PackageWatchdog.FAILURE_REASON_NATIVE_CRASH, 1)); + assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0, + observer.onHealthCheckFailed(null, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1)); + + // Make the rollbacks available + when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(mRollbackInfo)); + when(mRollbackInfo.getPackages()).thenReturn(List.of(mPackageRollbackInfo)); + when(mPackageRollbackInfo.getVersionRolledBackFrom()).thenReturn(testFailedPackage); + + // native crash + assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30, + observer.onHealthCheckFailed(null, + PackageWatchdog.FAILURE_REASON_NATIVE_CRASH, 1)); + // non-native crash + assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30, + observer.onHealthCheckFailed(testFailedPackage, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1)); + // Second non-native crash again + assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_70, + observer.onHealthCheckFailed(testFailedPackage, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2)); + // Subsequent crashes when rollbacks have completed + when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of()); + assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0, + observer.onHealthCheckFailed(testFailedPackage, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 3)); + } + /** * Test that isAutomaticRollbackDenied works correctly when packages that are not * denied are sent. @@ -77,7 +168,7 @@ public class RollbackPackageHealthObserverTest { readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(RollbackPackageHealthObserver.isAutomaticRollbackDenied(mSysConfig, - new VersionedPackage("com.test.package", 1))).isEqualTo(false); + new VersionedPackage("com.test.package", 1))).isEqualTo(false); } /** @@ -96,7 +187,7 @@ public class RollbackPackageHealthObserverTest { readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(RollbackPackageHealthObserver.isAutomaticRollbackDenied(mSysConfig, - new VersionedPackage("com.android.vending", 1))).isEqualTo(true); + new VersionedPackage("com.android.vending", 1))).isEqualTo(true); } /** @@ -109,7 +200,7 @@ public class RollbackPackageHealthObserverTest { readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(RollbackPackageHealthObserver.isAutomaticRollbackDenied(mSysConfig, - new VersionedPackage("com.android.vending", 1))).isEqualTo(false); + new VersionedPackage("com.android.vending", 1))).isEqualTo(false); } /** diff --git a/services/tests/servicestests/res/xml/irq_device_map_3.xml b/services/tests/servicestests/res/xml/irq_device_map_3.xml index 1d2a7d37d613..7e2529aa0090 100644 --- a/services/tests/servicestests/res/xml/irq_device_map_3.xml +++ b/services/tests/servicestests/res/xml/irq_device_map_3.xml @@ -23,4 +23,7 @@ <device name="test.wifi.device"> <subsystem>Wifi</subsystem> </device> + <device name="test.sound_trigger.device"> + <subsystem>Sound_trigger</subsystem> + </device> </irq-device-map>
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java index 6216c66aa54f..4b86dd048cd1 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java @@ -152,8 +152,7 @@ public class AuthServiceTest { verify(mBiometricService, never()).registerAuthenticator( anyInt(), - anyInt(), - anyInt(), + any(), any()); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java index 4cdca268fc4b..26a3ae110525 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -43,14 +43,17 @@ import android.annotation.NonNull; import android.app.admin.DevicePolicyManager; import android.app.trust.ITrustManager; import android.content.Context; +import android.content.res.Resources; import android.hardware.biometrics.BiometricManager.Authenticators; -import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Binder; @@ -82,6 +85,7 @@ public class AuthSessionTest { private static final long TEST_REQUEST_ID = 22; @Mock private Context mContext; + @Mock private Resources mResources; @Mock private BiometricContext mBiometricContext; @Mock private ITrustManager mTrustManager; @Mock private DevicePolicyManager mDevicePolicyManager; @@ -103,6 +107,7 @@ public class AuthSessionTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + when(mContext.getResources()).thenReturn(mResources); when(mClientReceiver.asBinder()).thenReturn(mock(Binder.class)); when(mBiometricContext.updateContext(any(), anyBoolean())) .thenAnswer(invocation -> invocation.getArgument(0)); @@ -341,6 +346,33 @@ public class AuthSessionTest { testInvokesCancel(session -> session.onDialogDismissed(DISMISSED_REASON_NEGATIVE, null)); } + @Test + public void testCallbackOnAcquired() throws RemoteException { + final String acquiredStr = "test_acquired_info_callback"; + final String acquiredStrVendor = "test_acquired_info_callback_vendor"; + setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR); + + final AuthSession session = createAuthSession(mSensors, + false /* checkDevicePolicyManager */, + Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, + 0 /* operationId */, + 0 /* userId */); + + when(mContext.getString(com.android.internal.R.string.fingerprint_acquired_partial)) + .thenReturn(acquiredStr); + session.onAcquired(0, FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL, 0); + verify(mStatusBarService).onBiometricHelp(anyInt(), eq(acquiredStr)); + verify(mClientReceiver).onAcquired(eq(1), eq(acquiredStr)); + + when(mResources.getStringArray(com.android.internal.R.array.fingerprint_acquired_vendor)) + .thenReturn(new String[]{acquiredStrVendor}); + session.onAcquired(0, FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR, 0); + verify(mStatusBarService).onBiometricHelp(anyInt(), eq(acquiredStrVendor)); + verify(mClientReceiver).onAcquired( + eq(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR_BASE), eq(acquiredStrVendor)); + } + // TODO (b/208484275) : Enable these tests // @Test // public void testPreAuth_canAuthAndPrivacyDisabled() throws Exception { @@ -458,9 +490,16 @@ public class AuthSessionTest { IBiometricAuthenticator fingerprintAuthenticator = mock(IBiometricAuthenticator.class); when(fingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true); when(fingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); - mSensors.add(new BiometricSensor(mContext, id, + + final FingerprintSensorPropertiesInternal props = new FingerprintSensorPropertiesInternal( + id, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, + List.of() /* componentInfo */, type, + false /* resetLockoutRequiresHardwareAuthToken */); + mFingerprintSensorProps.add(props); + + mSensors.add(new BiometricSensor(mContext, TYPE_FINGERPRINT /* modality */, - Authenticators.BIOMETRIC_STRONG /* strength */, + props, fingerprintAuthenticator) { @Override boolean confirmationAlwaysRequired(int userId) { @@ -473,21 +512,6 @@ public class AuthSessionTest { } }); - final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); - componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, - "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */, - "00000001" /* serialNumber */, "" /* softwareVersion */)); - componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */, - "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */, - "vendor/version/revision" /* softwareVersion */)); - - mFingerprintSensorProps.add(new FingerprintSensorPropertiesInternal(id, - SensorProperties.STRENGTH_STRONG, - 5 /* maxEnrollmentsPerUser */, - componentInfo, - type, - false /* resetLockoutRequiresHardwareAuthToken */)); - when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true); } @@ -495,9 +519,13 @@ public class AuthSessionTest { IBiometricAuthenticator authenticator) throws RemoteException { when(authenticator.isHardwareDetected(any())).thenReturn(true); when(authenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); - mSensors.add(new BiometricSensor(mContext, id, + mSensors.add(new BiometricSensor(mContext, TYPE_FACE /* modality */, - Authenticators.BIOMETRIC_STRONG /* strength */, + new FaceSensorPropertiesInternal(id, + SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, + List.of() /* componentInfo */, FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFace Detection */, true /* supportsSelfIllumination */, + false /* resetLockoutRequiresHardwareAuthToken */), authenticator) { @Override boolean confirmationAlwaysRequired(int userId) { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index 168642e3533f..b51a8c4e1b6c 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -19,6 +19,7 @@ package com.android.server.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.Authenticators; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT; +import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI; @@ -66,7 +67,11 @@ import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.PromptInfo; import android.hardware.display.DisplayManagerGlobal; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -93,6 +98,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; import java.util.Random; @Presubmit @@ -114,6 +120,7 @@ public class BiometricServiceTest { private static final int SENSOR_ID_FINGERPRINT = 0; private static final int SENSOR_ID_FACE = 1; + private FingerprintSensorPropertiesInternal mFingerprintProps; private BiometricService mBiometricService; @@ -193,6 +200,11 @@ public class BiometricServiceTest { }; when(mInjector.getConfiguration(any())).thenReturn(config); + + mFingerprintProps = new FingerprintSensorPropertiesInternal(SENSOR_ID_FINGERPRINT, + STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, List.of() /* componentInfo */, + FingerprintSensorProperties.TYPE_UNKNOWN, + false /* resetLockoutRequiresHardwareAuthToken */); } @Test @@ -328,8 +340,7 @@ public class BiometricServiceTest { mBiometricService = new BiometricService(mContext, mInjector); mBiometricService.onStart(); - mBiometricService.mImpl.registerAuthenticator(0 /* id */, - TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG, + mBiometricService.mImpl.registerAuthenticator(TYPE_FINGERPRINT, mFingerprintProps, mFingerprintAuthenticator); invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, @@ -401,8 +412,7 @@ public class BiometricServiceTest { mBiometricService = new BiometricService(mContext, mInjector); mBiometricService.onStart(); - mBiometricService.mImpl.registerAuthenticator(0 /* id */, - TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG, + mBiometricService.mImpl.registerAuthenticator(TYPE_FINGERPRINT, mFingerprintProps, mFingerprintAuthenticator); invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, @@ -1334,9 +1344,13 @@ public class BiometricServiceTest { for (int i = 0; i < testCases.length; i++) { final BiometricSensor sensor = - new BiometricSensor(mContext, 0 /* id */, + new BiometricSensor(mContext, TYPE_FINGERPRINT, - testCases[i][0], + new FingerprintSensorPropertiesInternal(i /* id */, + Utils.authenticatorStrengthToPropertyStrength(testCases[i][0]), + 5 /* maxEnrollmentsPerUser */, List.of() /* componentInfo */, + FingerprintSensorProperties.TYPE_UNKNOWN, + false /* resetLockoutRequiresHardwareAuthToken */), mock(IBiometricAuthenticator.class)) { @Override boolean confirmationAlwaysRequired(int userId) { @@ -1364,8 +1378,7 @@ public class BiometricServiceTest { when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())) .thenReturn(true); when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true); - mBiometricService.mImpl.registerAuthenticator(0 /* testId */, - TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG, + mBiometricService.mImpl.registerAuthenticator(TYPE_FINGERPRINT, mFingerprintProps, mFingerprintAuthenticator); verify(mBiometricService.mBiometricStrengthController).updateStrengths(); @@ -1376,15 +1389,14 @@ public class BiometricServiceTest { mBiometricService = new BiometricService(mContext, mInjector); mBiometricService.onStart(); - final int testId = 0; - when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true); when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())) .thenReturn(true); when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true); - mBiometricService.mImpl.registerAuthenticator(testId /* id */, - TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG, + + final int testId = SENSOR_ID_FINGERPRINT; + mBiometricService.mImpl.registerAuthenticator(TYPE_FINGERPRINT, mFingerprintProps, mFingerprintAuthenticator); // Downgrade the authenticator @@ -1484,11 +1496,9 @@ public class BiometricServiceTest { mBiometricService.onStart(); mBiometricService.mImpl.registerAuthenticator( - 0 /* id */, 2 /* modality */, 15 /* strength */, - mFingerprintAuthenticator); + 2 /* modality */, mFingerprintProps, mFingerprintAuthenticator); mBiometricService.mImpl.registerAuthenticator( - 0 /* id */, 2 /* modality */, 15 /* strength */, - mFingerprintAuthenticator); + 2 /* modality */, mFingerprintProps, mFingerprintAuthenticator); } @Test(expected = IllegalArgumentException.class) @@ -1498,9 +1508,7 @@ public class BiometricServiceTest { mBiometricService.onStart(); mBiometricService.mImpl.registerAuthenticator( - 0 /* id */, 2 /* modality */, - Authenticators.BIOMETRIC_STRONG /* strength */, - null /* authenticator */); + 2 /* modality */, mFingerprintProps, null /* authenticator */); } @Test @@ -1511,8 +1519,13 @@ public class BiometricServiceTest { for (String s : mInjector.getConfiguration(null)) { SensorConfig config = new SensorConfig(s); - mBiometricService.mImpl.registerAuthenticator(config.id, config.modality, - config.strength, mFingerprintAuthenticator); + mBiometricService.mImpl.registerAuthenticator(config.modality, + new FingerprintSensorPropertiesInternal(config.id, + Utils.authenticatorStrengthToPropertyStrength(config.strength), + 5 /* maxEnrollmentsPerUser */, List.of() /* componentInfo */, + FingerprintSensorProperties.TYPE_UNKNOWN, + false /* resetLockoutRequiresHardwareAuthToken */), + mFingerprintAuthenticator); } } @@ -1609,7 +1622,12 @@ public class BiometricServiceTest { when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true); when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt())) .thenReturn(LockoutTracker.LOCKOUT_NONE); - mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FINGERPRINT, modality, strength, + mBiometricService.mImpl.registerAuthenticator(modality, + new FingerprintSensorPropertiesInternal(SENSOR_ID_FINGERPRINT, + Utils.authenticatorStrengthToPropertyStrength(strength), + 5 /* maxEnrollmentsPerUser */, List.of() /* componentInfo */, + FingerprintSensorProperties.TYPE_UNKNOWN, + false /* resetLockoutRequiresHardwareAuthToken */), mFingerprintAuthenticator); } @@ -1618,7 +1636,13 @@ public class BiometricServiceTest { when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true); when(mFaceAuthenticator.getLockoutModeForUser(anyInt())) .thenReturn(LockoutTracker.LOCKOUT_NONE); - mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FACE, modality, strength, + mBiometricService.mImpl.registerAuthenticator(modality, + new FaceSensorPropertiesInternal(SENSOR_ID_FACE, + Utils.authenticatorStrengthToPropertyStrength(strength), + 5 /* maxEnrollmentsPerUser */, List.of() /* componentInfo */, + FaceSensorProperties.TYPE_UNKNOWN, true /* supportsFace Detection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresHardwareAuthToken */), mFaceAuthenticator); } } @@ -1641,15 +1665,27 @@ public class BiometricServiceTest { when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())) .thenReturn(true); when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true); - mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FINGERPRINT, modality, - strength, mFingerprintAuthenticator); + mBiometricService.mImpl.registerAuthenticator(modality, + new FingerprintSensorPropertiesInternal(SENSOR_ID_FINGERPRINT, + Utils.authenticatorStrengthToPropertyStrength(strength), + 5 /* maxEnrollmentsPerUser */, List.of() /* componentInfo */, + FingerprintSensorProperties.TYPE_UNKNOWN, + false /* resetLockoutRequiresHardwareAuthToken */), + mFingerprintAuthenticator); } if ((modality & BiometricAuthenticator.TYPE_FACE) != 0) { when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true); - mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FACE, modality, - strength, mFaceAuthenticator); + mBiometricService.mImpl.registerAuthenticator(modality, + new FaceSensorPropertiesInternal(SENSOR_ID_FACE, + Utils.authenticatorStrengthToPropertyStrength(strength), + 5 /* maxEnrollmentsPerUser */, List.of() /* componentInfo */, + FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFace Detection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresHardwareAuthToken */), + mFaceAuthenticator); } } } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java index ee5ab92065ee..f7539bd27c9d 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java @@ -16,6 +16,9 @@ package com.android.server.biometrics; +import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; +import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -27,9 +30,13 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; -import android.hardware.biometrics.BiometricManager.Authenticators; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IInvalidationCallback; +import android.hardware.biometrics.SensorPropertiesInternal; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -42,6 +49,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.List; @Presubmit @SmallTest @@ -59,26 +67,54 @@ public class InvalidationTrackerTest { public void testCallbackReceived_whenAllStrongSensorsInvalidated() throws Exception { final IBiometricAuthenticator authenticator1 = mock(IBiometricAuthenticator.class); when(authenticator1.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); - final TestSensor sensor1 = new TestSensor(mContext, 0 /* id */, - BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG, + final TestSensor sensor1 = new TestSensor(mContext, + BiometricAuthenticator.TYPE_FINGERPRINT, + new FingerprintSensorPropertiesInternal(0 /* id */, + STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + List.of() /* componentInfo */, + FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, + false /* resetLockoutRequiresHardwareAuthToken */), authenticator1); final IBiometricAuthenticator authenticator2 = mock(IBiometricAuthenticator.class); when(authenticator2.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); - final TestSensor sensor2 = new TestSensor(mContext, 1 /* id */, - BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG, + final TestSensor sensor2 = new TestSensor(mContext, + BiometricAuthenticator.TYPE_FINGERPRINT, + new FingerprintSensorPropertiesInternal(1 /* id */, + STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + List.of() /* componentInfo */, + FingerprintSensorProperties.TYPE_REAR, + false /* resetLockoutRequiresHardwareAuthToken */), authenticator2); final IBiometricAuthenticator authenticator3 = mock(IBiometricAuthenticator.class); when(authenticator3.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); - final TestSensor sensor3 = new TestSensor(mContext, 2 /* id */, - BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG, + final TestSensor sensor3 = new TestSensor(mContext, + BiometricAuthenticator.TYPE_FACE, + new FaceSensorPropertiesInternal(2 /* id */, + STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + List.of() /* componentInfo */, + FaceSensorProperties.TYPE_RGB, + true /* supportsFace Detection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresHardwareAuthToken */), authenticator3); final IBiometricAuthenticator authenticator4 = mock(IBiometricAuthenticator.class); when(authenticator4.hasEnrolledTemplates(anyInt(), any())).thenReturn(true); - final TestSensor sensor4 = new TestSensor(mContext, 3 /* id */, - BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_WEAK, + final TestSensor sensor4 = new TestSensor(mContext, + BiometricAuthenticator.TYPE_FACE, + new FaceSensorPropertiesInternal(3 /* id */, + STRENGTH_WEAK, + 5 /* maxEnrollmentsPerUser */, + List.of() /* componentInfo */, + FaceSensorProperties.TYPE_IR, + true /* supportsFace Detection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresHardwareAuthToken */), authenticator4); final ArrayList<BiometricSensor> sensors = new ArrayList<>(); @@ -113,9 +149,9 @@ public class InvalidationTrackerTest { private static class TestSensor extends BiometricSensor { - TestSensor(@NonNull Context context, int id, int modality, int strength, + TestSensor(@NonNull Context context, int modality, @NonNull SensorPropertiesInternal props, @NonNull IBiometricAuthenticator impl) { - super(context, id, modality, strength, impl); + super(context, modality, props, impl); } @Override diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java index 903ed9082481..d3f04dfcfa17 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceRegistryTest.java @@ -17,8 +17,6 @@ package com.android.server.biometrics.sensors.face; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; -import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG; -import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK; import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK; @@ -70,9 +68,7 @@ public class FaceServiceRegistryTest { @Mock private ServiceProvider mProvider2; @Captor - private ArgumentCaptor<Integer> mIdCaptor; - @Captor - private ArgumentCaptor<Integer> mStrengthCaptor; + private ArgumentCaptor<FaceSensorPropertiesInternal> mPropsCaptor; private FaceSensorPropertiesInternal mProvider1Props; private FaceSensorPropertiesInternal mProvider2Props; @@ -82,13 +78,13 @@ public class FaceServiceRegistryTest { public void setup() { mProvider1Props = new FaceSensorPropertiesInternal(SENSOR_ID_1, STRENGTH_WEAK, 5 /* maxEnrollmentsPerUser */, - List.of(), FaceSensorProperties.TYPE_RGB, + List.of() /* componentInfo */, FaceSensorProperties.TYPE_RGB, true /* supportsFace Detection */, true /* supportsSelfIllumination */, false /* resetLockoutRequiresHardwareAuthToken */); mProvider2Props = new FaceSensorPropertiesInternal(SENSOR_ID_2, STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, - List.of(), FaceSensorProperties.TYPE_IR, + List.of() /* componentInfo */, FaceSensorProperties.TYPE_IR, true /* supportsFace Detection */, true /* supportsSelfIllumination */, false /* resetLockoutRequiresHardwareAuthToken */); @@ -107,10 +103,9 @@ public class FaceServiceRegistryTest { assertThat(mRegistry.getProviders()).containsExactly(mProvider1, mProvider2); assertThat(mRegistry.getAllProperties()).containsExactly(mProvider1Props, mProvider2Props); verify(mBiometricService, times(2)).registerAuthenticator( - mIdCaptor.capture(), eq(TYPE_FACE), mStrengthCaptor.capture(), any()); - assertThat(mIdCaptor.getAllValues()).containsExactly(SENSOR_ID_1, SENSOR_ID_2); - assertThat(mStrengthCaptor.getAllValues()) - .containsExactly(BIOMETRIC_WEAK, BIOMETRIC_STRONG); + eq(TYPE_FACE), mPropsCaptor.capture(), any()); + assertThat(mPropsCaptor.getAllValues()) + .containsExactly(mProvider1Props, mProvider2Props); } @Test diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java index 7468901a16af..d5d06d3b4eb8 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.face.aidl; +import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT; +import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -148,6 +150,28 @@ public class FaceAuthenticationClientTest { } @Test + public void testLockoutEndsOperation() throws RemoteException { + final FaceAuthenticationClient client = createClient(2); + client.start(mCallback); + client.onLockoutPermanent(); + + verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(), + eq(FACE_ERROR_LOCKOUT_PERMANENT), anyInt()); + verify(mCallback).onClientFinished(client, false); + } + + @Test + public void testTemporaryLockoutEndsOperation() throws RemoteException { + final FaceAuthenticationClient client = createClient(2); + client.start(mCallback); + client.onLockoutTimed(1000); + + verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(), + eq(FACE_ERROR_LOCKOUT), anyInt()); + verify(mCallback).onClientFinished(client, false); + } + + @Test public void notifyHalWhenContextChanges() throws RemoteException { final FaceAuthenticationClient client = createClient(); client.start(mCallback); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java index 13c3f64fec93..6e09069e654b 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceRegistryTest.java @@ -17,8 +17,6 @@ package com.android.server.biometrics.sensors.fingerprint; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; -import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG; -import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK; import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG; import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK; @@ -70,9 +68,7 @@ public class FingerprintServiceRegistryTest { @Mock private ServiceProvider mProvider2; @Captor - private ArgumentCaptor<Integer> mIdCaptor; - @Captor - private ArgumentCaptor<Integer> mStrengthCaptor; + private ArgumentCaptor<FingerprintSensorPropertiesInternal> mPropsCaptor; private FingerprintSensorPropertiesInternal mProvider1Props; private FingerprintSensorPropertiesInternal mProvider2Props; @@ -82,11 +78,11 @@ public class FingerprintServiceRegistryTest { public void setup() { mProvider1Props = new FingerprintSensorPropertiesInternal(SENSOR_ID_1, STRENGTH_WEAK, 5 /* maxEnrollmentsPerUser */, - List.of(), FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, + List.of() /* componentInfo */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, false /* resetLockoutRequiresHardwareAuthToken */); mProvider2Props = new FingerprintSensorPropertiesInternal(SENSOR_ID_2, STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, - List.of(), FingerprintSensorProperties.TYPE_UNKNOWN, + List.of() /* componentInfo */, FingerprintSensorProperties.TYPE_UNKNOWN, false /* resetLockoutRequiresHardwareAuthToken */); when(mProvider1.getSensorProperties()).thenReturn(List.of(mProvider1Props)); @@ -103,10 +99,9 @@ public class FingerprintServiceRegistryTest { assertThat(mRegistry.getProviders()).containsExactly(mProvider1, mProvider2); assertThat(mRegistry.getAllProperties()).containsExactly(mProvider1Props, mProvider2Props); verify(mBiometricService, times(2)).registerAuthenticator( - mIdCaptor.capture(), eq(TYPE_FINGERPRINT), mStrengthCaptor.capture(), any()); - assertThat(mIdCaptor.getAllValues()).containsExactly(SENSOR_ID_1, SENSOR_ID_2); - assertThat(mStrengthCaptor.getAllValues()) - .containsExactly(BIOMETRIC_WEAK, BIOMETRIC_STRONG); + eq(TYPE_FINGERPRINT), mPropsCaptor.capture(), any()); + assertThat(mPropsCaptor.getAllValues()) + .containsExactly(mProvider1Props, mProvider2Props); } @Test diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java index 25a700a5275f..1089c07e6787 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java @@ -110,15 +110,17 @@ public class FingerprintServiceTest { private final FingerprintSensorPropertiesInternal mSensorPropsDefault = new FingerprintSensorPropertiesInternal(ID_DEFAULT, STRENGTH_STRONG, 2 /* maxEnrollmentsPerUser */, - List.of(), + List.of() /* componentInfo */, TYPE_REAR, false /* resetLockoutRequiresHardwareAuthToken */); private final FingerprintSensorPropertiesInternal mSensorPropsVirtual = new FingerprintSensorPropertiesInternal(ID_VIRTUAL, STRENGTH_STRONG, 2 /* maxEnrollmentsPerUser */, - List.of(), + List.of() /* componentInfo */, TYPE_UDFPS_OPTICAL, false /* resetLockoutRequiresHardwareAuthToken */); + @Captor + private ArgumentCaptor<FingerprintSensorPropertiesInternal> mPropsCaptor; private FingerprintService mService; @Before @@ -166,7 +168,8 @@ public class FingerprintServiceTest { mService.mServiceWrapper.registerAuthenticators(HIDL_AUTHENTICATORS); waitForRegistration(); - verify(mIBiometricService).registerAuthenticator(eq(ID_DEFAULT), anyInt(), anyInt(), any()); + verify(mIBiometricService).registerAuthenticator(anyInt(), mPropsCaptor.capture(), any()); + assertThat(mPropsCaptor.getAllValues()).containsExactly(mSensorPropsDefault); } @Test @@ -178,7 +181,8 @@ public class FingerprintServiceTest { mService.mServiceWrapper.registerAuthenticators(HIDL_AUTHENTICATORS); waitForRegistration(); - verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any()); + verify(mIBiometricService).registerAuthenticator(anyInt(), mPropsCaptor.capture(), any()); + assertThat(mPropsCaptor.getAllValues()).containsExactly(mSensorPropsVirtual); } @Test @@ -188,7 +192,8 @@ public class FingerprintServiceTest { mService.mServiceWrapper.registerAuthenticators(HIDL_AUTHENTICATORS); waitForRegistration(); - verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any()); + verify(mIBiometricService).registerAuthenticator(anyInt(), mPropsCaptor.capture(), any()); + assertThat(mPropsCaptor.getAllValues()).containsExactly(mSensorPropsVirtual); } private void waitForRegistration() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java index 3cc6b0103322..5cadc0a5d036 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java @@ -25,7 +25,7 @@ import static org.mockito.Mockito.when; import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.IInputManager; -import android.hardware.input.InputManager; +import android.hardware.input.InputManagerGlobal; import android.os.RemoteException; import android.testing.TestableLooper; import android.view.InputDevice; @@ -38,7 +38,8 @@ import java.util.Objects; import java.util.stream.IntStream; /** - * A test utility class used to share the logic for setting up {@link InputManager}'s callback for + * A test utility class used to share the logic for setting up + * {@link android.hardware.input.InputManager}'s callback for * when a virtual input device being added. */ class InputManagerMockHelper { @@ -76,7 +77,7 @@ class InputManagerMockHelper { // Set a new instance of InputManager for testing that uses the IInputManager mock as the // interface to the server. - InputManager.resetInstance(mIInputManagerMock); + InputManagerGlobal.resetInstance(mIInputManagerMock); } private long handleNativeOpenInputDevice(InvocationOnMock inv) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index 120ddf6af7de..b539a76b521c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -86,6 +86,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { // Test setting default restrictions for managed profile. @Test + @Ignore("b/277916462") public void testMigration_managedProfileOwner() throws Exception { // Create a managed profile user. final File user10dir = getServices().addUser(10, 0, diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index dd81abeec5d3..16aadacb5af6 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1368,6 +1368,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testClearDeviceOwner() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -1955,6 +1956,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testSetUserRestriction_asDo() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -2123,6 +2125,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testSetUserRestriction_asPo() { setAsProfileOwner(admin1); @@ -2259,6 +2262,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { ); @Test + @Ignore("b/277916462") public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception { final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); @@ -2334,6 +2338,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testNoDefaultEnabledUserRestrictions() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -2925,6 +2930,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testCreateAdminSupportIntent() throws Exception { // Setup device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -4993,6 +4999,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testWipeDataManagedProfileOnOrganizationOwnedDevice() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); @@ -7023,6 +7030,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testSetUserControlDisabledPackages_asDO() throws Exception { final List<String> testPackages = new ArrayList<>(); testPackages.add("package_1"); @@ -7038,6 +7046,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testSetUserControlDisabledPackages_asPO() { final List<String> testPackages = new ArrayList<>(); testPackages.add("package_1"); @@ -7776,6 +7785,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testSetUserRestriction_financeDo_validRestrictions_setsRestriction() throws Exception { setDeviceOwner(); @@ -7858,6 +7868,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testSetUninstallBlocked_financeDo_success() throws Exception { String packageName = "com.android.foo.package"; setDeviceOwner(); @@ -7871,6 +7882,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testSetUserControlDisabledPackages_financeDo_success() throws Exception { List<String> packages = new ArrayList<>(); packages.add("com.android.foo.package"); @@ -7960,6 +7972,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testAddPersistentPreferredActivity_financeDo_success() throws Exception { IntentFilter filter = new IntentFilter(); ComponentName target = new ComponentName(admin2.getPackageName(), "test.class"); @@ -7975,6 +7988,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/277916462") public void testClearPackagePersistentPreferredActvities_financeDo_success() throws Exception { String packageName = admin2.getPackageName(); setDeviceOwner(); diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java index ce4b438470df..46956d74cc5c 100644 --- a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java @@ -41,8 +41,8 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.BackgroundThread; import com.android.server.display.BrightnessThrottler.Injector; -import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData; -import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel; +import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData; +import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel; import com.android.server.display.mode.DisplayModeDirectorTest; import org.junit.Before; @@ -93,7 +93,7 @@ public class BrightnessThrottlerTest { ///////////////// @Test - public void testBrightnessThrottlingData() { + public void testThermalBrightnessThrottlingData() { List<ThrottlingLevel> singleLevel = new ArrayList<>(); singleLevel.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f)); @@ -120,32 +120,32 @@ public class BrightnessThrottlerTest { PowerManager.BRIGHTNESS_MAX + EPSILON)); // Test invalid data - BrightnessThrottlingData data; - data = BrightnessThrottlingData.create((List<ThrottlingLevel>)null); + ThermalBrightnessThrottlingData data; + data = ThermalBrightnessThrottlingData.create((List<ThrottlingLevel>) null); assertEquals(data, null); - data = BrightnessThrottlingData.create(new ArrayList<ThrottlingLevel>()); + data = ThermalBrightnessThrottlingData.create(new ArrayList<ThrottlingLevel>()); assertEquals(data, null); - data = BrightnessThrottlingData.create(unsortedThermalLevels); + data = ThermalBrightnessThrottlingData.create(unsortedThermalLevels); assertEquals(data, null); - data = BrightnessThrottlingData.create(unsortedBrightnessLevels); + data = ThermalBrightnessThrottlingData.create(unsortedBrightnessLevels); assertEquals(data, null); - data = BrightnessThrottlingData.create(unsortedLevels); + data = ThermalBrightnessThrottlingData.create(unsortedLevels); assertEquals(data, null); - data = BrightnessThrottlingData.create(invalidLevel); + data = ThermalBrightnessThrottlingData.create(invalidLevel); assertEquals(data, null); // Test valid data - data = BrightnessThrottlingData.create(singleLevel); + data = ThermalBrightnessThrottlingData.create(singleLevel); assertNotEquals(data, null); assertThrottlingLevelsEquals(singleLevel, data.throttlingLevels); - data = BrightnessThrottlingData.create(validLevels); + data = ThermalBrightnessThrottlingData.create(validLevels); assertNotEquals(data, null); assertThrottlingLevelsEquals(validLevels, data.throttlingLevels); } @Test - public void testThrottlingUnsupported() { + public void testThermalThrottlingUnsupported() { final BrightnessThrottler throttler = createThrottlerUnsupported(); assertFalse(throttler.deviceSupportsThrottling()); @@ -157,13 +157,13 @@ public class BrightnessThrottlerTest { } @Test - public void testThrottlingSingleLevel() throws Exception { + public void testThermalThrottlingSingleLevel() throws Exception { final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f); List<ThrottlingLevel> levels = new ArrayList<>(); levels.add(level); - final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels); + final ThermalBrightnessThrottlingData data = ThermalBrightnessThrottlingData.create(levels); final BrightnessThrottler throttler = createThrottlerSupported(data); assertTrue(throttler.deviceSupportsThrottling()); @@ -212,7 +212,7 @@ public class BrightnessThrottlerTest { } @Test - public void testThrottlingMultiLevel() throws Exception { + public void testThermalThrottlingMultiLevel() throws Exception { final ThrottlingLevel levelLo = new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.62f); final ThrottlingLevel levelHi = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, @@ -221,7 +221,7 @@ public class BrightnessThrottlerTest { List<ThrottlingLevel> levels = new ArrayList<>(); levels.add(levelLo); levels.add(levelHi); - final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels); + final ThermalBrightnessThrottlingData data = ThermalBrightnessThrottlingData.create(levels); final BrightnessThrottler throttler = createThrottlerSupported(data); assertTrue(throttler.deviceSupportsThrottling()); @@ -292,32 +292,32 @@ public class BrightnessThrottlerTest { assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason()); } - @Test public void testUpdateThrottlingData() throws Exception { + @Test public void testUpdateThermalThrottlingData() throws Exception { // Initialise brightness throttling levels // Ensure that they are overridden by setting the data through device config. final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f); List<ThrottlingLevel> levels = new ArrayList<>(); levels.add(level); - final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels); - mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,0.4"); + final ThermalBrightnessThrottlingData data = ThermalBrightnessThrottlingData.create(levels); + mDeviceConfigFake.setThermalBrightnessThrottlingData("123,1,critical,0.4"); final BrightnessThrottler throttler = createThrottlerSupported(data); verify(mThermalServiceMock).registerThermalEventListenerWithType( mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN)); final IThermalEventListener listener = mThermalEventListenerCaptor.getValue(); - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.4f); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.4f); // Set new (valid) data from device config - mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,0.8"); - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.8f); + mDeviceConfigFake.setThermalBrightnessThrottlingData("123,1,critical,0.8"); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.8f); - mDeviceConfigFake.setBrightnessThrottlingData( + mDeviceConfigFake.setThermalBrightnessThrottlingData( "123,1,critical,0.75;123,1,critical,0.99,id_2"); - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.75f); - mDeviceConfigFake.setBrightnessThrottlingData( + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.75f); + mDeviceConfigFake.setThermalBrightnessThrottlingData( "123,1,critical,0.8,default;123,1,critical,0.99,id_2"); - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.8f); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.8f); } @Test public void testInvalidThrottlingStrings() throws Exception { @@ -327,45 +327,54 @@ public class BrightnessThrottlerTest { 0.25f); List<ThrottlingLevel> levels = new ArrayList<>(); levels.add(level); - final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels); + final ThermalBrightnessThrottlingData data = ThermalBrightnessThrottlingData.create(levels); final BrightnessThrottler throttler = createThrottlerSupported(data); verify(mThermalServiceMock).registerThermalEventListenerWithType( mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN)); final IThermalEventListener listener = mThermalEventListenerCaptor.getValue(); // None of these are valid so shouldn't override the original data - mDeviceConfigFake.setBrightnessThrottlingData("321,1,critical,0.4"); // Not the current id - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); - mDeviceConfigFake.setBrightnessThrottlingData("123,0,critical,0.4"); // Incorrect number - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); - mDeviceConfigFake.setBrightnessThrottlingData("123,2,critical,0.4"); // Incorrect number - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); - mDeviceConfigFake.setBrightnessThrottlingData("123,1,invalid,0.4"); // Invalid level - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); - mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,none"); // Invalid brightness - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); - mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,-3"); // Invalid brightness - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); - mDeviceConfigFake.setBrightnessThrottlingData("invalid string"); // Invalid format - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); - mDeviceConfigFake.setBrightnessThrottlingData(""); // Invalid format - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + + // Not the current id + mDeviceConfigFake.setThermalBrightnessThrottlingData("321,1,critical,0.4"); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + // Incorrect number + mDeviceConfigFake.setThermalBrightnessThrottlingData("123,0,critical,0.4"); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + // Incorrect number + mDeviceConfigFake.setThermalBrightnessThrottlingData("123,2,critical,0.4"); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + // Invalid level + mDeviceConfigFake.setThermalBrightnessThrottlingData("123,1,invalid,0.4"); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + // Invalid brightness + mDeviceConfigFake.setThermalBrightnessThrottlingData("123,1,critical,none"); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + // Invalid brightness + mDeviceConfigFake.setThermalBrightnessThrottlingData("123,1,critical,-3"); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + // Invalid format + mDeviceConfigFake.setThermalBrightnessThrottlingData("invalid string"); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + // Invalid format + mDeviceConfigFake.setThermalBrightnessThrottlingData(""); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); // Invalid string format - mDeviceConfigFake.setBrightnessThrottlingData( + mDeviceConfigFake.setThermalBrightnessThrottlingData( "123,default,1,critical,0.75,1,critical,0.99"); - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); // Invalid level string and number string - mDeviceConfigFake.setBrightnessThrottlingData( + mDeviceConfigFake.setThermalBrightnessThrottlingData( "123,1,1,critical,0.75,id_2,1,critical,0.99"); - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); // Invalid format - (two default ids for same display) - mDeviceConfigFake.setBrightnessThrottlingData( + mDeviceConfigFake.setThermalBrightnessThrottlingData( "123,1,critical,0.75,default;123,1,critical,0.99"); - testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); + testThermalThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f); } - private void testThrottling(BrightnessThrottler throttler, IThermalEventListener listener, - float tooLowCap, float tooHighCap) throws Exception { + private void testThermalThrottling(BrightnessThrottler throttler, + IThermalEventListener listener, float tooLowCap, float tooHighCap) throws Exception { final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, tooHighCap); @@ -388,7 +397,7 @@ public class BrightnessThrottlerTest { 0.25f); List<ThrottlingLevel> levels = new ArrayList<>(); levels.add(level); - final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels); + final ThermalBrightnessThrottlingData data = ThermalBrightnessThrottlingData.create(levels); // These are identical to the string set below final ThrottlingLevel levelSevere = new ThrottlingLevel(PowerManager.THERMAL_STATUS_SEVERE, @@ -398,7 +407,7 @@ public class BrightnessThrottlerTest { final ThrottlingLevel levelEmergency = new ThrottlingLevel( PowerManager.THERMAL_STATUS_EMERGENCY, 0.1f); - mDeviceConfigFake.setBrightnessThrottlingData( + mDeviceConfigFake.setThermalBrightnessThrottlingData( "123,3,severe,0.9,critical,0.5,emergency,0.1"); final BrightnessThrottler throttler = createThrottlerSupported(data); @@ -466,12 +475,13 @@ public class BrightnessThrottlerTest { private BrightnessThrottler createThrottlerUnsupported() { return new BrightnessThrottler(mInjectorMock, mHandler, mHandler, /* throttlingChangeCallback= */ () -> {}, /* uniqueDisplayId= */ null, - /* throttlingDataId= */ null, /* throttlingDataMap= */ new HashMap<>(1)); + /* thermalThrottlingDataId= */ null, + /* thermalThrottlingDataMap= */ new HashMap<>(1)); } - private BrightnessThrottler createThrottlerSupported(BrightnessThrottlingData data) { + private BrightnessThrottler createThrottlerSupported(ThermalBrightnessThrottlingData data) { assertNotNull(data); - HashMap<String, BrightnessThrottlingData> throttlingDataMap = new HashMap<>(1); + HashMap<String, ThermalBrightnessThrottlingData> throttlingDataMap = new HashMap<>(1); throttlingDataMap.put("default", data); return new BrightnessThrottler(mInjectorMock, mHandler, BackgroundThread.getHandler(), () -> {}, "123", "default", throttlingDataMap); diff --git a/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java b/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java index a7d3df90751f..130e6ad91b49 100644 --- a/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java @@ -84,11 +84,11 @@ public class DeviceStateToLayoutMapTest { } @Test - public void testBrightnessThrottlingMapId() { + public void testThermalBrightnessThrottlingMapId() { Layout configLayout = mDeviceStateToLayoutMap.get(2); - assertEquals("concurrent1", configLayout.getAt(0).getBrightnessThrottlingMapId()); - assertEquals("concurrent2", configLayout.getAt(1).getBrightnessThrottlingMapId()); + assertEquals("concurrent1", configLayout.getAt(0).getThermalBrightnessThrottlingMapId()); + assertEquals("concurrent2", configLayout.getAt(1).getThermalBrightnessThrottlingMapId()); } @Test @@ -108,7 +108,7 @@ public class DeviceStateToLayoutMapTest { } @Test - public void testRefreshRateThermalThrottlingMapId() { + public void testThermalRefreshRateThrottlingMapId() { Layout configLayout = mDeviceStateToLayoutMap.get(4); assertEquals("test2", configLayout.getAt(0).getRefreshRateThermalThrottlingMapId()); @@ -124,12 +124,14 @@ public class DeviceStateToLayoutMapTest { /* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null, mDisplayIdProducerMock, Layout.Display.POSITION_FRONT, Display.DEFAULT_DISPLAY, /* brightnessThrottlingMapId= */ "brightness1", - /* refreshRateZoneId= */ "zone1", /* refreshRateThermalThrottlingMapId= */ "rr1"); + /* refreshRateZoneId= */ "zone1", + /* refreshRateThermalThrottlingMapId= */ "rr1"); testLayout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(678L), /* isDefault= */ false, /* isEnabled= */ false, /* displayGroupName= */ "group1", mDisplayIdProducerMock, Layout.Display.POSITION_REAR, Display.DEFAULT_DISPLAY, /* brightnessThrottlingMapId= */ "brightness2", - /* refreshRateZoneId= */ "zone2", /* refreshRateThermalThrottlingMapId= */ "rr2"); + /* refreshRateZoneId= */ "zone2", + /* refreshRateThermalThrottlingMapId= */ "rr2"); assertEquals(testLayout, configLayout); } @@ -147,7 +149,8 @@ public class DeviceStateToLayoutMapTest { layout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(id), /* isDefault= */ false, enabled, group, mDisplayIdProducerMock, Layout.Display.POSITION_UNKNOWN, Display.DEFAULT_DISPLAY, /* brightnessThrottlingMapId= */ null, - /* refreshRateZoneId= */ null, /* refreshRateThermalThrottlingMapId= */ null); + /* refreshRateZoneId= */ null, + /* refreshRateThermalThrottlingMapId= */ null); } private void setupDeviceStateToLayoutMap() throws IOException { diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java index ed0755949869..5837b21b89fd 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -187,72 +187,72 @@ public final class DisplayDeviceConfigTest { assertArrayEquals(new int[]{-1, 10, 20, 30, 40}, mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux()); - List<DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel> + List<DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel> defaultThrottlingLevels = new ArrayList<>(); defaultThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.4f )); defaultThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.3f )); defaultThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.2f )); defaultThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.1f )); defaultThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.05f )); defaultThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.025f )); - DisplayDeviceConfig.BrightnessThrottlingData defaultThrottlingData = - new DisplayDeviceConfig.BrightnessThrottlingData(defaultThrottlingLevels); + DisplayDeviceConfig.ThermalBrightnessThrottlingData defaultThrottlingData = + new DisplayDeviceConfig.ThermalBrightnessThrottlingData(defaultThrottlingLevels); - List<DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel> + List<DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel> concurrentThrottlingLevels = new ArrayList<>(); concurrentThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.2f )); concurrentThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.15f )); concurrentThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.1f )); concurrentThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.05f )); concurrentThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.025f )); concurrentThrottlingLevels.add( - new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel( + new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel( DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.0125f )); - DisplayDeviceConfig.BrightnessThrottlingData concurrentThrottlingData = - new DisplayDeviceConfig.BrightnessThrottlingData(concurrentThrottlingLevels); + DisplayDeviceConfig.ThermalBrightnessThrottlingData concurrentThrottlingData = + new DisplayDeviceConfig.ThermalBrightnessThrottlingData(concurrentThrottlingLevels); - HashMap<String, DisplayDeviceConfig.BrightnessThrottlingData> throttlingDataMap = + HashMap<String, DisplayDeviceConfig.ThermalBrightnessThrottlingData> throttlingDataMap = new HashMap<>(2); throttlingDataMap.put("default", defaultThrottlingData); throttlingDataMap.put("concurrent", concurrentThrottlingData); assertEquals(throttlingDataMap, - mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId()); + mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId()); assertNotNull(mDisplayDeviceConfig.getHostUsiVersion()); assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2); @@ -351,16 +351,16 @@ public final class DisplayDeviceConfigTest { assertArrayEquals(mDisplayDeviceConfig.getHighAmbientBrightnessThresholds(), HIGH_AMBIENT_THRESHOLD_OF_PEAK_REFRESH_RATE); - // Todo: Add asserts for BrightnessThrottlingData, DensityMapping, + // Todo: Add asserts for ThermalBrightnessThrottlingData, DensityMapping, // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor. } @Test - public void testRefreshRateThermalThrottlingFromDisplayConfig() throws IOException { + public void testThermalRefreshRateThrottlingFromDisplayConfig() throws IOException { setupDisplayDeviceConfigFromDisplayConfigFile(); SparseArray<SurfaceControl.RefreshRateRange> defaultMap = - mDisplayDeviceConfig.getRefreshRateThrottlingData(null); + mDisplayDeviceConfig.getThermalRefreshRateThrottlingData(null); assertNotNull(defaultMap); assertEquals(2, defaultMap.size()); assertEquals(30, defaultMap.get(Temperature.THROTTLING_CRITICAL).min, SMALL_DELTA); @@ -369,7 +369,7 @@ public final class DisplayDeviceConfigTest { assertEquals(30, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).max, SMALL_DELTA); SparseArray<SurfaceControl.RefreshRateRange> testMap = - mDisplayDeviceConfig.getRefreshRateThrottlingData("test"); + mDisplayDeviceConfig.getThermalRefreshRateThrottlingData("test"); assertNotNull(testMap); assertEquals(1, testMap.size()); assertEquals(60, testMap.get(Temperature.THROTTLING_EMERGENCY).min, SMALL_DELTA); diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index 567548e83dc8..7536c7949bcb 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -649,9 +649,9 @@ public class LogicalDisplayMapperTest { assertEquals(0, mLogicalDisplayMapper.getDisplayLocked(device2) .getLeadDisplayIdLocked()); assertEquals("concurrent", mLogicalDisplayMapper.getDisplayLocked(device1) - .getBrightnessThrottlingDataIdLocked()); + .getThermalBrightnessThrottlingDataIdLocked()); assertEquals("concurrent", mLogicalDisplayMapper.getDisplayLocked(device2) - .getBrightnessThrottlingDataIdLocked()); + .getThermalBrightnessThrottlingDataIdLocked()); mLogicalDisplayMapper.setDeviceStateLocked(1, false); advanceTime(1000); @@ -661,10 +661,10 @@ public class LogicalDisplayMapperTest { assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked()); assertEquals(DisplayDeviceConfig.DEFAULT_ID, mLogicalDisplayMapper.getDisplayLocked(device1) - .getBrightnessThrottlingDataIdLocked()); + .getThermalBrightnessThrottlingDataIdLocked()); assertEquals(DisplayDeviceConfig.DEFAULT_ID, mLogicalDisplayMapper.getDisplayLocked(device2) - .getBrightnessThrottlingDataIdLocked()); + .getThermalBrightnessThrottlingDataIdLocked()); mLogicalDisplayMapper.setDeviceStateLocked(2, false); advanceTime(1000); @@ -674,10 +674,10 @@ public class LogicalDisplayMapperTest { assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked()); assertEquals(DisplayDeviceConfig.DEFAULT_ID, mLogicalDisplayMapper.getDisplayLocked(device1) - .getBrightnessThrottlingDataIdLocked()); + .getThermalBrightnessThrottlingDataIdLocked()); assertEquals(DisplayDeviceConfig.DEFAULT_ID, mLogicalDisplayMapper.getDisplayLocked(device2) - .getBrightnessThrottlingDataIdLocked()); + .getThermalBrightnessThrottlingDataIdLocked()); } @Test @@ -863,7 +863,7 @@ public class LogicalDisplayMapperTest { layout.createDisplayLocked(address, /* isDefault= */ false, enabled, group, mIdProducer, Layout.Display.POSITION_UNKNOWN, Display.DEFAULT_DISPLAY, /* brightnessThrottlingMapId= */ null, /* refreshRateZoneId= */ null, - /* refreshRateThrottlingMapId= */ null); + /* refreshRateThermalThrottlingMapId= */ null); } private void advanceTime(long timeMs) { diff --git a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java index db5a46976748..6907145542cc 100644 --- a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java @@ -2583,7 +2583,7 @@ public class DisplayModeDirectorTest { KEY_REFRESH_RATE_IN_HBM_HDR, String.valueOf(fps)); } - public void setBrightnessThrottlingData(String brightnessThrottlingData) { + public void setThermalBrightnessThrottlingData(String brightnessThrottlingData) { putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_BRIGHTNESS_THROTTLING_DATA, brightnessThrottlingData); } diff --git a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt index e1a04ad5ab7d..416b1f49f5d9 100644 --- a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt @@ -19,8 +19,6 @@ package com.android.server.input import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager -import android.content.Context -import android.content.ContextWrapper import android.hardware.BatteryState.STATUS_CHARGING import android.hardware.BatteryState.STATUS_DISCHARGING import android.hardware.BatteryState.STATUS_FULL @@ -31,12 +29,14 @@ import android.hardware.input.IInputDeviceBatteryState import android.hardware.input.IInputDevicesChangedListener import android.hardware.input.IInputManager import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.os.Binder import android.os.IBinder import android.os.test.TestLooper import android.platform.test.annotations.Presubmit +import android.testing.TestableContext import android.view.InputDevice -import androidx.test.InstrumentationRegistry +import androidx.test.core.app.ApplicationProvider import com.android.server.input.BatteryController.BluetoothBatteryManager import com.android.server.input.BatteryController.BluetoothBatteryManager.BluetoothBatteryListener import com.android.server.input.BatteryController.POLLING_PERIOD_MILLIS @@ -66,7 +66,6 @@ import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.eq import org.mockito.Mockito.mock import org.mockito.Mockito.never -import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions @@ -197,17 +196,18 @@ class BatteryControllerTests { private lateinit var bluetoothBatteryManager: BluetoothBatteryManager private lateinit var batteryController: BatteryController - private lateinit var context: Context + private lateinit var context: TestableContext private lateinit var testLooper: TestLooper private lateinit var devicesChangedListener: IInputDevicesChangedListener private val deviceGenerationMap = mutableMapOf<Int /*deviceId*/, Int /*generation*/>() @Before fun setup() { - context = spy(ContextWrapper(InstrumentationRegistry.getContext())) + context = TestableContext(ApplicationProvider.getApplicationContext()) testLooper = TestLooper() - val inputManager = InputManager.resetInstance(iInputManager) - `when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager) + InputManagerGlobal.resetInstance(iInputManager) + val inputManager = InputManager(context) + context.addMockSystemService(InputManager::class.java, inputManager) `when`(iInputManager.inputDeviceIds).then { deviceGenerationMap.keys.toIntArray() } @@ -256,7 +256,7 @@ class BatteryControllerTests { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } @Test diff --git a/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt index 705a5da9d60f..c10f65195307 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.ContextWrapper import android.hardware.input.IInputManager import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.os.test.TestLooper import android.platform.test.annotations.Presubmit import android.provider.Settings @@ -102,7 +103,8 @@ class KeyRemapperTests { dataStore, testLooper.looper ) - val inputManager = InputManager.resetInstance(iInputManager) + InputManagerGlobal.resetInstance(iInputManager) + val inputManager = InputManager(context) Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) .thenReturn(inputManager) Mockito.`when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID)) @@ -110,7 +112,7 @@ class KeyRemapperTests { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } @Test 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 00eb80d21f47..0f4d4e874a2e 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt @@ -23,6 +23,7 @@ import android.hardware.input.IInputManager import android.hardware.input.IKeyboardBacklightListener import android.hardware.input.IKeyboardBacklightState import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.hardware.lights.Light import android.os.UEventObserver import android.os.test.TestLooper @@ -116,7 +117,8 @@ class KeyboardBacklightControllerTests { testLooper = TestLooper() keyboardBacklightController = KeyboardBacklightController(context, native, dataStore, testLooper.looper) - val inputManager = InputManager.resetInstance(iInputManager) + InputManagerGlobal.resetInstance(iInputManager) + val inputManager = InputManager(context) `when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager) `when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID)) `when`(native.setLightColor(anyInt(), anyInt(), anyInt())).then { @@ -131,7 +133,7 @@ class KeyboardBacklightControllerTests { @After fun tearDown() { - InputManager.clearInstance() + InputManagerGlobal.clearInstance() } @Test 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 7729fa29667b..ea3f3bca32ff 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt @@ -25,6 +25,7 @@ import android.content.pm.ResolveInfo import android.content.pm.ServiceInfo import android.hardware.input.IInputManager import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.hardware.input.KeyboardLayout import android.icu.util.ULocale import android.os.Bundle @@ -144,7 +145,8 @@ class KeyboardLayoutManagerTests { } private fun setupInputDevices() { - val inputManager = InputManager.resetInstance(iInputManager) + InputManagerGlobal.resetInstance(iInputManager) + val inputManager = InputManager(context) Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) .thenReturn(inputManager) @@ -852,4 +854,4 @@ class KeyboardLayoutManagerTests { ) } } -}
\ No newline at end of file +} 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 550204b99323..4cfbb9520d5f 100644 --- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java @@ -105,6 +105,7 @@ public class LocaleManagerServiceTest { mMockPackageManager = mock(PackageManager.class); mMockPackageMonitor = mock(PackageMonitor.class); + doReturn(mMockContext).when(mMockContext).createContextAsUser(any(), anyInt()); // For unit tests, set the default installer info doReturn(DEFAULT_INSTALL_SOURCE_INFO).when(mMockPackageManager) .getInstallSourceInfo(anyString()); diff --git a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java index da9de2562930..e20f1e7065d4 100644 --- a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java @@ -131,6 +131,7 @@ public class SystemAppUpdateTrackerTest { doReturn(mMockPackageManager).when(mMockContext).getPackageManager(); doReturn(InstrumentationRegistry.getContext().getContentResolver()) .when(mMockContext).getContentResolver(); + doReturn(mMockContext).when(mMockContext).createContextAsUser(any(), anyInt()); mStoragefile = new AtomicFile(new File( Environment.getExternalStorageDirectory(), "systemUpdateUnitTests.xml")); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index 0b6756d7c063..6bcda3fbcf43 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -178,6 +178,8 @@ public final class UserManagerTest { UserHandle.of(userInfo.id)); assertThat(userContext.getSystemService( UserManager.class).isMediaSharedWithParent()).isTrue(); + assertThat(Settings.Secure.getInt(userContext.getContentResolver(), + Settings.Secure.USER_SETUP_COMPLETE, 0)).isEqualTo(1); List<UserInfo> list = mUserManager.getUsers(); List<UserInfo> cloneUsers = list.stream().filter( diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java index b2843d82a08a..de82854d42ee 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java @@ -422,7 +422,8 @@ public class DexMetadataHelperTest { null /* splitNames */, null /* isFeatureSplits */, null /* usesSplitNames */, null /* configForSplit */, null /* splitApkPaths */, null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(), - null /* requiredSplitTypes */, null /* splitTypes */); + null /* requiredSplitTypes */, null /* splitTypes */, + false /* allowUpdateOwnership */); Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkgLite)); } diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index a0fb3deeb131..21a11bc0e49e 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -763,7 +763,7 @@ public class PowerManagerServiceTest { ArgumentCaptor.forClass(DreamManagerInternal.DreamManagerStateListener.class); verify(mDreamManagerInternalMock).registerDreamManagerStateListener( dreamManagerStateListener.capture()); - dreamManagerStateListener.getValue().onKeepDreamingWhenUndockedChanged(false); + dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(false); when(mBatteryManagerInternalMock.getPlugType()) .thenReturn(BatteryManager.BATTERY_PLUGGED_DOCK); @@ -793,7 +793,7 @@ public class PowerManagerServiceTest { ArgumentCaptor.forClass(DreamManagerInternal.DreamManagerStateListener.class); verify(mDreamManagerInternalMock).registerDreamManagerStateListener( dreamManagerStateListener.capture()); - dreamManagerStateListener.getValue().onKeepDreamingWhenUndockedChanged(true); + dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(true); when(mBatteryManagerInternalMock.getPlugType()) .thenReturn(BatteryManager.BATTERY_PLUGGED_DOCK); @@ -823,7 +823,7 @@ public class PowerManagerServiceTest { ArgumentCaptor.forClass(DreamManagerInternal.DreamManagerStateListener.class); verify(mDreamManagerInternalMock).registerDreamManagerStateListener( dreamManagerStateListener.capture()); - dreamManagerStateListener.getValue().onKeepDreamingWhenUndockedChanged(true); + dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(true); when(mBatteryManagerInternalMock.getPlugType()) .thenReturn(BatteryManager.BATTERY_PLUGGED_DOCK); @@ -831,7 +831,7 @@ public class PowerManagerServiceTest { forceAwake(); // Needs to be awake first before it can dream. forceDream(); - dreamManagerStateListener.getValue().onKeepDreamingWhenUndockedChanged(false); + dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(false); when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0); setPluggedIn(false); @@ -839,6 +839,34 @@ public class PowerManagerServiceTest { } @Test + public void testWakefulnessDream_shouldStopDreamingWhenUnplugging_whenDreamPrevents() { + // Make sure "unplug turns on screen" is configured to true. + when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen)) + .thenReturn(true); + + createService(); + startSystem(); + + ArgumentCaptor<DreamManagerInternal.DreamManagerStateListener> dreamManagerStateListener = + ArgumentCaptor.forClass(DreamManagerInternal.DreamManagerStateListener.class); + verify(mDreamManagerInternalMock).registerDreamManagerStateListener( + dreamManagerStateListener.capture()); + + when(mBatteryManagerInternalMock.getPlugType()) + .thenReturn(BatteryManager.BATTERY_PLUGGED_AC); + setPluggedIn(true); + + forceAwake(); // Needs to be awake first before it can dream. + forceDream(); + dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(false); + when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0); + setPluggedIn(false); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + } + + + @Test public void testWakefulnessDoze_goToSleep() { createService(); // Start with AWAKE state diff --git a/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java b/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java index 2230ddd8a4a7..2bde51b4eb57 100644 --- a/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java +++ b/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java @@ -103,21 +103,45 @@ public class ShutdownCheckPointsTest { } @Test - public void testCallerProcessBinderEntry() throws RemoteException { + public void testCallerProcessBinderEntries() throws RemoteException { List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfos = new ArrayList<>(); runningAppProcessInfos.add( new ActivityManager.RunningAppProcessInfo("process_name", 1, new String[0])); when(mActivityManager.getRunningAppProcesses()).thenReturn(runningAppProcessInfos); mTestInjector.setCurrentTime(1000); + // Matching pid in getRunningAppProcesses mInstance.recordCheckPointInternal(1, "reason1"); + // Mising pid in getRunningAppProcesses + mInstance.recordCheckPointInternal(2, "reason2"); assertEquals( "Shutdown request from BINDER for reason reason1 " + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n" + "com.android.server.power.ShutdownCheckPointsTest" - + ".testCallerProcessBinderEntry\n" - + "From process process_name (pid=1)\n\n", + + ".testCallerProcessBinderEntries\n" + + "From process process_name (pid=1)\n\n" + + "Shutdown request from BINDER for reason reason2 " + + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n" + + "com.android.server.power.ShutdownCheckPointsTest" + + ".testCallerProcessBinderEntries\n" + + "From process ? (pid=2)\n\n", + dumpToString()); + } + + @Test + public void testNullCallerProcessBinderEntries() throws RemoteException { + when(mActivityManager.getRunningAppProcesses()).thenReturn(null); + + mTestInjector.setCurrentTime(1000); + mInstance.recordCheckPointInternal(1, "reason1"); + + assertEquals( + "Shutdown request from BINDER for reason reason1 " + + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n" + + "com.android.server.power.ShutdownCheckPointsTest" + + ".testNullCallerProcessBinderEntries\n" + + "From process ? (pid=1)\n\n", dumpToString()); } diff --git a/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java index 7cf5bc88c213..dca67d6da7ad 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java @@ -14,13 +14,14 @@ * limitations under the License. */ -package com.android.server.power.stats; +package com.android.server.power.stats.wakeups; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_ALARM; +import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN; import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI; -import static com.android.server.power.stats.CpuWakeupStats.WAKEUP_REASON_HALF_WINDOW_MS; +import static com.android.server.power.stats.wakeups.CpuWakeupStats.WAKEUP_REASON_HALF_WINDOW_MS; import static com.google.common.truth.Truth.assertThat; @@ -34,6 +35,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.frameworks.servicestests.R; +import com.android.server.power.stats.wakeups.CpuWakeupStats.Wakeup; import org.junit.Test; import org.junit.runner.RunWith; @@ -46,10 +48,11 @@ import java.util.concurrent.ThreadLocalRandom; @RunWith(AndroidJUnit4.class) public class CpuWakeupStatsTest { private static final String KERNEL_REASON_ALARM_IRQ = "120 test.alarm.device"; - private static final String KERNEL_REASON_WIFI_IRQ = "120 test.wifi.device"; + private static final String KERNEL_REASON_WIFI_IRQ = "130 test.wifi.device"; + private static final String KERNEL_REASON_SOUND_TRIGGER_IRQ = "129 test.sound_trigger.device"; private static final String KERNEL_REASON_UNKNOWN_IRQ = "140 test.unknown.device"; private static final String KERNEL_REASON_UNKNOWN = "free-form-reason test.alarm.device"; - private static final String KERNEL_REASON_UNSUPPORTED = "-1 test.alarm.device"; + private static final String KERNEL_REASON_ALARM_ABNORMAL = "-1 test.alarm.device"; private static final String KERNEL_REASON_ABORT = "Abort: due to test.alarm.device"; private static final int TEST_UID_1 = 13239823; @@ -140,6 +143,40 @@ public class CpuWakeupStatsTest { } @Test + public void soundTriggerIrqAttributionSolo() { + final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler); + final long wakeupTime = 1247121; + + populateDefaultProcStates(obj); + + obj.noteWakeupTimeAndReason(wakeupTime, 1, KERNEL_REASON_SOUND_TRIGGER_IRQ); + + // Outside the window, so should be ignored. + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER, + wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1); + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER, + wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2); + // Should be attributed + obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER, wakeupTime + 5, TEST_UID_3, + TEST_UID_5); + + final SparseArray<SparseIntArray> attribution = obj.mWakeupAttribution.get(wakeupTime); + assertThat(attribution).isNotNull(); + assertThat(attribution.size()).isEqualTo(1); + assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER)).isTrue(); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER).indexOfKey( + TEST_UID_1)).isLessThan(0); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER).indexOfKey( + TEST_UID_2)).isLessThan(0); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER).get(TEST_UID_3)).isEqualTo( + TEST_PROC_STATE_3); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER).indexOfKey( + TEST_UID_4)).isLessThan(0); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER).get(TEST_UID_5)).isEqualTo( + TEST_PROC_STATE_5); + } + + @Test public void wifiIrqAttributionSolo() { final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler); final long wakeupTime = 12423121; @@ -268,22 +305,39 @@ public class CpuWakeupStatsTest { } @Test - public void unsupportedWakeupIgnored() { + public void abnormalAlarmAttribution() { final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler); + populateDefaultProcStates(obj); long wakeupTime = 970934; - obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNSUPPORTED); + obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_ALARM_ABNORMAL); - // Should be ignored as this type of wakeup is unsupported. - assertThat(obj.mWakeupEvents.size()).isEqualTo(0); + assertThat(obj.mWakeupEvents.size()).isEqualTo(1); + assertThat(obj.mWakeupEvents.valueAt(0).mType).isEqualTo(Wakeup.TYPE_ABNORMAL); obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3); obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4); - // Any nearby activity should not end up in the attribution map. - assertThat(obj.mWakeupAttribution.size()).isEqualTo(0); + final SparseArray<SparseIntArray> attribution = obj.mWakeupAttribution.get(wakeupTime); + assertThat(attribution.size()).isEqualTo(1); + assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_ALARM)).isTrue(); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).indexOfKey(TEST_UID_1)).isLessThan( + 0); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).indexOfKey(TEST_UID_2)).isLessThan( + 0); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_3)).isEqualTo( + TEST_PROC_STATE_3); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_4)).isEqualTo( + TEST_PROC_STATE_4); + assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).indexOfKey(TEST_UID_5)).isLessThan( + 0); + } + + @Test + public void abortIgnored() { + final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler); - wakeupTime = 883124; + long wakeupTime = 883124; obj.noteWakeupTimeAndReason(wakeupTime, 3, KERNEL_REASON_ABORT); // Should be ignored as this type of wakeup is unsupported. diff --git a/services/tests/servicestests/src/com/android/server/power/stats/IrqDeviceMapTest.java b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/IrqDeviceMapTest.java index 43d9e60c4a2b..47a8f49e7025 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/IrqDeviceMapTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/IrqDeviceMapTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.power.stats; +package com.android.server.power.stats.wakeups; import static com.google.common.truth.Truth.assertThat; diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java index 07b434538c7b..2ab79fcdeae7 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java @@ -77,16 +77,19 @@ public class InputDeviceDelegateTest { private TestLooper mTestLooper; private ContextWrapper mContextSpy; + private InputManager mInputManager; private InputDeviceDelegate mInputDeviceDelegate; private IInputDevicesChangedListener mIInputDevicesChangedListener; @Before public void setUp() throws Exception { mTestLooper = new TestLooper(); - InputManager inputManager = InputManager.resetInstance(mIInputManagerMock); + InputManagerGlobal.resetInstance(mIInputManagerMock); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); - when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager); + mInputManager = new InputManager(mContextSpy); + when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))) + .thenReturn(mInputManager); doAnswer(invocation -> mIInputDevicesChangedListener = invocation.getArgument(0)) .when(mIInputManagerMock).registerInputDevicesChangedListener(any()); @@ -97,7 +100,7 @@ public class InputDeviceDelegateTest { @After public void tearDown() throws Exception { - InputManager.clearInstance(); + InputManagerGlobal.clearInstance(); } @Test diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index 6bd280aae11d..f158ce14549f 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -47,6 +47,7 @@ import android.content.ContextWrapper; import android.content.pm.PackageManagerInternal; import android.hardware.input.IInputManager; import android.hardware.input.InputManager; +import android.hardware.input.InputManagerGlobal; import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.IVibratorManager; import android.media.AudioAttributes; @@ -184,11 +185,13 @@ public class VibratorManagerServiceTest { private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener mRegisteredAppsOnVirtualDeviceListener; + private InputManager mInputManager; + @Before public void setUp() throws Exception { mTestLooper = new TestLooper(); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); - InputManager inputManager = InputManager.resetInstance(mIInputManagerMock); + InputManagerGlobal.resetInstance(mIInputManagerMock); mVibrationConfig = new VibrationConfig(mContextSpy.getResources()); ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); @@ -196,7 +199,10 @@ public class VibratorManagerServiceTest { mVibrator = new FakeVibrator(mContextSpy); when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibrator); - when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager); + + mInputManager = new InputManager(mContextSpy); + when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))) + .thenReturn(mInputManager); when(mContextSpy.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManagerMock); when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]); when(mPackageManagerInternalMock.getSystemUiServiceComponent()) @@ -259,6 +265,7 @@ public class VibratorManagerServiceTest { LocalServices.removeServiceForTest(PowerManagerInternal.class); // Ignore potential exceptions about the looper having never dispatched any messages. mTestLooper.stopAutoDispatchAndIgnoreExceptions(); + InputManagerGlobal.clearInstance(); } private VibratorManagerService createSystemReadyService() { diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java index 82bc6f6c5263..06fc01738967 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java +++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java @@ -87,6 +87,7 @@ public class UiServiceTestCase { Mockito.doReturn(new Intent()).when(mContext).registerReceiverAsUser( any(), any(), any(), any(), any()); Mockito.doReturn(new Intent()).when(mContext).registerReceiver(any(), any()); + Mockito.doReturn(new Intent()).when(mContext).registerReceiver(any(), any(), anyInt()); Mockito.doNothing().when(mContext).unregisterReceiver(any()); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java index ff6c9769b69f..516fb4aa40c6 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java @@ -15,23 +15,31 @@ */ package com.android.server.notification; -import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY; +import static android.app.Notification.FLAG_AUTO_CANCEL; +import static android.app.Notification.FLAG_BUBBLE; +import static android.app.Notification.FLAG_CAN_COLORIZE; +import static android.app.Notification.FLAG_FOREGROUND_SERVICE; +import static android.app.Notification.FLAG_NO_CLEAR; +import static android.app.Notification.FLAG_ONGOING_EVENT; + +import static com.android.server.notification.GroupHelper.BASE_FLAGS; import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import android.annotation.SuppressLint; import android.app.Notification; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; +import android.util.ArrayMap; import androidx.test.runner.AndroidJUnit4; @@ -45,11 +53,10 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; @SmallTest +@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the class. @RunWith(AndroidJUnit4.class) public class GroupHelperTest extends UiServiceTestCase { private @Mock GroupHelper.Callback mCallback; @@ -82,21 +89,104 @@ public class GroupHelperTest extends UiServiceTestCase { } @Test - public void testNoGroup_postingUnderLimit() throws Exception { + public void testGetAutogroupSummaryFlags_noChildren() { + ArrayMap<String, Integer> children = new ArrayMap<>(); + + assertEquals(BASE_FLAGS, mGroupHelper.getAutogroupSummaryFlags(children)); + } + + @Test + public void testGetAutogroupSummaryFlags_oneOngoing() { + ArrayMap<String, Integer> children = new ArrayMap<>(); + children.put("a", 0); + children.put("b", FLAG_ONGOING_EVENT); + children.put("c", FLAG_BUBBLE); + + assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS, + mGroupHelper.getAutogroupSummaryFlags(children)); + } + + @Test + public void testGetAutogroupSummaryFlags_oneOngoingNoClear() { + ArrayMap<String, Integer> children = new ArrayMap<>(); + children.put("a", 0); + children.put("b", FLAG_ONGOING_EVENT|FLAG_NO_CLEAR); + children.put("c", FLAG_BUBBLE); + + assertEquals(FLAG_NO_CLEAR | FLAG_ONGOING_EVENT | BASE_FLAGS, + mGroupHelper.getAutogroupSummaryFlags(children)); + } + + @Test + public void testGetAutogroupSummaryFlags_oneOngoingBubble() { + ArrayMap<String, Integer> children = new ArrayMap<>(); + children.put("a", 0); + children.put("b", FLAG_ONGOING_EVENT | FLAG_BUBBLE); + children.put("c", FLAG_BUBBLE); + + assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS, + mGroupHelper.getAutogroupSummaryFlags(children)); + } + + @Test + public void testGetAutogroupSummaryFlags_multipleOngoing() { + ArrayMap<String, Integer> children = new ArrayMap<>(); + children.put("a", 0); + children.put("b", FLAG_ONGOING_EVENT); + children.put("c", FLAG_BUBBLE); + children.put("d", FLAG_ONGOING_EVENT); + + assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS, + mGroupHelper.getAutogroupSummaryFlags(children)); + } + + @Test + public void testGetAutogroupSummaryFlags_oneAutoCancel() { + ArrayMap<String, Integer> children = new ArrayMap<>(); + children.put("a", 0); + children.put("b", FLAG_AUTO_CANCEL); + children.put("c", FLAG_BUBBLE); + + assertEquals(BASE_FLAGS, + mGroupHelper.getAutogroupSummaryFlags(children)); + } + + @Test + public void testGetAutogroupSummaryFlags_allAutoCancel() { + ArrayMap<String, Integer> children = new ArrayMap<>(); + children.put("a", FLAG_AUTO_CANCEL); + children.put("b", FLAG_AUTO_CANCEL | FLAG_CAN_COLORIZE); + children.put("c", FLAG_AUTO_CANCEL); + children.put("d", FLAG_AUTO_CANCEL | FLAG_FOREGROUND_SERVICE); + + assertEquals(FLAG_AUTO_CANCEL | BASE_FLAGS, + mGroupHelper.getAutogroupSummaryFlags(children)); + } + + @Test + public void testGetAutogroupSummaryFlags_allAutoCancelOneOngoing() { + ArrayMap<String, Integer> children = new ArrayMap<>(); + children.put("a", FLAG_AUTO_CANCEL); + children.put("b", FLAG_AUTO_CANCEL | FLAG_CAN_COLORIZE); + children.put("c", FLAG_AUTO_CANCEL); + children.put("d", FLAG_AUTO_CANCEL | FLAG_FOREGROUND_SERVICE | FLAG_ONGOING_EVENT); + + assertEquals(FLAG_AUTO_CANCEL| FLAG_ONGOING_EVENT | BASE_FLAGS, + mGroupHelper.getAutogroupSummaryFlags(children)); + } + + @Test + public void testNoGroup_postingUnderLimit() { final String pkg = "package"; for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) { mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false); } - verify(mCallback, never()).addAutoGroupSummary( - eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean()); - verify(mCallback, never()).addAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verifyZeroInteractions(mCallback); } @Test - public void testNoGroup_multiPackage() throws Exception { + public void testNoGroup_multiPackage() { final String pkg = "package"; final String pkg2 = "package2"; for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) { @@ -105,31 +195,23 @@ public class GroupHelperTest extends UiServiceTestCase { } mGroupHelper.onNotificationPosted( getSbn(pkg2, AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM), false); - verify(mCallback, never()).addAutoGroupSummary( - eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean()); - verify(mCallback, never()).addAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verifyZeroInteractions(mCallback); } @Test - public void testNoGroup_multiUser() throws Exception { + public void testNoGroup_multiUser() { final String pkg = "package"; for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) { mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false); } mGroupHelper.onNotificationPosted( - getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.ALL), false); - verify(mCallback, never()).addAutoGroupSummary( - anyInt(), eq(pkg), anyString(), anyBoolean()); - verify(mCallback, never()).addAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.of(7)), false); + verifyZeroInteractions(mCallback); } @Test - public void testNoGroup_someAreGrouped() throws Exception { + public void testNoGroup_someAreGrouped() { final String pkg = "package"; for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) { mGroupHelper.onNotificationPosted( @@ -137,233 +219,344 @@ public class GroupHelperTest extends UiServiceTestCase { } mGroupHelper.onNotificationPosted( getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM, "a"), false); - verify(mCallback, never()).addAutoGroupSummary( - eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean()); - verify(mCallback, never()).addAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verifyZeroInteractions(mCallback); } @Test - public void testPostingOverLimit() throws Exception { + public void testAddSummary() { final String pkg = "package"; for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { mGroupHelper.onNotificationPosted( getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false); } - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false)); + verify(mCallback, times(1)).addAutoGroupSummary( + anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS)); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt()); } @Test - public void testPostingOverLimit_addsOngoingFlag() throws Exception { + public void testAddSummary_oneChildOngoing_summaryOngoing() { final String pkg = "package"; for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); if (i == 0) { - sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; + sbn.getNotification().flags |= FLAG_ONGOING_EVENT; } mGroupHelper.onNotificationPosted(sbn, false); } - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(true)); + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), + eq(BASE_FLAGS | FLAG_ONGOING_EVENT)); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt()); } @Test - public void testAutoGroupCount_addingNoGroupSBN() { + public void testAddSummary_oneChildAutoCancel_summaryNotAutoCancel() { final String pkg = "package"; - ArrayList<StatusBarNotification> notifications = new ArrayList<>(); - for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) { - notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM)); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + if (i == 0) { + sbn.getNotification().flags |= FLAG_AUTO_CANCEL; + } + mGroupHelper.onNotificationPosted(sbn, false); } + verify(mCallback, times(1)).addAutoGroupSummary( + anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS)); + verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt()); + } - for (StatusBarNotification sbn: notifications) { - sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - sbn.setOverrideGroupKey(AUTOGROUP_KEY); + @Test + public void testAddSummary_allChildrenAutoCancel_summaryAutoCancel() { + final String pkg = "package"; + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + sbn.getNotification().flags |= FLAG_AUTO_CANCEL; + mGroupHelper.onNotificationPosted(sbn, false); } + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), + eq(BASE_FLAGS | FLAG_AUTO_CANCEL)); + verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt()); + } - for (StatusBarNotification sbn: notifications) { - mGroupHelper.onNotificationPosted(sbn, true); + @Test + public void testAddSummary_summaryAutoCancelNoClear() { + final String pkg = "package"; + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + sbn.getNotification().flags |= FLAG_AUTO_CANCEL; + if (i == 0) { + sbn.getNotification().flags |= FLAG_NO_CLEAR; + } + mGroupHelper.onNotificationPosted(sbn, false); } - - verify(mCallback, times(AUTOGROUP_AT_COUNT + 1)) - .updateAutogroupSummary(anyInt(), anyString(), eq(true)); - - int userId = UserHandle.SYSTEM.getIdentifier(); - assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg), AUTOGROUP_AT_COUNT + 1); + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), + eq(BASE_FLAGS | FLAG_AUTO_CANCEL | FLAG_NO_CLEAR)); + verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt()); } @Test - public void testAutoGroupCount_UpdateNotification() { + public void testAutoGrouped_allOngoing_updateChildNotOngoing() { final String pkg = "package"; - ArrayList<StatusBarNotification> notifications = new ArrayList<>(); - for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) { - notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM)); - } - for (StatusBarNotification sbn: notifications) { - sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - sbn.setOverrideGroupKey(AUTOGROUP_KEY); + // Post AUTOGROUP_AT_COUNT ongoing notifications + ArrayList<StatusBarNotification> notifications = new ArrayList<>(); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + sbn.getNotification().flags |= FLAG_ONGOING_EVENT; + notifications.add(sbn); } for (StatusBarNotification sbn: notifications) { - mGroupHelper.onNotificationPosted(sbn, true); + mGroupHelper.onNotificationPosted(sbn, false); } - notifications.get(0).getNotification().flags &= ~Notification.FLAG_ONGOING_EVENT; - mGroupHelper.onNotificationUpdated(notifications.get(0)); + // One notification is no longer ongoing + notifications.get(0).getNotification().flags &= ~FLAG_ONGOING_EVENT; + mGroupHelper.onNotificationPosted(notifications.get(0), true); - verify(mCallback, times(AUTOGROUP_AT_COUNT + 2)) - .updateAutogroupSummary(anyInt(), anyString(), eq(true)); - - int userId = UserHandle.SYSTEM.getIdentifier(); - assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg), AUTOGROUP_AT_COUNT); + // Summary should keep FLAG_ONGOING_EVENT if any child has it + verify(mCallback).updateAutogroupSummary( + anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT)); } @Test - public void testAutoGroupCount_UpdateNotificationAfterChanges() { + public void testAutoGrouped_singleOngoing_removeOngoingChild() { final String pkg = "package"; + + // Post AUTOGROUP_AT_COUNT ongoing notifications ArrayList<StatusBarNotification> notifications = new ArrayList<>(); - for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) { - notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM)); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + if (i == 0) { + sbn.getNotification().flags |= FLAG_ONGOING_EVENT; + } + notifications.add(sbn); } for (StatusBarNotification sbn: notifications) { - sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - sbn.setOverrideGroupKey(AUTOGROUP_KEY); + mGroupHelper.onNotificationPosted(sbn, false); } - for (StatusBarNotification sbn: notifications) { - mGroupHelper.onNotificationPosted(sbn, true); - } + // remove ongoing + mGroupHelper.onNotificationRemoved(notifications.get(0)); - notifications.get(0).getNotification().flags &= ~Notification.FLAG_ONGOING_EVENT; + // Summary is no longer ongoing + verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS)); + } - mGroupHelper.onNotificationUpdated(notifications.get(0)); + @Test + public void testAutoGrouped_noOngoing_updateOngoingChild() { + final String pkg = "package"; - notifications.get(0).getNotification().flags |= Notification.FLAG_ONGOING_EVENT; + // Post AUTOGROUP_AT_COUNT ongoing notifications + ArrayList<StatusBarNotification> notifications = new ArrayList<>(); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + notifications.add(sbn); + } - mGroupHelper.onNotificationUpdated(notifications.get(0)); + for (StatusBarNotification sbn: notifications) { + mGroupHelper.onNotificationPosted(sbn, false); + } - verify(mCallback, times(AUTOGROUP_AT_COUNT + 3)) - .updateAutogroupSummary(anyInt(), anyString(), eq(true)); + // update to ongoing + notifications.get(0).getNotification().flags |= FLAG_ONGOING_EVENT; + mGroupHelper.onNotificationPosted(notifications.get(0), true); - int userId = UserHandle.SYSTEM.getIdentifier(); - assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg), AUTOGROUP_AT_COUNT + 1); + // Summary is now ongoing + verify(mCallback).updateAutogroupSummary( + anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT)); } @Test - public void testAutoGroupCount_RemoveNotification() { + public void testAutoGrouped_noOngoing_addOngoingChild() { final String pkg = "package"; + + // Post AUTOGROUP_AT_COUNT ongoing notifications ArrayList<StatusBarNotification> notifications = new ArrayList<>(); - for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) { - notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM)); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + notifications.add(sbn); } for (StatusBarNotification sbn: notifications) { - sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - sbn.setOverrideGroupKey(AUTOGROUP_KEY); + mGroupHelper.onNotificationPosted(sbn, false); } - for (StatusBarNotification sbn: notifications) { - mGroupHelper.onNotificationPosted(sbn, true); + // add ongoing + StatusBarNotification sbn = getSbn(pkg, AUTOGROUP_AT_COUNT + 1, null, UserHandle.SYSTEM); + sbn.getNotification().flags |= FLAG_ONGOING_EVENT; + mGroupHelper.onNotificationPosted(sbn, true); + + // Summary is now ongoing + verify(mCallback).updateAutogroupSummary( + anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT)); + } + + @Test + public void testAutoGrouped_singleOngoing_appGroupOngoingChild() { + final String pkg = "package"; + + // Post AUTOGROUP_AT_COUNT ongoing notifications + ArrayList<StatusBarNotification> notifications = new ArrayList<>(); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + if (i == 0) { + sbn.getNotification().flags |= FLAG_ONGOING_EVENT; + } + notifications.add(sbn); } - mGroupHelper.onNotificationRemoved(notifications.get(0)); + for (StatusBarNotification sbn: notifications) { + mGroupHelper.onNotificationPosted(sbn, false); + } - verify(mCallback, times(AUTOGROUP_AT_COUNT + 2)) - .updateAutogroupSummary(anyInt(), anyString(), eq(true)); + // app group the ongoing child + StatusBarNotification sbn = getSbn(pkg, 0, "0", UserHandle.SYSTEM, "app group now"); + mGroupHelper.onNotificationPosted(sbn, true); - int userId = UserHandle.SYSTEM.getIdentifier(); - assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg), AUTOGROUP_AT_COUNT); + // Summary is no longer ongoing + verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS)); } - @Test - public void testAutoGroupCount_UpdateToNoneOngoingNotification() { + public void testAutoGrouped_singleOngoing_removeNonOngoingChild() { final String pkg = "package"; + + // Post AUTOGROUP_AT_COUNT ongoing notifications ArrayList<StatusBarNotification> notifications = new ArrayList<>(); - for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) { - notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM)); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + if (i == 0) { + sbn.getNotification().flags |= FLAG_ONGOING_EVENT; + } + notifications.add(sbn); } for (StatusBarNotification sbn: notifications) { - sbn.setOverrideGroupKey(AUTOGROUP_KEY); + mGroupHelper.onNotificationPosted(sbn, false); } - for (StatusBarNotification sbn: notifications) { - mGroupHelper.onNotificationPosted(sbn, true); + // remove ongoing + mGroupHelper.onNotificationRemoved(notifications.get(1)); + + // Summary is still ongoing + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt()); + } + + @Test + public void testAutoGrouped_allAutoCancel_updateChildNotAutoCancel() { + final String pkg = "package"; + + // Post AUTOGROUP_AT_COUNT ongoing notifications + ArrayList<StatusBarNotification> notifications = new ArrayList<>(); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + sbn.getNotification().flags |= FLAG_AUTO_CANCEL; + notifications.add(sbn); } - notifications.get(0).getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - mGroupHelper.onNotificationUpdated(notifications.get(0)); + for (StatusBarNotification sbn: notifications) { + mGroupHelper.onNotificationPosted(sbn, false); + } - verify(mCallback, times(1)) - .updateAutogroupSummary(anyInt(), anyString(), eq(true)); + // One notification is no longer autocancelable + notifications.get(0).getNotification().flags &= ~FLAG_AUTO_CANCEL; + mGroupHelper.onNotificationPosted(notifications.get(0), true); - int userId = UserHandle.SYSTEM.getIdentifier(); - assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg), 1); + // Summary should no longer be autocancelable + verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS)); } @Test - public void testAutoGroupCount_AddOneOngoingNotification() { + public void testAutoGrouped_almostAllAutoCancel_updateChildAutoCancel() { final String pkg = "package"; + + // Post AUTOGROUP_AT_COUNT ongoing notifications ArrayList<StatusBarNotification> notifications = new ArrayList<>(); - for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) { - notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM)); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + if (i != 0) { + sbn.getNotification().flags |= FLAG_AUTO_CANCEL; + } + notifications.add(sbn); } - StatusBarNotification sbn = notifications.get(AUTOGROUP_AT_COUNT); - sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - sbn.setOverrideGroupKey(AUTOGROUP_KEY); - - for (StatusBarNotification current: notifications) { - mGroupHelper.onNotificationPosted(current, true); + for (StatusBarNotification sbn: notifications) { + mGroupHelper.onNotificationPosted(sbn, false); } - verify(mCallback, times(1)) - .updateAutogroupSummary(anyInt(), anyString(), eq(true)); + // Missing notification is now autocancelable + notifications.get(0).getNotification().flags |= FLAG_AUTO_CANCEL; + mGroupHelper.onNotificationPosted(notifications.get(0), true); - int userId = UserHandle.SYSTEM.getIdentifier(); - assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg), 1); + // Summary should now autocancelable + verify(mCallback).updateAutogroupSummary( + anyInt(), anyString(), eq(BASE_FLAGS | FLAG_AUTO_CANCEL)); } @Test - public void testAutoGroupCount_UpdateNoneOngoing() { + public void testAutoGrouped_allAutoCancel_updateChildAppGrouped() { final String pkg = "package"; + + // Post AUTOGROUP_AT_COUNT ongoing notifications ArrayList<StatusBarNotification> notifications = new ArrayList<>(); - for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) { - notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM)); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + sbn.getNotification().flags |= FLAG_AUTO_CANCEL; + notifications.add(sbn); } for (StatusBarNotification sbn: notifications) { - sbn.setOverrideGroupKey(AUTOGROUP_KEY); + mGroupHelper.onNotificationPosted(sbn, false); + } + + // One notification is now grouped by app + StatusBarNotification sbn = getSbn(pkg, 0, "0", UserHandle.SYSTEM, "app group now"); + mGroupHelper.onNotificationPosted(sbn, true); + + // Summary should be still be autocancelable + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt()); + } + + @Test + public void testAutoGrouped_allAutoCancel_removeChild() { + final String pkg = "package"; + + // Post AUTOGROUP_AT_COUNT ongoing notifications + ArrayList<StatusBarNotification> notifications = new ArrayList<>(); + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + sbn.getNotification().flags |= FLAG_AUTO_CANCEL; + notifications.add(sbn); } for (StatusBarNotification sbn: notifications) { - mGroupHelper.onNotificationPosted(sbn, true); + mGroupHelper.onNotificationPosted(sbn, false); } - verify(mCallback, times(0)) - .updateAutogroupSummary(anyInt(), anyString(), eq(true)); + mGroupHelper.onNotificationRemoved(notifications.get(0)); - int userId = UserHandle.SYSTEM.getIdentifier(); - assertEquals(mGroupHelper.getOngoingGroupCount(userId, pkg), 0); + // Summary should still be autocancelable + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt()); } - @Test - public void testDropToZeroRemoveGroup() throws Exception { + public void testDropToZeroRemoveGroup() { final String pkg = "package"; List<StatusBarNotification> posted = new ArrayList<>(); for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { @@ -371,7 +564,8 @@ public class GroupHelperTest extends UiServiceTestCase { posted.add(sbn); mGroupHelper.onNotificationPosted(sbn, false); } - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false)); + verify(mCallback, times(1)).addAutoGroupSummary( + anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS)); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -390,7 +584,7 @@ public class GroupHelperTest extends UiServiceTestCase { } @Test - public void testAppStartsGrouping() throws Exception { + public void testAppStartsGrouping() { final String pkg = "package"; List<StatusBarNotification> posted = new ArrayList<>(); for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { @@ -399,7 +593,7 @@ public class GroupHelperTest extends UiServiceTestCase { mGroupHelper.onNotificationPosted(sbn, false); } verify(mCallback, times(1)).addAutoGroupSummary( - anyInt(), eq(pkg), anyString(), anyBoolean()); + anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS)); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -408,9 +602,10 @@ public class GroupHelperTest extends UiServiceTestCase { for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { final StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "app group"); - mGroupHelper.onNotificationPosted(sbn, false); + sbn.setOverrideGroupKey("autogrouped"); + mGroupHelper.onNotificationPosted(sbn, true); verify(mCallback, times(1)).removeAutoGroup(sbn.getKey()); - if (i < AUTOGROUP_AT_COUNT -1) { + if (i < AUTOGROUP_AT_COUNT - 1) { verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); } } @@ -418,8 +613,7 @@ public class GroupHelperTest extends UiServiceTestCase { } @Test - public void testNewNotificationsAddedToAutogroup_ifOriginalNotificationsCanceled() - throws Exception { + public void testNewNotificationsAddedToAutogroup_ifOriginalNotificationsCanceled() { final String pkg = "package"; List<StatusBarNotification> posted = new ArrayList<>(); for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { @@ -427,7 +621,8 @@ public class GroupHelperTest extends UiServiceTestCase { posted.add(sbn); mGroupHelper.onNotificationPosted(sbn, false); } - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false)); + verify(mCallback, times(1)).addAutoGroupSummary( + anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS)); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -441,10 +636,7 @@ public class GroupHelperTest extends UiServiceTestCase { Mockito.reset(mCallback); // only one child remains - Map<String, LinkedHashSet<String>> ungroupedForUser = - mGroupHelper.mUngroupedNotifications.get(UserHandle.USER_SYSTEM); - assertNotNull(ungroupedForUser); - assertEquals(1, ungroupedForUser.get(pkg).size()); + assertEquals(1, mGroupHelper.getNotGroupedByAppCount(UserHandle.USER_SYSTEM, pkg)); // Add new notification; it should be autogrouped even though the total count is // < AUTOGROUP_AT_COUNT @@ -454,5 +646,8 @@ public class GroupHelperTest extends UiServiceTestCase { verify(mCallback, times(1)).addAutoGroup(sbn.getKey()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS)); + verify(mCallback, never()).addAutoGroupSummary( + anyInt(), anyString(), anyString(), anyInt()); } } 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 1ba6ad7c9f34..9cfdaa7cad0c 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -28,6 +28,7 @@ import static android.app.Notification.FLAG_CAN_COLORIZE; import static android.app.Notification.FLAG_FOREGROUND_SERVICE; import static android.app.Notification.FLAG_NO_CLEAR; import static android.app.Notification.FLAG_ONGOING_EVENT; +import static android.app.Notification.FLAG_USER_INITIATED_JOB; import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; @@ -227,6 +228,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; import com.android.server.UiServiceTestCase; +import com.android.server.job.JobSchedulerInternal; import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; import com.android.server.notification.NotificationManagerService.NotificationAssistants; @@ -335,6 +337,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Mock ActivityManagerInternal mAmi; @Mock + JobSchedulerInternal mJsi; + @Mock private Looper mMainLooper; @Mock private NotificationManager mMockNm; @@ -443,6 +447,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mAmi); + LocalServices.removeServiceForTest(JobSchedulerInternal.class); + LocalServices.addService(JobSchedulerInternal.class, mJsi); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); LocalServices.removeServiceForTest(PermissionPolicyInternal.class); @@ -748,13 +754,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, String groupKey, boolean isSummary) { + return generateNotificationRecord(channel, id, "tag" + System.currentTimeMillis(), groupKey, + isSummary); + } + + private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, + String tag, String groupKey, boolean isSummary) { Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setGroup(groupKey) .setGroupSummary(isSummary); StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, - "tag" + System.currentTimeMillis(), mUid, 0, + tag, mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); return new NotificationRecord(mContext, sbn, channel); } @@ -1251,7 +1263,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { waitForIdle(); update = new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE); - update.setFgServiceShown(true); + update.setUserVisibleTaskShown(true); mBinderService.updateNotificationChannelForPackage(PKG, mUid, update); waitForIdle(); assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( @@ -1893,7 +1905,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.mSummaryByGroupKey.put("pkg", summary); mService.mAutobundledSummaries.put(0, new ArrayMap<>()); mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); - mService.updateAutobundledSummaryFlags(0, "pkg", true, false); + mService.updateAutobundledSummaryFlags( + 0, "pkg", GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, false); assertTrue(summary.getSbn().isOngoing()); } @@ -1909,7 +1922,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); mService.mSummaryByGroupKey.put("pkg", summary); - mService.updateAutobundledSummaryFlags(0, "pkg", false, false); + mService.updateAutobundledSummaryFlags(0, "pkg", GroupHelper.BASE_FLAGS, false); assertFalse(summary.getSbn().isOngoing()); } @@ -2891,7 +2904,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true); NotificationRecord r = mService.createAutoGroupSummary( - temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), false); + temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), 0); assertThat(r.isImportanceFixed()).isTrue(); } @@ -4207,7 +4220,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testOnlyAutogroupIfGroupChanged_noPriorNoti_autogroups() throws Exception { + public void testOnlyAutogroupIfNeeded_newNotification_ghUpdate() { NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); mService.addEnqueuedNotification(r); NotificationManagerService.PostNotificationRunnable runnable = @@ -4220,17 +4233,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testOnlyAutogroupIfGroupChanged_groupChanged_autogroups() - throws Exception { - NotificationRecord r = - generateNotificationRecord(mTestNotificationChannel, 0, "group", false); + public void testOnlyAutogroupIfNeeded_groupChanged_ghUpdate() { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, + "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", "group", false); mService.addNotification(r); - r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); - mService.addEnqueuedNotification(r); + NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, + "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", null, false); + mService.addEnqueuedNotification(update); NotificationManagerService.PostNotificationRunnable runnable = - mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + mService.new PostNotificationRunnable(update.getKey(), + update.getSbn().getPackageName(), update.getUid(), + SystemClock.elapsedRealtime()); runnable.run(); waitForIdle(); @@ -4238,16 +4252,39 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testOnlyAutogroupIfGroupChanged_noGroupChanged_autogroups() - throws Exception { - NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "group", - false); + public void testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate() { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, + "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", "group", false); mService.addNotification(r); - mService.addEnqueuedNotification(r); + NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, + "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", null, false); + update.getNotification().flags = FLAG_AUTO_CANCEL; + mService.addEnqueuedNotification(update); NotificationManagerService.PostNotificationRunnable runnable = - mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), SystemClock.elapsedRealtime()); + mService.new PostNotificationRunnable(update.getKey(), + update.getSbn().getPackageName(), update.getUid(), + SystemClock.elapsedRealtime()); + runnable.run(); + waitForIdle(); + + verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); + } + + @Test + public void testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate() { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, + "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false); + mService.addNotification(r); + NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, + "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false); + update.getNotification().color = Color.BLACK; + mService.addEnqueuedNotification(update); + + NotificationManagerService.PostNotificationRunnable runnable = + mService.new PostNotificationRunnable(update.getKey(), + update.getSbn().getPackageName(), + update.getUid(), SystemClock.elapsedRealtime()); runnable.run(); waitForIdle(); @@ -8609,7 +8646,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertNotNull(n.publicVersion.bigContentView); assertNotNull(n.publicVersion.headsUpContentView); - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); assertNull(n.contentView); assertNull(n.bigContentView); @@ -10214,10 +10251,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // grouphelper is a mock here, so make the calls it would make - // add summary; wait for it to be posted - mService.addAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), nr1.getKey(), - true); - waitForIdle(); + // add summary + mService.addNotification(mService.createAutoGroupSummary(nr1.getUserId(), + nr1.getSbn().getPackageName(), nr1.getKey(), + GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT)); // cancel both children mBinderService.cancelNotificationWithTag(PKG, PKG, nr0.getSbn().getTag(), @@ -10226,9 +10263,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { nr1.getSbn().getId(), nr1.getSbn().getUserId()); waitForIdle(); - // group helper would send 'remove flag' and then 'remove summary' events - mService.updateAutobundledSummaryFlags(nr1.getUserId(), nr1.getSbn().getPackageName(), - false, false); + // group helper would send 'remove summary' event mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName()); waitForIdle(); @@ -10439,7 +10474,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setFullScreenIntent(mock(PendingIntent.class), true) .build(); - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); final int stickyFlag = n.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED; @@ -10524,7 +10559,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setFlag(FLAG_CAN_COLORIZE, true) .build(); - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); assertFalse(n.isForegroundService()); assertFalse(n.hasColorizedPermission()); @@ -10552,7 +10587,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should not be set assertSame(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10571,7 +10606,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should be set assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10595,7 +10630,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should be set assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10612,7 +10647,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should not be set assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10630,7 +10665,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { n.flags |= Notification.FLAG_NO_DISMISS; // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should be cleared assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10648,7 +10683,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should not be set assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10669,7 +10704,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { n.flags |= Notification.FLAG_NO_DISMISS; // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should be cleared assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10686,7 +10721,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should not be set assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10705,7 +10740,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should be set assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10733,7 +10768,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should be cleared assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); @@ -10754,12 +10789,589 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .build(); // When: fix the notification with NotificationManagerService - mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE); + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should not be set assertSame(0, n.flags & Notification.FLAG_NO_DISMISS); } + @Test + public void testCancelAllNotifications_IgnoreUserInitiatedJob() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); + sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotifications_IgnoreUserInitiatedJob", + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + mBinderService.cancelAllNotifications(PKG, sbn.getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(sbn.getPackageName()); + assertEquals(1, notifs.length); + assertEquals(1, mService.getNotificationRecordCount()); + } + + @Test + public void testCancelAllNotifications_UijFlag_NoUij_Allowed() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(false); + final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); + sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotifications_UijFlag_NoUij_Allowed", + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + mBinderService.cancelAllNotifications(PKG, sbn.getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(sbn.getPackageName()); + assertEquals(0, notifs.length); + } + + @Test + public void testCancelAllNotificationsOtherPackage_IgnoresUijNotification() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); + sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotifications_IgnoreOtherPackages", + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(sbn.getPackageName()); + assertEquals(1, notifs.length); + assertEquals(1, mService.getNotificationRecordCount()); + } + + @Test + public void testRemoveUserInitiatedJobFlag_ImmediatelyAfterEnqueue() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .build(); + StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + mInternalService.removeUserInitiatedJobFlagFromNotification(PKG, sbn.getId(), + sbn.getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(sbn.getPackageName()); + assertFalse(notifs[0].getNotification().isUserInitiatedJob()); + } + + @Test + public void testCancelAfterSecondEnqueueDoesNotSpecifyUserInitiatedJobFlag() throws Exception { + final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); + sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | FLAG_USER_INITIATED_JOB; + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + mBinderService.cancelNotificationWithTag(PKG, PKG, sbn.getTag(), sbn.getId(), + sbn.getUserId()); + waitForIdle(); + assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); + assertEquals(0, mService.getNotificationRecordCount()); + } + + @Test + public void testCancelNotificationWithTag_fromApp_cannotCancelUijChild() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + mService.isSystemUid = false; + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.getBinderService().cancelNotificationWithTag( + parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), + parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(1, notifs.length); + } + + @Test + public void testCancelNotificationWithTag_fromApp_cannotCancelUijParent() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + mService.isSystemUid = false; + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.getBinderService().cancelNotificationWithTag( + parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), + parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(3, notifs.length); + } + + @Test + public void testCancelAllNotificationsFromApp_cannotCancelUijChild() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + mService.isSystemUid = false; + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; + final NotificationRecord newGroup = generateNotificationRecord( + mTestNotificationChannel, 4, "group2", false); + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.addNotification(newGroup); + mService.getBinderService().cancelAllNotifications( + parent.getSbn().getPackageName(), parent.getSbn().getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(1, notifs.length); + } + + @Test + public void testCancelAllNotifications_fromApp_cannotCancelUijParent() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + mService.isSystemUid = false; + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + final NotificationRecord newGroup = generateNotificationRecord( + mTestNotificationChannel, 4, "group2", false); + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.addNotification(newGroup); + mService.getBinderService().cancelAllNotifications( + parent.getSbn().getPackageName(), parent.getSbn().getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(1, notifs.length); + } + + @Test + public void testCancelNotificationsFromListener_clearAll_GroupWithUijParent() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + final NotificationRecord newGroup = generateNotificationRecord( + mTestNotificationChannel, 4, "group2", false); + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.addNotification(newGroup); + mService.getBinderService().cancelNotificationsFromListener(null, null); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(0, notifs.length); + } + + @Test + public void testCancelNotificationsFromListener_clearAll_GroupWithUijChild() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; + final NotificationRecord newGroup = generateNotificationRecord( + mTestNotificationChannel, 4, "group2", false); + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.addNotification(newGroup); + mService.getBinderService().cancelNotificationsFromListener(null, null); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(0, notifs.length); + } + + @Test + public void testCancelNotificationsFromListener_clearAll_Uij() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, null, false); + child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mService.addNotification(child2); + mService.getBinderService().cancelNotificationsFromListener(null, null); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); + assertEquals(0, notifs.length); + } + + @Test + public void testCancelNotificationsFromListener_byKey_GroupWithUijParent() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + final NotificationRecord newGroup = generateNotificationRecord( + mTestNotificationChannel, 4, "group2", false); + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.addNotification(newGroup); + String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), + child2.getSbn().getKey(), newGroup.getSbn().getKey()}; + mService.getBinderService().cancelNotificationsFromListener(null, keys); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(0, notifs.length); + } + + @Test + public void testCancelNotificationsFromListener_byKey_GroupWithUijChild() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; + final NotificationRecord newGroup = generateNotificationRecord( + mTestNotificationChannel, 4, "group2", false); + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.addNotification(newGroup); + String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), + child2.getSbn().getKey(), newGroup.getSbn().getKey()}; + mService.getBinderService().cancelNotificationsFromListener(null, keys); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(0, notifs.length); + } + + @Test + public void testCancelNotificationsFromListener_byKey_Uij() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 3, null, false); + child.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mService.addNotification(child); + String[] keys = {child.getSbn().getKey()}; + mService.getBinderService().cancelNotificationsFromListener(null, keys); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(child.getSbn().getPackageName()); + assertEquals(0, notifs.length); + } + + @Test + public void testUserInitiatedCancelAllWithGroup_UserInitiatedFlag() throws Exception { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + final NotificationRecord parent = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + final NotificationRecord child = generateNotificationRecord( + mTestNotificationChannel, 2, "group", false); + final NotificationRecord child2 = generateNotificationRecord( + mTestNotificationChannel, 3, "group", false); + child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; + final NotificationRecord newGroup = generateNotificationRecord( + mTestNotificationChannel, 4, "group2", false); + mService.addNotification(parent); + mService.addNotification(child); + mService.addNotification(child2); + mService.addNotification(newGroup); + mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), parent.getUserId()); + waitForIdle(); + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); + assertEquals(0, notifs.length); + } + + @Test + public void testDeleteChannelGroupChecksForUijs() throws Exception { + when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid))) + .thenReturn(singletonList(mock(AssociationInfo.class))); + CountDownLatch latch = new CountDownLatch(2); + mService.createNotificationChannelGroup(PKG, mUid, + new NotificationChannelGroup("group", "group"), true, false); + new Thread(() -> { + NotificationChannel notificationChannel = new NotificationChannel("id", "id", + NotificationManager.IMPORTANCE_HIGH); + notificationChannel.setGroup("group"); + ParceledListSlice<NotificationChannel> pls = + new ParceledListSlice(ImmutableList.of(notificationChannel)); + try { + mBinderService.createNotificationChannelsForPackage(PKG, mUid, pls); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + latch.countDown(); + }).start(); + new Thread(() -> { + try { + synchronized (this) { + wait(5000); + } + mService.createNotificationChannelGroup(PKG, mUid, + new NotificationChannelGroup("new", "new group"), true, false); + NotificationChannel notificationChannel = + new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH); + notificationChannel.setGroup("new"); + ParceledListSlice<NotificationChannel> pls = + new ParceledListSlice(ImmutableList.of(notificationChannel)); + try { + mBinderService.createNotificationChannelsForPackage(PKG, mUid, pls); + mBinderService.deleteNotificationChannelGroup(PKG, "group"); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } catch (Exception e) { + e.printStackTrace(); + } + latch.countDown(); + }).start(); + + latch.await(); + verify(mJsi).isNotificationChannelAssociatedWithAnyUserInitiatedJobs( + anyString(), anyInt(), anyString()); + } + + @Test + public void testRemoveUserInitiatedJobFlagFromNotification_enqueued() { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + Notification n = new Notification.Builder(mContext, "").build(); + n.flags |= FLAG_USER_INITIATED_JOB; + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addEnqueuedNotification(r); + + mInternalService.removeUserInitiatedJobFlagFromNotification( + PKG, r.getSbn().getId(), r.getSbn().getUserId()); + + waitForIdle(); + + verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any()); + } + + @Test + public void testRemoveUserInitiatedJobFlagFromNotification_posted() { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + Notification n = new Notification.Builder(mContext, "").build(); + n.flags |= FLAG_USER_INITIATED_JOB; + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addNotification(r); + + mInternalService.removeUserInitiatedJobFlagFromNotification( + PKG, r.getSbn().getId(), r.getSbn().getUserId()); + + waitForIdle(); + + ArgumentCaptor<NotificationRecord> captor = + ArgumentCaptor.forClass(NotificationRecord.class); + verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any()); + + assertEquals(0, captor.getValue().getNotification().flags); + } + + @Test + public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_enqueued() { + for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { + Notification n = new Notification.Builder(mContext, "").build(); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, i, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + mService.addEnqueuedNotification(r); + } + Notification n = new Notification.Builder(mContext, "").build(); + n.flags |= FLAG_USER_INITIATED_JOB; + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, + NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addEnqueuedNotification(r); + + mInternalService.removeUserInitiatedJobFlagFromNotification( + PKG, r.getSbn().getId(), r.getSbn().getUserId()); + + waitForIdle(); + + assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, + mService.getNotificationRecordCount()); + } + + @Test + public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_posted() { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { + Notification n = new Notification.Builder(mContext, "").build(); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, i, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + mService.addNotification(r); + } + Notification n = new Notification.Builder(mContext, "").build(); + n.flags |= FLAG_USER_INITIATED_JOB; + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, + NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addNotification(r); + + mInternalService.removeUserInitiatedJobFlagFromNotification( + PKG, r.getSbn().getId(), r.getSbn().getUserId()); + + waitForIdle(); + + assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, + mService.getNotificationRecordCount()); + } + + @Test + public void testCanPostUijWhenOverLimit() throws RemoteException { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { + StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, + i, null, false).getSbn(); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testCanPostUijWhenOverLimit", + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + } + + final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); + sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCanPostUijWhenOverLimit - uij over limit!", + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + + waitForIdle(); + + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(sbn.getPackageName()); + assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); + assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, + mService.getNotificationRecordCount()); + } + + @Test + public void testCannotPostNonUijWhenOverLimit() throws RemoteException { + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(true); + for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { + StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, + i, null, false).getSbn(); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testCannotPostNonUijWhenOverLimit", + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + waitForIdle(); + } + + final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, + 100, null, false).getSbn(); + sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCannotPostNonUijWhenOverLimit - uij over limit!", + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + + final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel, + 101, null, false).getSbn(); + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCannotPostNonUijWhenOverLimit - non uij over limit!", + sbn2.getId(), sbn2.getNotification(), sbn2.getUserId()); + + when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) + .thenReturn(false); + final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel, + 101, null, false).getSbn(); + sbn3.getNotification().flags |= FLAG_USER_INITIATED_JOB; + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCannotPostNonUijWhenOverLimit - fake uij over limit!", + sbn3.getId(), sbn3.getNotification(), sbn3.getUserId()); + + waitForIdle(); + + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(sbn.getPackageName()); + assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); + assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, + mService.getNotificationRecordCount()); + } + + @Test + public void fixNotification_withUijFlag_butIsNotUij() throws Exception { + final ApplicationInfo applicationInfo = new ApplicationInfo(); + when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(applicationInfo); + + Notification n = new Notification.Builder(mContext, "test") + .setFlag(FLAG_USER_INITIATED_JOB, true) + .build(); + + mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); + assertFalse(n.isUserInitiatedJob()); + } + private void setDpmAppOppsExemptFromDismissal(boolean isOn) { DeviceConfig.setProperty( DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER, diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordExtractorDataTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordExtractorDataTest.java index e6569f7e0ce2..9fe0e49c4ab8 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordExtractorDataTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordExtractorDataTest.java @@ -98,6 +98,41 @@ public class NotificationRecordExtractorDataTest extends UiServiceTestCase { } @Test + public void testHasDiffs_autoBundled() { + NotificationRecord r = generateRecord(); + + NotificationRecordExtractorData extractorData = new NotificationRecordExtractorData( + 1, + r.getPackageVisibilityOverride(), + r.canShowBadge(), + r.canBubble(), + r.getNotification().isBubbleNotification(), + r.getChannel(), + r.getGroupKey(), + r.getPeopleOverride(), + r.getSnoozeCriteria(), + r.getUserSentiment(), + r.getSuppressedVisualEffects(), + r.getSystemGeneratedSmartActions(), + r.getSmartReplies(), + r.getImportance(), + r.getRankingScore(), + r.isConversation(), + r.getProposedImportance(), + r.hasSensitiveContent()); + + Bundle signals = new Bundle(); + signals.putString(Adjustment.KEY_GROUP_KEY, "ranker_group"); + Adjustment adjustment = new Adjustment("pkg", r.getKey(), signals, "", 0); + r.addAdjustment(adjustment); + NotificationAdjustmentExtractor adjustmentExtractor = new NotificationAdjustmentExtractor(); + adjustmentExtractor.process(r); + + assertTrue(extractorData.hasDiffForRankingLocked(r, 1)); + assertTrue(extractorData.hasDiffForLoggingLocked(r, 1)); + } + + @Test public void testHasDiffs_sensitiveContentChange() { NotificationRecord r = generateRecord(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index b1a9f081253c..34bb664c9598 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -96,8 +96,6 @@ public class RoleObserverTest extends UiServiceTestCase { private TestableNotificationManagerService mService; private NotificationManagerService.RoleObserver mRoleObserver; - private TestableContext mContext = spy(getContext()); - @Mock private PreferencesHelper mPreferencesHelper; @Mock diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java new file mode 100644 index 000000000000..bcd807ab6d2f --- /dev/null +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.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.notification; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; + +import android.content.ComponentName; +import android.net.Uri; +import android.provider.Settings; +import android.service.notification.Condition; +import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeDiff; +import android.service.notification.ZenPolicy; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.ArrayMap; + +import androidx.test.filters.SmallTest; + +import com.android.server.UiServiceTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class ZenModeDiffTest extends UiServiceTestCase { + // version is not included in the diff; manual & automatic rules have special handling + public static final Set<String> ZEN_MODE_CONFIG_EXEMPT_FIELDS = + Set.of("version", "manualRule", "automaticRules"); + + @Test + public void testRuleDiff_addRemoveSame() { + // Test add, remove, and both sides same + ZenModeConfig.ZenRule r = makeRule(); + + // Both sides same rule + ZenModeDiff.RuleDiff dSame = new ZenModeDiff.RuleDiff(r, r); + assertFalse(dSame.hasDiff()); + + // from existent rule to null: expect deleted + ZenModeDiff.RuleDiff deleted = new ZenModeDiff.RuleDiff(r, null); + assertTrue(deleted.hasDiff()); + assertTrue(deleted.wasRemoved()); + + // from null to new rule: expect added + ZenModeDiff.RuleDiff added = new ZenModeDiff.RuleDiff(null, r); + assertTrue(added.hasDiff()); + assertTrue(added.wasAdded()); + } + + @Test + public void testRuleDiff_fieldDiffs() throws Exception { + // Start these the same + ZenModeConfig.ZenRule r1 = makeRule(); + ZenModeConfig.ZenRule r2 = makeRule(); + + // maps mapping field name -> expected output value as we set diffs + ArrayMap<String, Object> expectedFrom = new ArrayMap<>(); + ArrayMap<String, Object> expectedTo = new ArrayMap<>(); + List<Field> fieldsForDiff = getFieldsForDiffCheck( + ZenModeConfig.ZenRule.class, Set.of()); // actually no exempt fields for ZenRule + generateFieldDiffs(r1, r2, fieldsForDiff, expectedFrom, expectedTo); + + ZenModeDiff.RuleDiff d = new ZenModeDiff.RuleDiff(r1, r2); + assertTrue(d.hasDiff()); + + // Now diff them and check that each of the fields has a diff + for (Field f : fieldsForDiff) { + String name = f.getName(); + assertNotNull("diff not found for field: " + name, d.getDiffForField(name)); + assertTrue(d.getDiffForField(name).hasDiff()); + assertTrue("unexpected field: " + name, expectedFrom.containsKey(name)); + assertTrue("unexpected field: " + name, expectedTo.containsKey(name)); + assertEquals(expectedFrom.get(name), d.getDiffForField(name).from()); + assertEquals(expectedTo.get(name), d.getDiffForField(name).to()); + } + } + + @Test + public void testConfigDiff_addRemoveSame() { + // Default config, will test add, remove, and no change + ZenModeConfig c = new ZenModeConfig(); + + ZenModeDiff.ConfigDiff dSame = new ZenModeDiff.ConfigDiff(c, c); + assertFalse(dSame.hasDiff()); + + ZenModeDiff.ConfigDiff added = new ZenModeDiff.ConfigDiff(null, c); + assertTrue(added.hasDiff()); + assertTrue(added.wasAdded()); + + ZenModeDiff.ConfigDiff removed = new ZenModeDiff.ConfigDiff(c, null); + assertTrue(removed.hasDiff()); + assertTrue(removed.wasRemoved()); + } + + @Test + public void testConfigDiff_fieldDiffs() throws Exception { + // these two start the same + ZenModeConfig c1 = new ZenModeConfig(); + ZenModeConfig c2 = new ZenModeConfig(); + + // maps mapping field name -> expected output value as we set diffs + ArrayMap<String, Object> expectedFrom = new ArrayMap<>(); + ArrayMap<String, Object> expectedTo = new ArrayMap<>(); + List<Field> fieldsForDiff = getFieldsForDiffCheck( + ZenModeConfig.class, ZEN_MODE_CONFIG_EXEMPT_FIELDS); + generateFieldDiffs(c1, c2, fieldsForDiff, expectedFrom, expectedTo); + + ZenModeDiff.ConfigDiff d = new ZenModeDiff.ConfigDiff(c1, c2); + assertTrue(d.hasDiff()); + + // Now diff them and check that each of the fields has a diff + for (Field f : fieldsForDiff) { + String name = f.getName(); + assertNotNull("diff not found for field: " + name, d.getDiffForField(name)); + assertTrue(d.getDiffForField(name).hasDiff()); + assertTrue("unexpected field: " + name, expectedFrom.containsKey(name)); + assertTrue("unexpected field: " + name, expectedTo.containsKey(name)); + assertEquals(expectedFrom.get(name), d.getDiffForField(name).from()); + assertEquals(expectedTo.get(name), d.getDiffForField(name).to()); + } + } + + @Test + public void testConfigDiff_specialSenders() { + // these two start the same + ZenModeConfig c1 = new ZenModeConfig(); + ZenModeConfig c2 = new ZenModeConfig(); + + // set c1 and c2 to have some different senders + c1.allowMessagesFrom = ZenModeConfig.SOURCE_STAR; + c2.allowMessagesFrom = ZenModeConfig.SOURCE_CONTACT; + c1.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_IMPORTANT; + c2.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_NONE; + + ZenModeDiff.ConfigDiff d = new ZenModeDiff.ConfigDiff(c1, c2); + assertTrue(d.hasDiff()); + + // Diff in top-level fields + assertTrue(d.getDiffForField("allowMessagesFrom").hasDiff()); + assertTrue(d.getDiffForField("allowConversationsFrom").hasDiff()); + + // Bonus testing of stringification of people senders and conversation senders + assertTrue(d.toString().contains("allowMessagesFrom:stars->contacts")); + assertTrue(d.toString().contains("allowConversationsFrom:important->none")); + } + + @Test + public void testConfigDiff_hasRuleDiffs() { + // two default configs + ZenModeConfig c1 = new ZenModeConfig(); + ZenModeConfig c2 = new ZenModeConfig(); + + // two initially-identical rules + ZenModeConfig.ZenRule r1 = makeRule(); + ZenModeConfig.ZenRule r2 = makeRule(); + + // one that will become a manual rule + ZenModeConfig.ZenRule m = makeRule(); + + // Add r1 to c1, but not r2 to c2 yet -- expect a rule to be deleted + c1.automaticRules.put(r1.id, r1); + ZenModeDiff.ConfigDiff deleteRule = new ZenModeDiff.ConfigDiff(c1, c2); + assertTrue(deleteRule.hasDiff()); + assertNotNull(deleteRule.getAllAutomaticRuleDiffs()); + assertTrue(deleteRule.getAllAutomaticRuleDiffs().containsKey("ruleId")); + assertTrue(deleteRule.getAllAutomaticRuleDiffs().get("ruleId").wasRemoved()); + + // Change r2 a little, add r2 to c2 as an automatic rule and m as a manual rule + r2.component = null; + r2.pkg = "different"; + c2.manualRule = m; + c2.automaticRules.put(r2.id, r2); + + // Expect diffs in both manual rule (added) and automatic rule (changed) + ZenModeDiff.ConfigDiff changed = new ZenModeDiff.ConfigDiff(c1, c2); + assertTrue(changed.hasDiff()); + assertTrue(changed.getManualRuleDiff().hasDiff()); + + ArrayMap<String, ZenModeDiff.RuleDiff> automaticDiffs = changed.getAllAutomaticRuleDiffs(); + assertNotNull(automaticDiffs); + assertTrue(automaticDiffs.containsKey("ruleId")); + assertNotNull(automaticDiffs.get("ruleId").getDiffForField("component")); + assertNull(automaticDiffs.get("ruleId").getDiffForField("component").to()); + assertNotNull(automaticDiffs.get("ruleId").getDiffForField("pkg")); + assertEquals("different", automaticDiffs.get("ruleId").getDiffForField("pkg").to()); + } + + // Helper methods for working with configs, policies, rules + // Just makes a zen rule with fields filled in + private ZenModeConfig.ZenRule makeRule() { + ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); + rule.configurationActivity = new ComponentName("a", "a"); + rule.component = new ComponentName("b", "b"); + rule.conditionId = new Uri.Builder().scheme("hello").build(); + rule.condition = new Condition(rule.conditionId, "", Condition.STATE_TRUE); + rule.enabled = true; + rule.creationTime = 123; + rule.id = "ruleId"; + rule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + rule.modified = false; + rule.name = "name"; + rule.snoozing = true; + rule.pkg = "a"; + return rule; + } + + // Get the fields on which we would want to check a diff. The requirements are: not final or/ + // static (as these should/can never change), and not in a specific list that's exempted. + private List<Field> getFieldsForDiffCheck(Class c, Set<String> exemptNames) + throws SecurityException { + Field[] fields = c.getDeclaredFields(); + ArrayList<Field> out = new ArrayList<>(); + + for (Field field : fields) { + // Check for exempt reasons + int m = field.getModifiers(); + if (Modifier.isFinal(m) + || Modifier.isStatic(m) + || exemptNames.contains(field.getName())) { + continue; + } + out.add(field); + } + return out; + } + + // Generate a set of generic diffs for the specified two objects and the fields to generate + // diffs for, and store the results in the provided expectation maps to be able to check the + // output later. + private void generateFieldDiffs(Object a, Object b, List<Field> fields, + ArrayMap<String, Object> expectedA, ArrayMap<String, Object> expectedB) + throws Exception { + // different classes passed in means bad input + assertEquals(a.getClass(), b.getClass()); + + // Loop through fields for which we want to check diffs, set a diff and keep track of + // what we set. + for (Field f : fields) { + f.setAccessible(true); + // Just double-check also that the fields actually are for the class declared + assertEquals(f.getDeclaringClass(), a.getClass()); + Class t = f.getType(); + // handle the full set of primitive types first + if (boolean.class.equals(t)) { + f.setBoolean(a, true); + expectedA.put(f.getName(), true); + f.setBoolean(b, false); + expectedB.put(f.getName(), false); + } else if (int.class.equals(t)) { + // these are not actually valid going to be valid for arbitrary int enum fields, but + // we just put something in there regardless. + f.setInt(a, 2); + expectedA.put(f.getName(), 2); + f.setInt(b, 1); + expectedB.put(f.getName(), 1); + } else if (long.class.equals(t)) { + f.setLong(a, 200L); + expectedA.put(f.getName(), 200L); + f.setLong(b, 100L); + expectedB.put(f.getName(), 100L); + } else if (t.isPrimitive()) { + // This method doesn't yet handle other primitive types. If the relevant diff + // classes gain new fields of these types, please add another clause here. + fail("primitive type not handled by generateFieldDiffs: " + t.getName()); + } else if (String.class.equals(t)) { + f.set(a, "string1"); + expectedA.put(f.getName(), "string1"); + f.set(b, "string2"); + expectedB.put(f.getName(), "string2"); + } else { + // catch-all for other types: have the field be "added" + f.set(a, null); + expectedA.put(f.getName(), null); + try { + f.set(b, t.getDeclaredConstructor().newInstance()); + expectedB.put(f.getName(), t.getDeclaredConstructor().newInstance()); + } catch (Exception e) { + // No default constructor, or blithely attempting to construct something doesn't + // work for some reason. If the default value isn't null, then keep it. + if (f.get(b) != null) { + expectedB.put(f.getName(), f.get(b)); + } else { + // If we can't even rely on that, fail. Have the test-writer special case + // something, as this is not able to be genericized. + fail("could not generically construct value for field: " + f.getName()); + } + } + } + } + } +} 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 6f9798ea7d69..b2a54010e75e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -69,8 +69,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AutomaticZenRule; @@ -78,7 +76,6 @@ import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.ComponentName; import android.content.ContentResolver; -import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -90,7 +87,6 @@ import android.media.AudioManagerInternal; import android.media.AudioSystem; import android.media.VolumePolicy; import android.net.Uri; -import android.os.Binder; import android.os.Process; import android.os.UserHandle; import android.provider.Settings; @@ -98,6 +94,7 @@ import android.provider.Settings.Global; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.ScheduleInfo; +import android.service.notification.ZenModeDiff; import android.service.notification.ZenPolicy; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -877,7 +874,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL); assertEquals("Config mismatch: current vs expected: " - + mZenModeHelperSpy.mConfig.diff(expected), expected, mZenModeHelperSpy.mConfig); + + new ZenModeDiff.ConfigDiff(mZenModeHelperSpy.mConfig, expected), expected, + mZenModeHelperSpy.mConfig); } @Test @@ -1046,7 +1044,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig actual = mZenModeHelperSpy.mConfigs.get(10); assertEquals( - "Config mismatch: current vs expected: " + actual.diff(config10), config10, actual); + "Config mismatch: current vs expected: " + + new ZenModeDiff.ConfigDiff(actual, config10), config10, actual); assertNotEquals("Expected config mismatch", config11, mZenModeHelperSpy.mConfigs.get(11)); } @@ -1062,7 +1061,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM); assertEquals("Config mismatch: current vs original: " - + mZenModeHelperSpy.mConfig.diff(original), original, mZenModeHelperSpy.mConfig); + + new ZenModeDiff.ConfigDiff(mZenModeHelperSpy.mConfig, original), + original, mZenModeHelperSpy.mConfig); assertEquals(original.hashCode(), mZenModeHelperSpy.mConfig.hashCode()); } @@ -1083,8 +1083,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig actual = mZenModeHelperSpy.mConfigs.get(10); expected.user = 10; - assertEquals( - "Config mismatch: current vs original: " + actual.diff(expected), expected, actual); + assertEquals("Config mismatch: current vs original: " + + new ZenModeDiff.ConfigDiff(actual, expected), + expected, actual); assertEquals(expected.hashCode(), actual.hashCode()); expected.user = 0; assertNotEquals(expected, mZenModeHelperSpy.mConfig); diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp index 986fb71afa2d..e704ebf32270 100644 --- a/services/tests/voiceinteractiontests/Android.bp +++ b/services/tests/voiceinteractiontests/Android.bp @@ -40,6 +40,7 @@ android_test { "platform-test-annotations", "services.core", "services.voiceinteraction", + "services.soundtrigger", "servicestests-core-utils", "servicestests-utils-mockito-extended", "truth-prebuilt", diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerDuplicateModelHandlerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerDuplicateModelHandlerTest.java new file mode 100644 index 000000000000..bc94dacea324 --- /dev/null +++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerDuplicateModelHandlerTest.java @@ -0,0 +1,335 @@ +/* + * 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.soundtrigger_middleware; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +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.verifyNoMoreInteractions; + +import android.media.soundtrigger.ModelParameterRange; +import android.media.soundtrigger.Phrase; +import android.media.soundtrigger.PhraseSoundModel; +import android.media.soundtrigger.Properties; +import android.media.soundtrigger.RecognitionConfig; +import android.media.soundtrigger.RecognitionMode; +import android.media.soundtrigger.SoundModel; +import android.media.soundtrigger.SoundModelType; +import android.media.soundtrigger.Status; +import android.os.IBinder; + +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; +import org.mockito.InOrder; +import org.mockito.MockitoAnnotations; + +@RunWith(JUnit4.class) +public final class SoundTriggerDuplicateModelHandlerTest { + // Component under test + private SoundTriggerDuplicateModelHandler mComponent; + + private static final String DUPLICATE_UUID = "abcddead-beef-0123-3210-0123456789ab"; + private static final String DIFFERENT_UUID = "0000dead-beef-0123-3210-0123456789ab"; + + @Mock private ISoundTriggerHal mUnderlying; + @Mock private ISoundTriggerHal.GlobalCallback mGlobalCallback; + @Mock private ISoundTriggerHal.ModelCallback mModelCallback; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mComponent = new SoundTriggerDuplicateModelHandler(mUnderlying); + doNothing().when(mUnderlying).registerCallback(any()); + mComponent.registerCallback(mGlobalCallback); + verify(mUnderlying).registerCallback(eq(mGlobalCallback)); + } + + @Test + public void loadSoundModel_throwsResourceContention_whenDuplicateUuid() { + final var soundModel = createSoundModelOne(); + final var soundModelSameUuid = createSoundModelTwo(); + // First sound model load should complete successfully + mComponent.loadSoundModel(soundModel, mModelCallback); + verify(mUnderlying).loadSoundModel(eq(soundModel), eq(mModelCallback)); + assertEquals( + assertThrows( + RecoverableException.class, + () -> mComponent.loadSoundModel(soundModelSameUuid, mModelCallback)) + .errorCode, + Status.RESOURCE_CONTENTION); + // Model has not been unloaded, so we don't get a callback + verify(mGlobalCallback, never()).onResourcesAvailable(); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + @Test + public void loadSoundModel_doesNotThrowResourceContention_whenDifferentUuid() { + final var soundModel = createSoundModelOne(); + // Make all other fields the same + final var soundModelDifferentUuid = createSoundModelOne(); + soundModelDifferentUuid.uuid = DIFFERENT_UUID; + InOrder inOrder = Mockito.inOrder(mUnderlying); + // First sound model load should complete successfully + mComponent.loadSoundModel(soundModel, mModelCallback); + inOrder.verify(mUnderlying).loadSoundModel(eq(soundModel), eq(mModelCallback)); + mComponent.loadSoundModel(soundModelDifferentUuid, mModelCallback); + inOrder.verify(mUnderlying).loadSoundModel(eq(soundModelDifferentUuid), eq(mModelCallback)); + // No contention, so we don't get a callback + verify(mGlobalCallback, never()).onResourcesAvailable(); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + @Test + public void loadSoundModel_doesNotThrow_afterDuplicateUuidHasBeenUnloaded() { + final var soundModel = createSoundModelOne(); + // First sound model load should complete successfully + int handle = mComponent.loadSoundModel(soundModel, mModelCallback); + verify(mUnderlying).loadSoundModel(eq(soundModel), eq(mModelCallback)); + // Unload model should complete successfully + mComponent.unloadSoundModel(handle); + verify(mUnderlying).unloadSoundModel(eq(handle)); + // Since the model with the same UUID was unloaded, the subsequent load model + // should succeed. + mComponent.loadSoundModel(soundModel, mModelCallback); + verify(mUnderlying, times(2)).loadSoundModel(eq(soundModel), eq(mModelCallback)); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + @Test + public void unloadSoundModel_triggersResourceCallback_afterDuplicateUuidRejected() { + final var soundModel = createSoundModelOne(); + final var soundModelSameUuid = createSoundModelTwo(); + // First sound model load should complete successfully + int handle = mComponent.loadSoundModel(soundModel, mModelCallback); + verify(mUnderlying).loadSoundModel(eq(soundModel), eq(mModelCallback)); + assertEquals( + assertThrows( + RecoverableException.class, + () -> mComponent.loadSoundModel(soundModelSameUuid, mModelCallback)) + .errorCode, + Status.RESOURCE_CONTENTION); + mComponent.unloadSoundModel(handle); + verify(mUnderlying).unloadSoundModel(eq(handle)); + verify(mGlobalCallback).onResourcesAvailable(); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + // Next tests are same as above, but for phrase sound model. + @Test + public void loadPhraseSoundModel_throwsResourceContention_whenDuplicateUuid() { + final var soundModel = createPhraseSoundModelOne(); + final var soundModelSameUuid = createPhraseSoundModelTwo(); + // First sound model load should complete successfully + mComponent.loadPhraseSoundModel(soundModel, mModelCallback); + verify(mUnderlying).loadPhraseSoundModel(eq(soundModel), eq(mModelCallback)); + assertEquals( + assertThrows( + RecoverableException.class, + () -> + mComponent.loadPhraseSoundModel( + soundModelSameUuid, mModelCallback)) + .errorCode, + Status.RESOURCE_CONTENTION); + // Model has not been unloaded, so we don't get a callback + verify(mGlobalCallback, never()).onResourcesAvailable(); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + @Test + public void loadPhraseSoundModel_doesNotThrowResourceContention_whenDifferentUuid() { + final var soundModel = createPhraseSoundModelOne(); + // Make all other fields the same + final var soundModelDifferentUuid = createPhraseSoundModelOne(); + soundModelDifferentUuid.common.uuid = DIFFERENT_UUID; + InOrder inOrder = Mockito.inOrder(mUnderlying); + // First sound model load should complete successfully + mComponent.loadPhraseSoundModel(soundModel, mModelCallback); + inOrder.verify(mUnderlying).loadPhraseSoundModel(eq(soundModel), eq(mModelCallback)); + mComponent.loadPhraseSoundModel(soundModelDifferentUuid, mModelCallback); + inOrder.verify(mUnderlying).loadPhraseSoundModel(eq(soundModelDifferentUuid), + eq(mModelCallback)); + // No contention, so we don't get a callback + verify(mGlobalCallback, never()).onResourcesAvailable(); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + @Test + public void loadPhraseSoundModel_doesNotThrow_afterDuplicateUuidHasBeenUnloaded() { + final var soundModel = createPhraseSoundModelOne(); + // First sound model load should complete successfully + int handle = mComponent.loadPhraseSoundModel(soundModel, mModelCallback); + verify(mUnderlying).loadPhraseSoundModel(eq(soundModel), eq(mModelCallback)); + // Unload model should complete successfully + mComponent.unloadSoundModel(handle); + verify(mUnderlying).unloadSoundModel(eq(handle)); + // Since the model with the same UUID was unloaded, the subsequent load model + // should succeed. + mComponent.loadPhraseSoundModel(soundModel, mModelCallback); + verify(mUnderlying, times(2)).loadPhraseSoundModel(eq(soundModel), eq(mModelCallback)); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + @Test + public void unloadSoundModel_triggersResourceCallback_afterDuplicateUuidRejectedPhrase() { + final var soundModel = createPhraseSoundModelOne(); + final var soundModelSameUuid = createPhraseSoundModelTwo(); + // First sound model load should complete successfully + int handle = mComponent.loadPhraseSoundModel(soundModel, mModelCallback); + verify(mUnderlying).loadPhraseSoundModel(eq(soundModel), eq(mModelCallback)); + assertEquals( + assertThrows( + RecoverableException.class, + () -> + mComponent.loadPhraseSoundModel( + soundModelSameUuid, mModelCallback)) + .errorCode, + Status.RESOURCE_CONTENTION); + mComponent.unloadSoundModel(handle); + verify(mUnderlying).unloadSoundModel(eq(handle)); + verify(mGlobalCallback).onResourcesAvailable(); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + @Test + public void testDelegation() { + // Test that the rest of the interface delegates its calls to the underlying object + // appropriately. + // This test method does not test load/unloadSoundModel + var properties = new Properties(); + InOrder inOrder = Mockito.inOrder(mUnderlying); + doReturn(properties).when(mUnderlying).getProperties(); + assertEquals(mComponent.getProperties(), properties); + inOrder.verify(mUnderlying).getProperties(); + var mockGlobalCallback = mock(ISoundTriggerHal.GlobalCallback.class); + mComponent.registerCallback(mockGlobalCallback); + inOrder.verify(mUnderlying).registerCallback(eq(mockGlobalCallback)); + int modelId = 5; + int deviceHandle = 2; + int ioHandle = 3; + var config = mock(RecognitionConfig.class); + mComponent.startRecognition(modelId, deviceHandle, ioHandle, config); + inOrder.verify(mUnderlying) + .startRecognition(eq(modelId), eq(deviceHandle), eq(ioHandle), eq(config)); + + mComponent.stopRecognition(modelId); + inOrder.verify(mUnderlying).stopRecognition(eq(modelId)); + mComponent.forceRecognitionEvent(modelId); + inOrder.verify(mUnderlying).forceRecognitionEvent(eq(modelId)); + int param = 10; + int value = 50; + var modelParamRange = new ModelParameterRange(); + doReturn(modelParamRange).when(mUnderlying).queryParameter(anyInt(), anyInt()); + assertEquals(mComponent.queryParameter(param, value), modelParamRange); + inOrder.verify(mUnderlying).queryParameter(param, value); + doReturn(value).when(mUnderlying).getModelParameter(anyInt(), anyInt()); + assertEquals(mComponent.getModelParameter(modelId, param), value); + inOrder.verify(mUnderlying).getModelParameter(eq(modelId), eq(param)); + mComponent.setModelParameter(modelId, param, value); + inOrder.verify(mUnderlying).setModelParameter(eq(modelId), eq(param), eq(value)); + var recipient = mock(IBinder.DeathRecipient.class); + mComponent.linkToDeath(recipient); + inOrder.verify(mUnderlying).linkToDeath(eq(recipient)); + mComponent.unlinkToDeath(recipient); + inOrder.verify(mUnderlying).unlinkToDeath(eq(recipient)); + mComponent.flushCallbacks(); + inOrder.verify(mUnderlying).flushCallbacks(); + var token = mock(IBinder.class); + mComponent.clientAttached(token); + inOrder.verify(mUnderlying).clientAttached(eq(token)); + mComponent.clientDetached(token); + inOrder.verify(mUnderlying).clientDetached(eq(token)); + mComponent.reboot(); + inOrder.verify(mUnderlying).reboot(); + mComponent.detach(); + inOrder.verify(mUnderlying).detach(); + verifyNoMoreInteractions(mUnderlying); + verifyNoMoreInteractions(mGlobalCallback); + } + + private static SoundModel createSoundModelOne() { + SoundModel model = new SoundModel(); + model.type = SoundModelType.GENERIC; + model.uuid = DUPLICATE_UUID; + model.vendorUuid = "87654321-5432-6543-7654-456789fedcba"; + byte[] data = new byte[] {91, 92, 93, 94, 95}; + model.data = TestUtil.byteArrayToParcelFileDescriptor(data); + model.dataSize = data.length; + return model; + } + + // Different except for the same UUID + private static SoundModel createSoundModelTwo() { + SoundModel model = new SoundModel(); + model.type = SoundModelType.GENERIC; + model.uuid = DUPLICATE_UUID; + model.vendorUuid = "12345678-9876-5432-1012-345678901234"; + byte[] data = new byte[] {19, 18, 17, 16}; + model.data = TestUtil.byteArrayToParcelFileDescriptor(data); + model.dataSize = data.length; + return model; + } + + private static PhraseSoundModel createPhraseSoundModelOne() { + PhraseSoundModel model = new PhraseSoundModel(); + model.common = createSoundModelOne(); + model.common.type = SoundModelType.KEYPHRASE; + model.phrases = new Phrase[1]; + model.phrases[0] = new Phrase(); + model.phrases[0].id = 123; + model.phrases[0].users = new int[] {5, 6, 7}; + model.phrases[0].locale = "locale"; + model.phrases[0].text = "text"; + model.phrases[0].recognitionModes = + RecognitionMode.USER_AUTHENTICATION | RecognitionMode.USER_IDENTIFICATION; + return model; + } + + private static PhraseSoundModel createPhraseSoundModelTwo() { + PhraseSoundModel model = new PhraseSoundModel(); + model.common = createSoundModelTwo(); + model.common.type = SoundModelType.KEYPHRASE; + model.phrases = new Phrase[1]; + model.phrases[0] = new Phrase(); + model.phrases[0].id = 321; + model.phrases[0].users = new int[] {4, 3, 2, 1}; + model.phrases[0].locale = "differentLocale"; + model.phrases[0].text = "differentText"; + model.phrases[0].recognitionModes = 0; + return model; + } +} diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/TestUtil.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/TestUtil.java index 39561f74d7ed..3b7bc952639e 100644 --- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/TestUtil.java +++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/TestUtil.java @@ -466,7 +466,7 @@ class TestUtil { assertEquals(43, event.phraseExtras[0].levels[0].levelPercent); } - private static ParcelFileDescriptor byteArrayToParcelFileDescriptor(byte[] data) { + static ParcelFileDescriptor byteArrayToParcelFileDescriptor(byte[] data) { try (SharedMemory shmem = SharedMemory.create("", data.length)) { ByteBuffer buffer = shmem.mapReadWrite(); buffer.put(data); diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index 2696d2bf58b9..f12b53acd06b 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -87,6 +87,8 @@ android:showWhenLocked="true"/> <activity android:name="android.view.cts.surfacevalidator.CapturedActivity"/> + <activity android:name="com.android.server.wm.SurfaceControlViewHostTests$TestActivity" /> + <service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService" android:foregroundServiceType="mediaProjection" android:enabled="true"> diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index b8a21ec4c030..8f2b470908c4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -83,6 +83,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED; +import static com.android.server.wm.ActivityRecord.LAUNCH_SOURCE_TYPE_HOME; import static com.android.server.wm.ActivityRecord.State.DESTROYED; import static com.android.server.wm.ActivityRecord.State.DESTROYING; import static com.android.server.wm.ActivityRecord.State.FINISHING; @@ -589,12 +590,18 @@ public class ActivityRecordTests extends WindowTestsBase { throw new IllegalStateException("Orientation in new config should be either" + "landscape or portrait."); } + + final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation(); + spyOn(displayRotation); + activity.setRequestedOrientation(requestedOrientation); final ActivityConfigurationChangeItem expected = ActivityConfigurationChangeItem.obtain(newConfig); verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(activity.app.getThread()), eq(activity.token), eq(expected)); + + verify(displayRotation).onSetRequestedOrientation(); } @Test @@ -3682,6 +3689,23 @@ public class ActivityRecordTests extends WindowTestsBase { assertTrue(activity.inTransition()); } + /** + * Verifies the task is moved to back when back pressed if the root activity was originally + * started from Launcher. + */ + @Test + public void testMoveTaskToBackWhenStartedFromLauncher() { + final Task task = createTask(mDisplayContent); + final ActivityRecord ar = createActivityRecord(task); + task.realActivity = ar.mActivityComponent; + ar.intent.setAction(Intent.ACTION_MAIN); + ar.intent.addCategory(Intent.CATEGORY_LAUNCHER); + doReturn(true).when(ar).isLaunchSourceType(eq(LAUNCH_SOURCE_TYPE_HOME)); + + mAtm.mActivityClientController.onBackPressed(ar.token, null /* callback */); + verify(task).moveTaskToBack(any()); + } + private ICompatCameraControlCallback getCompatCameraControlCallback() { return new ICompatCameraControlCallback.Stub() { @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java index e85b574baa22..5282585e9757 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java @@ -147,8 +147,8 @@ public class DimmerTests extends WindowTestsBase { int width = 100; int height = 300; - Rect bounds = new Rect(0, 0, width, height); - mDimmer.updateDims(mTransaction, bounds); + mDimmer.mDimState.mDimBounds.set(0, 0, width, height); + mDimmer.updateDims(mTransaction); verify(mTransaction).setWindowCrop(getDimLayer(), width, height); verify(mTransaction).show(getDimLayer()); @@ -194,7 +194,7 @@ public class DimmerTests extends WindowTestsBase { SurfaceControl dimLayer = getDimLayer(); mDimmer.resetDimStates(); - mDimmer.updateDims(mTransaction, new Rect()); + mDimmer.updateDims(mTransaction); verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any( SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), eq(ANIMATION_TYPE_DIMMER)); @@ -212,29 +212,29 @@ public class DimmerTests extends WindowTestsBase { mDimmer.resetDimStates(); mDimmer.dimAbove(mTransaction, child, alpha); - mDimmer.updateDims(mTransaction, new Rect()); + mDimmer.updateDims(mTransaction); verify(mTransaction).show(dimLayer); verify(mTransaction, never()).remove(dimLayer); } @Test public void testDimUpdateWhileDimming() { - Rect bounds = new Rect(); TestWindowContainer child = new TestWindowContainer(mWm); mHost.addChild(child, 0); final float alpha = 0.8f; mDimmer.dimAbove(mTransaction, child, alpha); + final Rect bounds = mDimmer.mDimState.mDimBounds; SurfaceControl dimLayer = getDimLayer(); bounds.set(0, 0, 10, 10); - mDimmer.updateDims(mTransaction, bounds); + mDimmer.updateDims(mTransaction); verify(mTransaction).setWindowCrop(dimLayer, bounds.width(), bounds.height()); verify(mTransaction, times(1)).show(dimLayer); verify(mTransaction).setPosition(dimLayer, 0, 0); bounds.set(10, 10, 30, 30); - mDimmer.updateDims(mTransaction, bounds); + mDimmer.updateDims(mTransaction); verify(mTransaction).setWindowCrop(dimLayer, bounds.width(), bounds.height()); verify(mTransaction).setPosition(dimLayer, 10, 10); } @@ -246,13 +246,13 @@ public class DimmerTests extends WindowTestsBase { mDimmer.dimAbove(mTransaction, child, 1); SurfaceControl dimLayer = getDimLayer(); - mDimmer.updateDims(mTransaction, new Rect()); + mDimmer.updateDims(mTransaction); verify(mTransaction, times(1)).show(dimLayer); reset(mSurfaceAnimatorStarter); mDimmer.dontAnimateExit(); mDimmer.resetDimStates(); - mDimmer.updateDims(mTransaction, new Rect()); + mDimmer.updateDims(mTransaction); verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any( SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), eq(ANIMATION_TYPE_DIMMER)); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index ba9f809e9a2a..7330411d1dd7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; @@ -1063,6 +1064,51 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation()); } + private void updateAllDisplayContentAndRotation(DisplayContent dc) { + // NB updateOrientation will not revert the user orientation until a settings change + // takes effect. + dc.updateOrientation(); + dc.onDisplayChanged(dc); + dc.mWmService.updateRotation(true /* alwaysSendConfiguration */, + false /* forceRelayout */); + waitUntilHandlersIdle(); + } + + @Test + public void testNoSensorRevert() { + final DisplayContent dc = mDisplayContent; + spyOn(dc); + doReturn(true).when(dc).getIgnoreOrientationRequest(); + final DisplayRotation dr = dc.getDisplayRotation(); + spyOn(dr); + doReturn(false).when(dr).useDefaultSettingsProvider(); + final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build(); + app.setOrientation(SCREEN_ORIENTATION_LANDSCAPE, app); + + assertFalse(dc.getRotationReversionController().isAnyOverrideActive()); + dc.getDisplayRotation().setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, + ROTATION_90); + updateAllDisplayContentAndRotation(dc); + assertEquals(ROTATION_90, dc.getDisplayRotation() + .rotationForOrientation(SCREEN_ORIENTATION_UNSPECIFIED, ROTATION_90)); + + app.setOrientation(SCREEN_ORIENTATION_NOSENSOR); + updateAllDisplayContentAndRotation(dc); + assertTrue(dc.getRotationReversionController().isAnyOverrideActive()); + assertEquals(ROTATION_0, dc.getRotation()); + + app.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED); + updateAllDisplayContentAndRotation(dc); + assertFalse(dc.getRotationReversionController().isAnyOverrideActive()); + assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, + dc.getDisplayRotation().getUserRotationMode()); + assertEquals(ROTATION_90, dc.getDisplayRotation().getUserRotation()); + assertEquals(ROTATION_90, dc.getDisplayRotation() + .rotationForOrientation(SCREEN_ORIENTATION_UNSPECIFIED, ROTATION_0)); + dc.getDisplayRotation().setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, + ROTATION_0); + } + @Test public void testOnDescendantOrientationRequestChanged() { final DisplayContent dc = createNewDisplay(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java index c2b3783b7311..a3117269eb01 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java @@ -365,6 +365,23 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { } @Test + public void testCameraDisconnected_revertRotationAndRefresh() throws Exception { + configureActivityAndDisplay(SCREEN_ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE); + // Open camera and test for compat treatment + mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); + callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ true); + assertEquals(mDisplayRotationCompatPolicy.getOrientation(), + SCREEN_ORIENTATION_LANDSCAPE); + assertActivityRefreshRequested(/* refreshRequested */ true); + // Close camera and test for revert + mCameraAvailabilityCallback.onCameraClosed(CAMERA_ID_1); + callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ true); + assertEquals(mDisplayRotationCompatPolicy.getOrientation(), + SCREEN_ORIENTATION_UNSPECIFIED); + assertActivityRefreshRequested(/* refreshRequested */ true); + } + + @Test public void testGetOrientation_cameraConnectionClosed_returnUnspecified() { configureActivity(SCREEN_ORIENTATION_PORTRAIT); 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 495f868b1b11..4b2d1071d113 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -70,6 +70,7 @@ import android.view.IRotationWatcher; import android.view.Surface; import android.view.WindowManager; +import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import com.android.internal.util.test.FakeSettingsProvider; @@ -114,6 +115,7 @@ public class DisplayRotationTests { private static WindowManagerService sMockWm; private DisplayContent mMockDisplayContent; + private DisplayRotationReversionController mMockDisplayRotationReversionController; private DisplayPolicy mMockDisplayPolicy; private DisplayAddress mMockDisplayAddress; private Context mMockContext; @@ -140,6 +142,8 @@ public class DisplayRotationTests { private DeviceStateController mDeviceStateController; private TestDisplayRotation mTarget; + @Nullable + private DisplayRotationImmersiveAppCompatPolicy mDisplayRotationImmersiveAppCompatPolicyMock; @BeforeClass public static void setUpOnce() { @@ -165,7 +169,7 @@ public class DisplayRotationTests { LocalServices.removeServiceForTest(StatusBarManagerInternal.class); mMockStatusBarManagerInternal = mock(StatusBarManagerInternal.class); LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal); - + mDisplayRotationImmersiveAppCompatPolicyMock = null; mBuilder = new DisplayRotationBuilder(); } @@ -578,6 +582,38 @@ public class DisplayRotationTests { } @Test + public void testNotifiesChoiceWhenSensorUpdates_immersiveApp() throws Exception { + mDisplayRotationImmersiveAppCompatPolicyMock = mock( + DisplayRotationImmersiveAppCompatPolicy.class); + when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced( + Surface.ROTATION_90)).thenReturn(true); + + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + enableOrientationSensor(); + + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertTrue(waitForUiHandler()); + + verify(mMockStatusBarManagerInternal).onProposedRotationChanged(Surface.ROTATION_90, true); + + // An imaginary ActivityRecord.setRequestedOrientation call disables immersive mode: + when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced( + Surface.ROTATION_90)).thenReturn(false); + + // And then ActivityRecord.setRequestedOrientation calls onSetRequestedOrientation. + mTarget.onSetRequestedOrientation(); + + // onSetRequestedOrientation should lead to a second call to + // mOrientationListener.onProposedRotationChanged + // but now, instead of notifying mMockStatusBarManagerInternal, it calls updateRotation: + verify(sMockWm).updateRotation(false, false); + } + + @Test public void testAllowAllRotations_allowsUpsideDownSuggestion() throws Exception { mBuilder.build(); @@ -1374,6 +1410,10 @@ public class DisplayRotationTests { when(mMockContext.getResources().getBoolean( com.android.internal.R.bool.config_windowManagerHalfFoldAutoRotateOverride)) .thenReturn(mSupportHalfFoldAutoRotateOverride); + mMockDisplayRotationReversionController = + mock(DisplayRotationReversionController.class); + when(mMockDisplayContent.getRotationReversionController()) + .thenReturn(mMockDisplayRotationReversionController); mMockResolver = mock(ContentResolver.class); when(mMockContext.getContentResolver()).thenReturn(mMockResolver); @@ -1404,7 +1444,7 @@ public class DisplayRotationTests { } } - private static class TestDisplayRotation extends DisplayRotation { + private class TestDisplayRotation extends DisplayRotation { IntConsumer mProposedRotationCallback; TestDisplayRotation(DisplayContent dc, DisplayAddress address, DisplayPolicy policy, @@ -1417,7 +1457,7 @@ public class DisplayRotationTests { @Override DisplayRotationImmersiveAppCompatPolicy initImmersiveAppCompatPolicy( WindowManagerService service, DisplayContent displayContent) { - return null; + return mDisplayRotationImmersiveAppCompatPolicyMock; } @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index 43fc1c43d6ba..7cb7c79d63a0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -111,7 +111,6 @@ public class LaunchParamsPersisterTests extends WindowTestsBase { mDisplayUniqueId = "test:" + sNextUniqueId++; mTestDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1500) .setUniqueId(mDisplayUniqueId).build(); - mTestDisplay.getDefaultTaskDisplayArea().setWindowingMode(TEST_WINDOWING_MODE); when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId))) .thenReturn(mTestDisplay); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 9ebc7307418d..10f4158205e6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -924,6 +924,11 @@ public class RecentTasksTest extends WindowTestsBase { @Test public void testFreezeTaskListOrder_timeout() { + for (Task t : mTasks) { + // Make all the tasks non-empty + new ActivityBuilder(mAtm).setTask(t).build(); + } + // Add some tasks mRecentTasks.add(mTasks.get(0)); mRecentTasks.add(mTasks.get(1)); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index c131c84a50ce..7092b0b5ac34 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -104,7 +104,6 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { when(mMockRunner.asBinder()).thenReturn(new Binder()); mController = spy(new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks, DEFAULT_DISPLAY)); - mController.mShouldAttachNavBarToAppDuringTransition = false; mRootHomeTask = mDefaultDisplay.getDefaultTaskDisplayArea().getRootHomeTask(); assertNotNull(mRootHomeTask); } @@ -814,13 +813,13 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { } private void setupForShouldAttachNavBarDuringTransition() { - mController.mShouldAttachNavBarToAppDuringTransition = true; final WindowState navBar = spy(createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar")); mDefaultDisplay.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs); mWm.setRecentsAnimationController(mController); doReturn(navBar).when(mController).getNavigationBarWindow(); final DisplayPolicy displayPolicy = spy(mDefaultDisplay.getDisplayPolicy()); doReturn(displayPolicy).when(mDefaultDisplay).getDisplayPolicy(); + doReturn(true).when(displayPolicy).shouldAttachNavBarToAppDuringTransition(); } private static void initializeRecentsAnimationController(RecentsAnimationController controller, diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index e96d1abf9ced..de943d240084 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; 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; @@ -428,20 +429,24 @@ public class SizeCompatTests extends WindowTestsBase { .setLaunchedFromUid(mActivity.getUid()) .build(); doReturn(false).when(translucentActivity).fillsParent(); - WindowConfiguration translucentWinConf = translucentActivity.getWindowConfiguration(); - translucentActivity.setActivityType(ACTIVITY_TYPE_STANDARD); - translucentActivity.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); - translucentActivity.setDisplayWindowingMode(WINDOWING_MODE_MULTI_WINDOW); - translucentActivity.setAlwaysOnTop(true); + final Configuration requestedConfig = + translucentActivity.getRequestedOverrideConfiguration(); + final WindowConfiguration translucentWinConf = requestedConfig.windowConfiguration; + translucentWinConf.setActivityType(ACTIVITY_TYPE_STANDARD); + translucentWinConf.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + translucentWinConf.setDisplayWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + translucentWinConf.setAlwaysOnTop(true); + translucentActivity.onRequestedOverrideConfigurationChanged(requestedConfig); mTask.addChild(translucentActivity); - // We check the WIndowConfiguration properties - translucentWinConf = translucentActivity.getWindowConfiguration(); + // The original override of WindowConfiguration should keep. assertEquals(ACTIVITY_TYPE_STANDARD, translucentActivity.getActivityType()); assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getWindowingMode()); assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getDisplayWindowingMode()); assertTrue(translucentWinConf.isAlwaysOnTop()); + // Unless display is going to be rotated, it should always inherit from parent. + assertEquals(ROTATION_UNDEFINED, translucentWinConf.getDisplayRotation()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java new file mode 100644 index 000000000000..41bfc806f839 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java @@ -0,0 +1,194 @@ +/* + * 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.wm; + +import static android.Manifest.permission.ACCESS_SURFACE_FLINGER; +import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; +import static android.server.wm.CtsWindowInfoUtils.waitForWindowVisible; +import static android.server.wm.CtsWindowInfoUtils.waitForWindowFocus; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; + +import static org.junit.Assert.assertTrue; + +import android.app.Activity; +import android.app.Instrumentation; +import android.content.res.Configuration; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.view.Gravity; +import android.view.IWindow; +import android.view.SurfaceControl; +import android.view.SurfaceControlViewHost; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.view.WindowlessWindowManager; +import android.widget.Button; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; + +@Presubmit +@SmallTest +@RunWith(WindowTestRunner.class) +public class SurfaceControlViewHostTests { + private final ActivityTestRule<TestActivity> mActivityRule = new ActivityTestRule<>( + TestActivity.class); + private Instrumentation mInstrumentation; + private TestActivity mActivity; + + private View mView1; + private View mView2; + private SurfaceControlViewHost mScvh1; + private SurfaceControlViewHost mScvh2; + + @Before + public void setUp() throws Exception { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + + // ACCESS_SURFACE_FLINGER is necessary to call waitForWindow + // INTERNAL_SYSTEM_WINDOW is necessary to add SCVH with no host parent + mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(ACCESS_SURFACE_FLINGER, + INTERNAL_SYSTEM_WINDOW); + mActivity = mActivityRule.launchActivity(null); + } + + @After + public void tearDown() { + mInstrumentation.getUiAutomation().dropShellPermissionIdentity(); + } + + @Test + public void requestFocusWithMultipleWindows() throws InterruptedException, RemoteException { + SurfaceControl sc = new SurfaceControl.Builder() + .setName("SurfaceControlViewHostTests") + .setCallsite("requestFocusWithMultipleWindows") + .build(); + mView1 = new Button(mActivity); + mView2 = new Button(mActivity); + + mActivity.runOnUiThread(() -> { + TestWindowlessWindowManager wwm = new TestWindowlessWindowManager( + mActivity.getResources().getConfiguration(), sc, null); + + try { + mActivity.attachToSurfaceView(sc); + } catch (InterruptedException e) { + } + + mScvh1 = new SurfaceControlViewHost(mActivity, mActivity.getDisplay(), + wwm, "requestFocusWithMultipleWindows"); + mScvh2 = new SurfaceControlViewHost(mActivity, mActivity.getDisplay(), + wwm, "requestFocusWithMultipleWindows"); + + + mView1.setBackgroundColor(Color.RED); + mView2.setBackgroundColor(Color.BLUE); + + WindowManager.LayoutParams lp1 = new WindowManager.LayoutParams(200, 200, + TYPE_APPLICATION, 0, PixelFormat.OPAQUE); + WindowManager.LayoutParams lp2 = new WindowManager.LayoutParams(100, 100, + TYPE_APPLICATION, 0, PixelFormat.OPAQUE); + mScvh1.setView(mView1, lp1); + mScvh2.setView(mView2, lp2); + }); + + assertTrue("Failed to wait for view1", waitForWindowVisible(mView1)); + assertTrue("Failed to wait for view2", waitForWindowVisible(mView2)); + + WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */, + mScvh1.getFocusGrantToken(), true); + assertTrue("Failed to gain focus for view1", waitForWindowFocus(mView1, true)); + + WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */, + mScvh2.getFocusGrantToken(), true); + assertTrue("Failed to gain focus for view2", waitForWindowFocus(mView2, true)); + } + + private static class TestWindowlessWindowManager extends WindowlessWindowManager { + private final SurfaceControl mRoot; + + TestWindowlessWindowManager(Configuration c, SurfaceControl rootSurface, + IBinder hostInputToken) { + super(c, rootSurface, hostInputToken); + mRoot = rootSurface; + } + + @Override + protected SurfaceControl getParentSurface(IWindow window, + WindowManager.LayoutParams attrs) { + return mRoot; + } + } + + public static class TestActivity extends Activity implements SurfaceHolder.Callback { + private SurfaceView mSurfaceView; + private final CountDownLatch mSvReadyLatch = new CountDownLatch(1); + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final FrameLayout content = new FrameLayout(this); + mSurfaceView = new SurfaceView(this); + mSurfaceView.setBackgroundColor(Color.BLACK); + mSurfaceView.setZOrderOnTop(true); + final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(500, 500, + Gravity.LEFT | Gravity.TOP); + content.addView(mSurfaceView, lp); + setContentView(content); + mSurfaceView.getHolder().addCallback(this); + } + + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + mSvReadyLatch.countDown(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, + int height) { + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + } + + public void attachToSurfaceView(SurfaceControl sc) throws InterruptedException { + mSvReadyLatch.await(); + new SurfaceControl.Transaction().reparent(sc, mSurfaceView.getSurfaceControl()) + .show(sc).apply(); + } + } +} + diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java index 8e91ca28fcf1..77efc4b0d561 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java @@ -42,6 +42,8 @@ import android.view.SurfaceControl; import androidx.test.filters.SmallTest; +import com.android.server.testutils.TestHandler; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -371,6 +373,49 @@ public class SyncEngineTests extends WindowTestsBase { mAppWindow.removeImmediately(); } + @Test + public void testQueueSyncSet() { + final TestHandler testHandler = new TestHandler(null); + TestWindowContainer mockWC = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer mockWC2 = new TestWindowContainer(mWm, true /* waiter */); + + final BLASTSyncEngine bse = createTestBLASTSyncEngine(testHandler); + + BLASTSyncEngine.TransactionReadyListener listener = mock( + BLASTSyncEngine.TransactionReadyListener.class); + + int id = startSyncSet(bse, listener); + bse.addToSyncSet(id, mockWC); + bse.setReady(id); + bse.onSurfacePlacement(); + verify(listener, times(0)).onTransactionReady(eq(id), notNull()); + + final int[] nextId = new int[]{-1}; + bse.queueSyncSet( + () -> nextId[0] = startSyncSet(bse, listener), + () -> { + bse.setReady(nextId[0]); + bse.addToSyncSet(nextId[0], mockWC2); + }); + + // Make sure it is queued + assertEquals(-1, nextId[0]); + + // Finish the original sync and see that we've started a new sync-set immediately but + // that the readiness was posted. + mockWC.onSyncFinishedDrawing(); + verify(mWm.mWindowPlacerLocked).requestTraversal(); + bse.onSurfacePlacement(); + verify(listener, times(1)).onTransactionReady(eq(id), notNull()); + + assertTrue(nextId[0] != -1); + assertFalse(bse.isReady(nextId[0])); + + // now make sure the applySync callback was posted. + testHandler.flush(); + assertTrue(bse.isReady(nextId[0])); + } + static int startSyncSet(BLASTSyncEngine engine, BLASTSyncEngine.TransactionReadyListener listener) { return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test"); diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 90506d4f8651..43b429c76749 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -1404,19 +1404,17 @@ public class TransitionTests extends WindowTestsBase { // We are now going to simulate closing task1 to return back to (open) task2. final Transition closeTransition = controller.createTransition(TRANSIT_CLOSE); - closeTransition.collectExistenceChange(task1); - closeTransition.collectExistenceChange(activity1); closeTransition.collectExistenceChange(task2); closeTransition.collectExistenceChange(activity2); closeTransition.setTransientLaunch(activity2, task1); final Transition.ChangeInfo task1ChangeInfo = closeTransition.mChanges.get(task1); assertNotNull(task1ChangeInfo); assertTrue(task1ChangeInfo.hasChanged()); + // Make sure the unrelated activity is NOT collected. final Transition.ChangeInfo activity1ChangeInfo = closeTransition.mChanges.get(activity1); - assertNotNull(activity1ChangeInfo); - assertTrue(activity1ChangeInfo.hasChanged()); + assertNull(activity1ChangeInfo); // No need to wait for the activity in transient hide task. - assertTrue(activity1.isSyncFinished()); + assertEquals(WindowContainer.SYNC_STATE_NONE, activity1.mSyncState); activity1.setVisibleRequested(false); activity2.setVisibleRequested(true); @@ -1444,6 +1442,7 @@ public class TransitionTests extends WindowTestsBase { } } }); + assertTrue(activity1.isVisible()); controller.finishTransition(closeTransition); assertTrue(wasInFinishingTransition[0]); assertNull(controller.mFinishingTransition); @@ -1452,6 +1451,7 @@ public class TransitionTests extends WindowTestsBase { assertEquals(ActivityTaskManagerService.APP_SWITCH_DISALLOW, mAtm.getBalAppSwitchesState()); // Because task1 is occluded by task2, finishTransition should make activity1 invisible. assertFalse(activity1.isVisibleRequested()); + // Make sure activity1 visibility was committed assertFalse(activity1.isVisible()); assertFalse(activity1.app.hasActivityInVisibleTask()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index b48fd7d60f06..fdb3502f2ce7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -691,6 +691,7 @@ public class WindowStateTests extends WindowTestsBase { // Child window without scale (e.g. different app) should apply inverse scale of parent. doReturn(1f).when(cmp).getCompatScale(anyString(), anyInt()); final WindowState child2 = createWindow(w, TYPE_APPLICATION_SUB_PANEL, "child2"); + makeWindowVisible(w, child2); clearInvocations(t); child2.prepareSurfaces(); verify(t).setMatrix(child2.mSurfaceControl, w.mInvGlobalScale, 0, 0, w.mInvGlobalScale); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 7e3ec55f262a..f85cdf0b5035 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -77,6 +77,7 @@ import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; @@ -886,7 +887,11 @@ class WindowTestsBase extends SystemServiceTestsBase { } BLASTSyncEngine createTestBLASTSyncEngine() { - return new BLASTSyncEngine(mWm) { + return createTestBLASTSyncEngine(mWm.mH); + } + + BLASTSyncEngine createTestBLASTSyncEngine(Handler handler) { + return new BLASTSyncEngine(mWm, handler) { @Override void scheduleTimeout(SyncGroup s, long timeoutMs) { // Disable timeout. diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index 6cf2b2d7a31e..74ba45c130e3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -500,7 +500,6 @@ public class ZOrderingTests extends WindowTestsBase { RecentsAnimationController controller = new RecentsAnimationController( mWm, mockRunner, null, displayId); spyOn(controller); - controller.mShouldAttachNavBarToAppDuringTransition = true; doReturn(mNavBarWindow).when(controller).getNavigationBarWindow(); mWm.setRecentsAnimationController(controller); @@ -508,6 +507,10 @@ public class ZOrderingTests extends WindowTestsBase { spyOn(mDisplayContent.mInputMethodWindow); doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible(); + DisplayPolicy policy = mDisplayContent.getDisplayPolicy(); + spyOn(policy); + doReturn(true).when(policy).shouldAttachNavBarToAppDuringTransition(); + // create home activity Task rootHomeTask = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask(); final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService) diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java index 337e1f92050c..7fe8582f96de 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java @@ -27,6 +27,8 @@ import android.util.Slog; import com.android.internal.util.dump.DualDumpOutputStream; import com.android.server.audio.AudioService; +import java.util.Arrays; + /** * Represents the ALSA specification, and attributes of an ALSA device. */ @@ -36,17 +38,21 @@ public final class UsbAlsaDevice { private final int mCardNum; private final int mDeviceNum; + private final String mAlsaCardDeviceString; private final String mDeviceAddress; - private final boolean mHasOutput; - private final boolean mHasInput; - private final boolean mIsInputHeadset; - private final boolean mIsOutputHeadset; - private final boolean mIsDock; + // The following two constant will be used as index to access arrays. + private static final int INPUT = 0; + private static final int OUTPUT = 1; + private static final int NUM_DIRECTIONS = 2; + private static final String[] DIRECTION_STR = {"INPUT", "OUTPUT"}; + private final boolean[] mHasDevice = new boolean[NUM_DIRECTIONS]; - private boolean mSelected = false; - private int mOutputState; - private int mInputState; + private final boolean[] mIsHeadset = new boolean[NUM_DIRECTIONS]; + private final boolean mIsDock; + private final int[] mDeviceType = new int[NUM_DIRECTIONS]; + private boolean[] mIsSelected = new boolean[NUM_DIRECTIONS]; + private int[] mState = new int[NUM_DIRECTIONS]; private UsbAlsaJackDetector mJackDetector; private IAudioService mAudioService; @@ -60,11 +66,13 @@ public final class UsbAlsaDevice { mCardNum = card; mDeviceNum = device; mDeviceAddress = deviceAddress; - mHasOutput = hasOutput; - mHasInput = hasInput; - mIsInputHeadset = isInputHeadset; - mIsOutputHeadset = isOutputHeadset; + mHasDevice[OUTPUT] = hasOutput; + mHasDevice[INPUT] = hasInput; + mIsHeadset[INPUT] = isInputHeadset; + mIsHeadset[OUTPUT] = isOutputHeadset; mIsDock = isDock; + initDeviceType(); + mAlsaCardDeviceString = getAlsaCardDeviceString(); } /** @@ -104,28 +112,28 @@ public final class UsbAlsaDevice { * @return true if the device supports output. */ public boolean hasOutput() { - return mHasOutput; + return mHasDevice[OUTPUT]; } /** * @return true if the device supports input (recording). */ public boolean hasInput() { - return mHasInput; + return mHasDevice[INPUT]; } /** - * @return true if the device is a headset for purposes of input. + * @return true if the device is a headset for purposes of output. */ - public boolean isInputHeadset() { - return mIsInputHeadset; + public boolean isOutputHeadset() { + return mIsHeadset[OUTPUT]; } /** - * @return true if the device is a headset for purposes of output. + * @return true if the device is a headset for purposes of input. */ - public boolean isOutputHeadset() { - return mIsOutputHeadset; + public boolean isInputHeadset() { + return mIsHeadset[INPUT]; } /** @@ -157,6 +165,9 @@ public final class UsbAlsaDevice { /** Begins a jack-detection thread. */ private synchronized void startJackDetect() { + if (mJackDetector != null) { + return; + } // If no jack detect capabilities exist, mJackDetector will be null. mJackDetector = UsbAlsaJackDetector.startJackDetect(this); } @@ -171,75 +182,152 @@ public final class UsbAlsaDevice { /** Start using this device as the selected USB Audio Device. */ public synchronized void start() { - mSelected = true; - mInputState = 0; - mOutputState = 0; + startInput(); + startOutput(); + } + + /** Start using this device as the selected USB input device. */ + public synchronized void startInput() { + startDevice(INPUT); + } + + /** Start using this device as selected USB output device. */ + public synchronized void startOutput() { + startDevice(OUTPUT); + } + + private void startDevice(int direction) { + if (mIsSelected[direction]) { + return; + } + mIsSelected[direction] = true; + mState[direction] = 0; startJackDetect(); - updateWiredDeviceConnectionState(true); + updateWiredDeviceConnectionState(direction, true /*enable*/); } /** Stop using this device as the selected USB Audio Device. */ public synchronized void stop() { - stopJackDetect(); - updateWiredDeviceConnectionState(false); - mSelected = false; + stopInput(); + stopOutput(); } - /** Updates AudioService with the connection state of the alsaDevice. - * Checks ALSA Jack state for inputs and outputs before reporting. - */ - public synchronized void updateWiredDeviceConnectionState(boolean enable) { - if (!mSelected) { - Slog.e(TAG, "updateWiredDeviceConnectionState on unselected AlsaDevice!"); + /** Stop using this device as the selected USB input device. */ + public synchronized void stopInput() { + if (!mIsSelected[INPUT]) { return; } - String alsaCardDeviceString = getAlsaCardDeviceString(); - if (alsaCardDeviceString == null) { + if (!mIsSelected[OUTPUT]) { + // Stop jack detection when both input and output are stopped + stopJackDetect(); + } + updateInputWiredDeviceConnectionState(false /*enable*/); + mIsSelected[INPUT] = false; + } + + /** Stop using this device as the selected USB output device. */ + public synchronized void stopOutput() { + if (!mIsSelected[OUTPUT]) { return; } - try { - // Output Device - if (mHasOutput) { - int device = mIsDock ? AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET - : (mIsOutputHeadset - ? AudioSystem.DEVICE_OUT_USB_HEADSET - : AudioSystem.DEVICE_OUT_USB_DEVICE); - if (DEBUG) { - Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(device) - + " addr:" + alsaCardDeviceString - + " name:" + mDeviceName); - } - boolean connected = isOutputJackConnected(); - Slog.i(TAG, "OUTPUT JACK connected: " + connected); - int outputState = (enable && connected) ? 1 : 0; - if (outputState != mOutputState) { - mOutputState = outputState; - AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, - alsaCardDeviceString, mDeviceName); - mAudioService.setWiredDeviceConnectionState(attributes, outputState, TAG); - } - } + if (!mIsSelected[INPUT]) { + // Stop jack detection when both input and output are stopped + stopJackDetect(); + } + updateOutputWiredDeviceConnectionState(false /*enable*/); + mIsSelected[OUTPUT] = false; + } + + private void initDeviceType() { + mDeviceType[INPUT] = mHasDevice[INPUT] + ? (mIsHeadset[INPUT] ? AudioSystem.DEVICE_IN_USB_HEADSET + : AudioSystem.DEVICE_IN_USB_DEVICE) + : AudioSystem.DEVICE_NONE; + mDeviceType[OUTPUT] = mHasDevice[OUTPUT] + ? (mIsDock ? AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET + : (mIsHeadset[OUTPUT] ? AudioSystem.DEVICE_OUT_USB_HEADSET + : AudioSystem.DEVICE_OUT_USB_DEVICE)) + : AudioSystem.DEVICE_NONE; + } - // Input Device - if (mHasInput) { - int device = mIsInputHeadset - ? AudioSystem.DEVICE_IN_USB_HEADSET - : AudioSystem.DEVICE_IN_USB_DEVICE; - boolean connected = isInputJackConnected(); - Slog.i(TAG, "INPUT JACK connected: " + connected); - int inputState = (enable && connected) ? 1 : 0; - if (inputState != mInputState) { - mInputState = inputState; - AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, - alsaCardDeviceString, mDeviceName); - mAudioService.setWiredDeviceConnectionState(attributes, inputState, TAG); - } + /** + * @return the output device type that will be used to notify AudioService about device + * connection. If there is no output on this device, {@link AudioSystem#DEVICE_NONE} + * will be returned. + */ + public int getOutputDeviceType() { + return mDeviceType[OUTPUT]; + } + + /** + * @return the input device type that will be used to notify AudioService about device + * connection. If there is no input on this device, {@link AudioSystem#DEVICE_NONE} + * will be returned. + */ + public int getInputDeviceType() { + return mDeviceType[INPUT]; + } + + private boolean updateWiredDeviceConnectionState(int direction, boolean enable) { + if (!mIsSelected[direction]) { + Slog.e(TAG, "Updating wired device connection state on unselected device"); + return false; + } + if (mDeviceType[direction] == AudioSystem.DEVICE_NONE) { + Slog.d(TAG, + "Unable to set device connection state as " + DIRECTION_STR[direction] + + " device type is none"); + return false; + } + if (mAlsaCardDeviceString == null) { + Slog.w(TAG, "Failed to update " + DIRECTION_STR[direction] + " device connection " + + "state failed as alsa card device string is null"); + return false; + } + if (DEBUG) { + Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(mDeviceType[direction]) + + " addr:" + mAlsaCardDeviceString + + " name:" + mDeviceName); + } + boolean connected = direction == INPUT ? isInputJackConnected() : isOutputJackConnected(); + Slog.i(TAG, DIRECTION_STR[direction] + " JACK connected: " + connected); + int state = (enable && connected) ? 1 : 0; + if (state != mState[direction]) { + mState[direction] = state; + AudioDeviceAttributes attributes = new AudioDeviceAttributes( + mDeviceType[direction], mAlsaCardDeviceString, mDeviceName); + try { + mAudioService.setWiredDeviceConnectionState(attributes, state, TAG); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState for " + + DIRECTION_STR[direction]); + return false; } - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState"); } + return true; } + /** + * Notify AudioService about the input device connection state. + * + * @param enable true to notify the device as connected. + * @return true only when it successfully notifies AudioService about the device + * connection state. + */ + public synchronized boolean updateInputWiredDeviceConnectionState(boolean enable) { + return updateWiredDeviceConnectionState(INPUT, enable); + } + + /** + * Notify AudioService about the output device connection state. + * + * @param enable true to notify the device as connected. + * @return true only when it successfully notifies AudioService about the device + * connection state. + */ + public synchronized boolean updateOutputWiredDeviceConnectionState(boolean enable) { + return updateWiredDeviceConnectionState(OUTPUT, enable); + } /** * @Override @@ -249,8 +337,8 @@ public final class UsbAlsaDevice { return "UsbAlsaDevice: [card: " + mCardNum + ", device: " + mDeviceNum + ", name: " + mDeviceName - + ", hasOutput: " + mHasOutput - + ", hasInput: " + mHasInput + "]"; + + ", hasOutput: " + mHasDevice[OUTPUT] + + ", hasInput: " + mHasDevice[INPUT] + "]"; } /** @@ -262,8 +350,8 @@ public final class UsbAlsaDevice { dump.write("card", UsbAlsaDeviceProto.CARD, mCardNum); dump.write("device", UsbAlsaDeviceProto.DEVICE, mDeviceNum); dump.write("name", UsbAlsaDeviceProto.NAME, mDeviceName); - dump.write("has_output", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasOutput); - dump.write("has_input", UsbAlsaDeviceProto.HAS_CAPTURE, mHasInput); + dump.write("has_output", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasDevice[OUTPUT]); + dump.write("has_input", UsbAlsaDeviceProto.HAS_CAPTURE, mHasDevice[INPUT]); dump.write("address", UsbAlsaDeviceProto.ADDRESS, mDeviceAddress); dump.end(token); @@ -294,10 +382,8 @@ public final class UsbAlsaDevice { UsbAlsaDevice other = (UsbAlsaDevice) obj; return (mCardNum == other.mCardNum && mDeviceNum == other.mDeviceNum - && mHasOutput == other.mHasOutput - && mHasInput == other.mHasInput - && mIsInputHeadset == other.mIsInputHeadset - && mIsOutputHeadset == other.mIsOutputHeadset + && Arrays.equals(mHasDevice, other.mHasDevice) + && Arrays.equals(mIsHeadset, other.mIsHeadset) && mIsDock == other.mIsDock); } @@ -310,10 +396,10 @@ public final class UsbAlsaDevice { int result = 1; result = prime * result + mCardNum; result = prime * result + mDeviceNum; - result = prime * result + (mHasOutput ? 0 : 1); - result = prime * result + (mHasInput ? 0 : 1); - result = prime * result + (mIsInputHeadset ? 0 : 1); - result = prime * result + (mIsOutputHeadset ? 0 : 1); + result = prime * result + (mHasDevice[OUTPUT] ? 0 : 1); + result = prime * result + (mHasDevice[INPUT] ? 0 : 1); + result = prime * result + (mIsHeadset[INPUT] ? 0 : 1); + result = prime * result + (mIsHeadset[OUTPUT] ? 0 : 1); result = prime * result + (mIsDock ? 0 : 1); return result; diff --git a/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java index c4988478df71..d4f0b59dd7f2 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java @@ -81,7 +81,8 @@ public final class UsbAlsaJackDetector implements Runnable { if (mStopJackDetect) { return false; } - mAlsaDevice.updateWiredDeviceConnectionState(true); + mAlsaDevice.updateOutputWiredDeviceConnectionState(true); + mAlsaDevice.updateInputWiredDeviceConnectionState(true); } return true; } diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index aa1d556d02d3..99881e194b07 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -20,12 +20,14 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.usb.UsbDevice; +import android.media.AudioManager; import android.media.IAudioService; import android.media.midi.MidiDeviceInfo; import android.os.Bundle; import android.os.FileObserver; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.SystemProperties; import android.provider.Settings; import android.service.usb.UsbAlsaManagerProto; import android.util.Slog; @@ -42,6 +44,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Stack; /** * UsbAlsaManager manages USB audio and MIDI devices. @@ -51,8 +54,9 @@ public final class UsbAlsaManager { private static final boolean DEBUG = false; // Flag to turn on/off multi-peripheral select mode - // Set to true to have single-device-only mode - private static final boolean mIsSingleMode = true; + // Set to true to have multi-devices mode + private static final boolean IS_MULTI_MODE = SystemProperties.getBoolean( + "ro.audio.multi_usb_mode", false /*def*/); private static final String ALSA_DIRECTORY = "/dev/snd/"; @@ -70,7 +74,11 @@ public final class UsbAlsaManager { // this is needed to map USB devices to ALSA Audio Devices, especially to remove an // ALSA device when we are notified that its associated USB device has been removed. private final ArrayList<UsbAlsaDevice> mAlsaDevices = new ArrayList<UsbAlsaDevice>(); - private UsbAlsaDevice mSelectedDevice; + // A map from device type to attached devices. Given the audio framework only supports + // single device connection per device type, only the last attached device will be + // connected to audio framework. Once the last device is removed, previous device can + // be connected to audio framework. + private HashMap<Integer, Stack<UsbAlsaDevice>> mAttachedDevices = new HashMap<>(); // // Device Denylist @@ -162,11 +170,6 @@ public final class UsbAlsaManager { Slog.d(TAG, "selectAlsaDevice() " + alsaDevice); } - // This must be where an existing USB audio device is deselected.... (I think) - if (mIsSingleMode && mSelectedDevice != null) { - deselectAlsaDevice(); - } - // FIXME Does not yet handle the case where the setting is changed // after device connection. Ideally we should handle the settings change // in SettingsObserver. Here we should log that a USB device is connected @@ -178,21 +181,18 @@ public final class UsbAlsaManager { return; } - mSelectedDevice = alsaDevice; alsaDevice.start(); + if (DEBUG) { Slog.d(TAG, "selectAlsaDevice() - done."); } } - private synchronized void deselectAlsaDevice() { + private synchronized void deselectAlsaDevice(UsbAlsaDevice selectedDevice) { if (DEBUG) { - Slog.d(TAG, "deselectAlsaDevice() mSelectedDevice " + mSelectedDevice); - } - if (mSelectedDevice != null) { - mSelectedDevice.stop(); - mSelectedDevice = null; + Slog.d(TAG, "deselectAlsaDevice() selectedDevice " + selectedDevice); } + selectedDevice.stop(); } private int getAlsaDeviceListIndexFor(String deviceAddress) { @@ -204,32 +204,86 @@ public final class UsbAlsaManager { return -1; } - private UsbAlsaDevice removeAlsaDeviceFromList(String deviceAddress) { + private void addDeviceToAttachedDevicesMap(int deviceType, UsbAlsaDevice device) { + if (deviceType == AudioManager.DEVICE_NONE) { + Slog.i(TAG, "Ignore caching device as the type is NONE, device=" + device); + return; + } + Stack<UsbAlsaDevice> devices = mAttachedDevices.get(deviceType); + if (devices == null) { + mAttachedDevices.put(deviceType, new Stack<>()); + devices = mAttachedDevices.get(deviceType); + } + devices.push(device); + } + + private void addAlsaDevice(UsbAlsaDevice device) { + mAlsaDevices.add(0, device); + addDeviceToAttachedDevicesMap(device.getInputDeviceType(), device); + addDeviceToAttachedDevicesMap(device.getOutputDeviceType(), device); + } + + private void removeDeviceFromAttachedDevicesMap(int deviceType, UsbAlsaDevice device) { + Stack<UsbAlsaDevice> devices = mAttachedDevices.get(deviceType); + if (devices == null) { + return; + } + devices.remove(device); + if (devices.isEmpty()) { + mAttachedDevices.remove(deviceType); + } + } + + private UsbAlsaDevice removeAlsaDevice(String deviceAddress) { int index = getAlsaDeviceListIndexFor(deviceAddress); if (index > -1) { - return mAlsaDevices.remove(index); + UsbAlsaDevice device = mAlsaDevices.remove(index); + removeDeviceFromAttachedDevicesMap(device.getOutputDeviceType(), device); + removeDeviceFromAttachedDevicesMap(device.getInputDeviceType(), device); + return device; } else { return null; } } - /* package */ UsbAlsaDevice selectDefaultDevice() { + private UsbAlsaDevice selectDefaultDevice(int deviceType) { if (DEBUG) { - Slog.d(TAG, "selectDefaultDevice()"); + Slog.d(TAG, "selectDefaultDevice():" + deviceType); } - if (mAlsaDevices.size() > 0) { - UsbAlsaDevice alsaDevice = mAlsaDevices.get(0); - if (DEBUG) { - Slog.d(TAG, " alsaDevice:" + alsaDevice); - } - if (alsaDevice != null) { - selectAlsaDevice(alsaDevice); - } - return alsaDevice; - } else { + Stack<UsbAlsaDevice> devices = mAttachedDevices.get(deviceType); + if (devices == null || devices.isEmpty()) { return null; } + UsbAlsaDevice alsaDevice = devices.peek(); + Slog.d(TAG, "select default device:" + alsaDevice); + if (AudioManager.isInputDevice(deviceType)) { + alsaDevice.startInput(); + } else { + alsaDevice.startOutput(); + } + return alsaDevice; + } + + private void deselectCurrentDevice(int deviceType) { + if (DEBUG) { + Slog.d(TAG, "deselectCurrentDevice():" + deviceType); + } + if (deviceType == AudioManager.DEVICE_NONE) { + return; + } + + Stack<UsbAlsaDevice> devices = mAttachedDevices.get(deviceType); + if (devices == null || devices.isEmpty()) { + return; + } + UsbAlsaDevice alsaDevice = devices.peek(); + Slog.d(TAG, "deselect current device:" + alsaDevice); + if (AudioManager.isInputDevice(deviceType)) { + alsaDevice.stopInput(); + } else { + alsaDevice.stopOutput(); + } } /* package */ void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice, @@ -246,6 +300,7 @@ public final class UsbAlsaManager { AlsaCardsParser.AlsaCardRecord cardRec = mCardsParser.findCardNumFor(deviceAddress); if (cardRec == null) { + Slog.e(TAG, "usbDeviceAdded(): cannot find sound card for " + deviceAddress); return; } @@ -275,12 +330,19 @@ public final class UsbAlsaManager { new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/, deviceAddress, hasOutput, hasInput, isInputHeadset, isOutputHeadset, isDock); - if (alsaDevice != null) { - alsaDevice.setDeviceNameAndDescription( - cardRec.getCardName(), cardRec.getCardDescription()); - mAlsaDevices.add(0, alsaDevice); - selectAlsaDevice(alsaDevice); + alsaDevice.setDeviceNameAndDescription( + cardRec.getCardName(), cardRec.getCardDescription()); + if (IS_MULTI_MODE) { + deselectCurrentDevice(alsaDevice.getInputDeviceType()); + deselectCurrentDevice(alsaDevice.getOutputDeviceType()); + } else { + // At single mode, the first device is the selected device. + if (!mAlsaDevices.isEmpty()) { + deselectAlsaDevice(mAlsaDevices.get(0)); + } } + addAlsaDevice(alsaDevice); + selectAlsaDevice(alsaDevice); } addMidiDevice(deviceAddress, usbDevice, parser, cardRec); @@ -346,12 +408,20 @@ public final class UsbAlsaManager { } // Audio - UsbAlsaDevice alsaDevice = removeAlsaDeviceFromList(deviceAddress); + UsbAlsaDevice alsaDevice = removeAlsaDevice(deviceAddress); Slog.i(TAG, "USB Audio Device Removed: " + alsaDevice); - if (alsaDevice != null && alsaDevice == mSelectedDevice) { + if (alsaDevice != null) { waitForAlsaDevice(alsaDevice.getCardNum(), false /*isAdded*/); - deselectAlsaDevice(); - selectDefaultDevice(); // if there any external devices left, select one of them + deselectAlsaDevice(alsaDevice); + if (IS_MULTI_MODE) { + selectDefaultDevice(alsaDevice.getOutputDeviceType()); + selectDefaultDevice(alsaDevice.getInputDeviceType()); + } else { + // If there are any external devices left, select the latest attached one + if (!mAlsaDevices.isEmpty() && mAlsaDevices.get(0) != null) { + selectAlsaDevice(mAlsaDevices.get(0)); + } + } } // MIDI @@ -362,7 +432,6 @@ public final class UsbAlsaManager { } logDevices("usbDeviceRemoved()"); - } /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) { diff --git a/services/voiceinteraction/Android.bp b/services/voiceinteraction/Android.bp index 7332d2d8b0f6..de8d1440e6ac 100644 --- a/services/voiceinteraction/Android.bp +++ b/services/voiceinteraction/Android.bp @@ -9,11 +9,60 @@ package { filegroup { name: "services.voiceinteraction-sources", - srcs: ["java/**/*.java"], + srcs: ["java/com/android/server/voiceinteraction/*.java"], path: "java", visibility: ["//frameworks/base/services"], } +filegroup { + name: "services.soundtrigger_middleware-sources", + srcs: ["java/com/android/server/soundtrigger_middleware/*.java"], + path: "java", + visibility: ["//visibility:private"], +} + +filegroup { + name: "services.soundtrigger_service-sources", + srcs: ["java/com/android/server/soundtrigger/*.java"], + path: "java", + visibility: ["//visibility:private"], +} + +filegroup { + name: "services.soundtrigger-sources", + srcs: [ + ":services.soundtrigger_service-sources", + ":services.soundtrigger_middleware-sources", + ], + path: "java", + visibility: ["//frameworks/base/services"], +} + +java_library_static { + name: "services.soundtrigger_middleware", + defaults: ["platform_service_defaults"], + srcs: [":services.soundtrigger_middleware-sources"], + libs: [ + "services.core", + ], + static_libs: [ + "android.hardware.soundtrigger-V2.3-java", + ], + visibility: ["//visibility/base/services/tests/voiceinteraction"], +} + +java_library_static { + name: "services.soundtrigger", + defaults: ["platform_service_defaults"], + srcs: [":services.soundtrigger_service-sources"], + libs: [ + "services.core", + ], + static_libs: [ + "services.soundtrigger_middleware", + ], +} + java_library_static { name: "services.voiceinteraction", defaults: ["platform_service_defaults"], diff --git a/services/voiceinteraction/TEST_MAPPING b/services/voiceinteraction/TEST_MAPPING index 5fe1c8d2ecb0..f098155a9bf7 100644 --- a/services/voiceinteraction/TEST_MAPPING +++ b/services/voiceinteraction/TEST_MAPPING @@ -5,6 +5,9 @@ "options": [ { "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-filter": "android.voiceinteraction.cts.HotwordDetectionServiceStressTest" } ] }, diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index 5efd158133ed..07dc1c66bc4d 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -315,12 +315,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig, int keyphraseId, boolean runInBatterySaverMode) { synchronized (mLock) { + // TODO Remove previous callback handling IRecognitionStatusCallback oldCallback = modelData.getCallback(); if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) { Slog.w(TAG, "Canceling previous recognition for model id: " + modelData.getModelId()); try { - oldCallback.onError(STATUS_ERROR); + oldCallback.onPreempted(); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in onDetectionStopped", e); } @@ -759,15 +760,12 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { onRecognitionAbortLocked(event); break; case SoundTrigger.RECOGNITION_STATUS_FAILURE: - // Fire failures to all listeners since it's not tied to a keyphrase. - onRecognitionFailureLocked(); - break; case SoundTrigger.RECOGNITION_STATUS_SUCCESS: case SoundTrigger.RECOGNITION_STATUS_GET_STATE_RESPONSE: if (isKeyphraseRecognitionEvent(event)) { - onKeyphraseRecognitionSuccessLocked((KeyphraseRecognitionEvent) event); + onKeyphraseRecognitionLocked((KeyphraseRecognitionEvent) event); } else { - onGenericRecognitionSuccessLocked((GenericRecognitionEvent) event); + onGenericRecognitionLocked((GenericRecognitionEvent) event); } break; } @@ -778,7 +776,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return event instanceof KeyphraseRecognitionEvent; } - private void onGenericRecognitionSuccessLocked(GenericRecognitionEvent event) { + private void onGenericRecognitionLocked(GenericRecognitionEvent event) { MetricsLogger.count(mContext, "sth_generic_recognition_event", 1); if (event.status != SoundTrigger.RECOGNITION_STATUS_SUCCESS && event.status != SoundTrigger.RECOGNITION_STATUS_GET_STATE_RESPONSE) { @@ -901,17 +899,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } - private void onRecognitionFailureLocked() { - Slog.w(TAG, "Recognition failure"); - MetricsLogger.count(mContext, "sth_recognition_failure_event", 1); - try { - sendErrorCallbacksToAllLocked(STATUS_ERROR); - } finally { - internalClearModelStateLocked(); - internalClearGlobalStateLocked(); - } - } - private int getKeyphraseIdFromEvent(KeyphraseRecognitionEvent event) { if (event == null) { Slog.w(TAG, "Null RecognitionEvent received."); @@ -927,7 +914,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return keyphraseExtras[0].id; } - private void onKeyphraseRecognitionSuccessLocked(KeyphraseRecognitionEvent event) { + private void onKeyphraseRecognitionLocked(KeyphraseRecognitionEvent event) { Slog.i(TAG, "Recognition success"); MetricsLogger.count(mContext, "sth_keyphrase_recognition_event", 1); int keyphraseId = getKeyphraseIdFromEvent(event); @@ -1001,7 +988,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { private void onServiceDiedLocked() { try { MetricsLogger.count(mContext, "sth_service_died", 1); - sendErrorCallbacksToAllLocked(SoundTrigger.STATUS_DEAD_OBJECT); + for (ModelData modelData : mModelDataMap.values()) { + IRecognitionStatusCallback callback = modelData.getCallback(); + if (callback != null) { + try { + callback.onModuleDied(); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException send moduleDied for model handle " + + modelData.getHandle(), e); + } + } + } } finally { internalClearModelStateLocked(); internalClearGlobalStateLocked(); @@ -1111,21 +1108,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } - // Sends an error callback to all models with a valid registered callback. - private void sendErrorCallbacksToAllLocked(int errorCode) { - for (ModelData modelData : mModelDataMap.values()) { - IRecognitionStatusCallback callback = modelData.getCallback(); - if (callback != null) { - try { - callback.onError(errorCode); - } catch (RemoteException e) { - Slog.w(TAG, "RemoteException sendErrorCallbacksToAllLocked for model handle " + - modelData.getHandle(), e); - } - } - } - } - /** * Stops and unloads all models. This is intended as a clean-up call with the expectation that * this instance is not used after. @@ -1342,11 +1324,11 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { // Notify of error if needed. if (notifyClientOnError) { try { - callback.onError(status); + callback.onResumeFailed(status); } catch (DeadObjectException e) { forceStopAndUnloadModelLocked(modelData, e); } catch (RemoteException e) { - Slog.w(TAG, "RemoteException in onError", e); + Slog.w(TAG, "RemoteException in onResumeFailed", e); } } } else { @@ -1382,15 +1364,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { status = mModule.stopRecognition(modelData.getHandle()); if (status != SoundTrigger.STATUS_OK) { - Slog.w(TAG, "stopRecognition call failed with " + status); + Slog.e(TAG, "stopRecognition call failed with " + status); MetricsLogger.count(mContext, "sth_stop_recognition_error", 1); if (notify) { try { - callback.onError(status); + callback.onPauseFailed(status); } catch (DeadObjectException e) { forceStopAndUnloadModelLocked(modelData, e); } catch (RemoteException e) { - Slog.w(TAG, "RemoteException in onError", e); + Slog.w(TAG, "RemoteException in onPauseFailed", e); } } } else { diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java index 04c1c0451e63..1bbea89f5acb 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java @@ -25,6 +25,7 @@ import static android.content.pm.PackageManager.GET_META_DATA; import static android.content.pm.PackageManager.GET_SERVICES; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; import static android.hardware.soundtrigger.SoundTrigger.STATUS_BAD_VALUE; +import static android.hardware.soundtrigger.SoundTrigger.STATUS_DEAD_OBJECT; import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR; import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK; import static android.provider.Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY; @@ -39,12 +40,13 @@ import android.app.ActivityThread; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.PermissionChecker; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.hardware.soundtrigger.ConversionUtil; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.ModelParams; -import android.hardware.soundtrigger.ConversionUtil; import android.hardware.soundtrigger.SoundTrigger; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; @@ -64,6 +66,7 @@ import android.media.permission.SafeCloseable; import android.media.soundtrigger.ISoundTriggerDetectionService; import android.media.soundtrigger.ISoundTriggerDetectionServiceClient; import android.media.soundtrigger.SoundTriggerDetectionService; +import android.media.soundtrigger_middleware.ISoundTriggerInjection; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.os.Binder; import android.os.Bundle; @@ -74,8 +77,8 @@ import android.os.Parcel; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.RemoteException; -import android.os.ServiceSpecificException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; @@ -86,6 +89,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.ISoundTriggerService; import com.android.internal.app.ISoundTriggerSession; +import com.android.server.SoundTriggerInternal; import com.android.server.SystemService; import com.android.server.utils.EventLogger; @@ -98,8 +102,8 @@ import java.util.Map; import java.util.Objects; import java.util.TreeMap; import java.util.UUID; -import java.util.stream.Collectors; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * A single SystemService to manage all sound/voice-based sound models on the DSP. @@ -296,6 +300,23 @@ public class SoundTriggerService extends SystemService { return listUnderlyingModuleProperties(originatorIdentity); } } + + @Override + public void attachInjection(@NonNull ISoundTriggerInjection injection) { + if (PermissionChecker.checkCallingPermissionForPreflight(mContext, + android.Manifest.permission.MANAGE_SOUND_TRIGGER, null) + != PermissionChecker.PERMISSION_GRANTED) { + throw new SecurityException(); + } + try { + ISoundTriggerMiddlewareService.Stub + .asInterface(ServiceManager + .waitForService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE)) + .attachFakeHalInjection(injection); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } class SoundTriggerSessionStub extends ISoundTriggerSession.Stub { @@ -1368,8 +1389,7 @@ public class SoundTriggerService extends SystemService { })); } - @Override - public void onError(int status) { + private void onError(int status) { if (DEBUG) Slog.v(TAG, mPuuid + ": onError: " + status); sEventLogger.enqueue(new EventLogger.StringEvent(mPuuid @@ -1392,6 +1412,30 @@ public class SoundTriggerService extends SystemService { } @Override + public void onPreempted() { + if (DEBUG) Slog.v(TAG, mPuuid + ": onPreempted"); + onError(STATUS_ERROR); + } + + @Override + public void onModuleDied() { + if (DEBUG) Slog.v(TAG, mPuuid + ": onModuleDied"); + onError(STATUS_DEAD_OBJECT); + } + + @Override + public void onResumeFailed(int status) { + if (DEBUG) Slog.v(TAG, mPuuid + ": onResumeFailed: " + status); + onError(status); + } + + @Override + public void onPauseFailed(int status) { + if (DEBUG) Slog.v(TAG, mPuuid + ": onPauseFailed: " + status); + onError(status); + } + + @Override public void onRecognitionPaused() { Slog.i(TAG, mPuuid + "->" + mServiceName + ": IGNORED onRecognitionPaused"); diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerDuplicateModelHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerDuplicateModelHandler.java new file mode 100644 index 000000000000..01041932567c --- /dev/null +++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerDuplicateModelHandler.java @@ -0,0 +1,205 @@ +/* + * 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.soundtrigger_middleware; + +import android.annotation.NonNull; +import android.media.soundtrigger.ModelParameterRange; +import android.media.soundtrigger.PhraseSoundModel; +import android.media.soundtrigger.Properties; +import android.media.soundtrigger.RecognitionConfig; +import android.media.soundtrigger.SoundModel; +import android.media.soundtrigger.Status; +import android.os.IBinder; + +import java.util.ArrayList; +import java.util.List; + +/** + * This wrapper prevents a models with the same UUID from being loaded concurrently. This is used to + * protect STHAL implementations, which don't support concurrent loads of the same model. We reject + * the duplicate load with {@link Status#RESOURCE_CONTENTION}. + */ +public class SoundTriggerDuplicateModelHandler implements ISoundTriggerHal { + private final @NonNull ISoundTriggerHal mDelegate; + + private GlobalCallback mGlobalCallback; + // There are rarely more than two models loaded. + private final List<ModelData> mModelList = new ArrayList<>(); + + private static final class ModelData { + ModelData(int modelId, String uuid) { + mModelId = modelId; + mUuid = uuid; + } + + int getModelId() { + return mModelId; + } + + String getUuid() { + return mUuid; + } + + boolean getWasContended() { + return mWasContended; + } + + void setWasContended() { + mWasContended = true; + } + + private int mModelId; + private String mUuid; + private boolean mWasContended = false; + } + + public SoundTriggerDuplicateModelHandler(@NonNull ISoundTriggerHal delegate) { + mDelegate = delegate; + } + + @Override + public void reboot() { + mDelegate.reboot(); + } + + @Override + public void detach() { + mDelegate.detach(); + } + + @Override + public Properties getProperties() { + return mDelegate.getProperties(); + } + + @Override + public void registerCallback(GlobalCallback callback) { + mGlobalCallback = callback; + mDelegate.registerCallback(mGlobalCallback); + } + + @Override + public int loadSoundModel(SoundModel soundModel, ModelCallback callback) { + synchronized (this) { + checkDuplicateModelUuid(soundModel.uuid); + var result = mDelegate.loadSoundModel(soundModel, callback); + mModelList.add(new ModelData(result, soundModel.uuid)); + return result; + } + } + + @Override + public int loadPhraseSoundModel(PhraseSoundModel soundModel, ModelCallback callback) { + synchronized (this) { + checkDuplicateModelUuid(soundModel.common.uuid); + var result = mDelegate.loadPhraseSoundModel(soundModel, callback); + mModelList.add(new ModelData(result, soundModel.common.uuid)); + return result; + } + } + + @Override + public void unloadSoundModel(int modelHandle) { + mDelegate.unloadSoundModel(modelHandle); + for (int i = 0; i < mModelList.size(); i++) { + if (mModelList.get(i).getModelId() == modelHandle) { + var modelData = mModelList.remove(i); + if (modelData.getWasContended()) { + mGlobalCallback.onResourcesAvailable(); + } + // Model ID is unique + return; + } + } + } + + // Uninteresting delegation calls to follow. + @Override + public void stopRecognition(int modelHandle) { + mDelegate.stopRecognition(modelHandle); + } + + @Override + public void startRecognition( + int modelHandle, int deviceHandle, int ioHandle, RecognitionConfig config) { + mDelegate.startRecognition(modelHandle, deviceHandle, ioHandle, config); + } + + @Override + public void forceRecognitionEvent(int modelHandle) { + mDelegate.forceRecognitionEvent(modelHandle); + } + + @Override + public int getModelParameter(int modelHandle, int param) { + return mDelegate.getModelParameter(modelHandle, param); + } + + @Override + public void setModelParameter(int modelHandle, int param, int value) { + mDelegate.setModelParameter(modelHandle, param, value); + } + + @Override + public ModelParameterRange queryParameter(int modelHandle, int param) { + return mDelegate.queryParameter(modelHandle, param); + } + + @Override + public void linkToDeath(IBinder.DeathRecipient recipient) { + mDelegate.linkToDeath(recipient); + } + + @Override + public void unlinkToDeath(IBinder.DeathRecipient recipient) { + mDelegate.unlinkToDeath(recipient); + } + + @Override + public String interfaceDescriptor() { + return mDelegate.interfaceDescriptor(); + } + + @Override + public void flushCallbacks() { + mDelegate.flushCallbacks(); + } + + @Override + public void clientAttached(IBinder binder) { + mDelegate.clientAttached(binder); + } + + @Override + public void clientDetached(IBinder binder) { + mDelegate.clientDetached(binder); + } + + /** + * Helper for handling duplicate model. If there is a load attempt for a model with a UUID which + * is already loaded: 1) Reject with {@link Status.RESOURCE_CONTENTION} 2) Mark the already + * loaded model as contended, as we need to dispatch a resource available callback following the + * original model being unloaded. + */ + private void checkDuplicateModelUuid(String uuid) { + var model = mModelList.stream().filter(x -> x.getUuid().equals(uuid)).findFirst(); + if (model.isPresent()) { + model.get().setWasContended(); + throw new RecoverableException(Status.RESOURCE_CONTENTION); + } + } +} diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java index d2d8f1ad7a71..6223b2e8ace4 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java @@ -170,7 +170,8 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo */ private void attachToHal() { mHalService = new SoundTriggerHalEnforcer( - new SoundTriggerHalWatchdog(mHalFactory.create())); + new SoundTriggerHalWatchdog( + new SoundTriggerDuplicateModelHandler(mHalFactory.create()))); mHalService.linkToDeath(this); mHalService.registerCallback(this); mProperties = mHalService.getProperties(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java index aaf7a9eacce6..5846ff699f69 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java @@ -39,7 +39,7 @@ import java.util.UUID; * * @hide */ -public class DatabaseHelper extends SQLiteOpenHelper { +public class DatabaseHelper extends SQLiteOpenHelper implements IEnrolledModelDb { static final String TAG = "SoundModelDBHelper"; static final boolean DBG = false; @@ -153,11 +153,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - /** - * Updates the given keyphrase model, adds it, if it doesn't already exist. - * - * TODO: We only support one keyphrase currently. - */ + @Override public boolean updateKeyphraseSoundModel(KeyphraseSoundModel soundModel) { synchronized(this) { SQLiteDatabase db = getWritableDatabase(); @@ -193,9 +189,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - /** - * Deletes the sound model and associated keyphrases. - */ + @Override public boolean deleteKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale) { // Normalize the locale to guard against SQL injection. bcp47Locale = Locale.forLanguageTag(bcp47Locale).toLanguageTag(); @@ -218,12 +212,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - /** - * Returns a matching {@link KeyphraseSoundModel} for the keyphrase ID. - * Returns null if a match isn't found. - * - * TODO: We only support one keyphrase currently. - */ + @Override public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale) { // Sanitize the locale to guard against SQL injection. @@ -237,12 +226,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - /** - * Returns a matching {@link KeyphraseSoundModel} for the keyphrase string. - * Returns null if a match isn't found. - * - * TODO: We only support one keyphrase currently. - */ + @Override public KeyphraseSoundModel getKeyphraseSoundModel(String keyphrase, int userHandle, String bcp47Locale) { // Sanitize the locale to guard against SQL injection. diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index f3cb9baedd4b..486945d9159e 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -56,6 +56,7 @@ import android.service.voice.HotwordDetector; import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback; import android.service.voice.ISandboxedDetectionService; import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback; +import android.service.voice.SoundTriggerFailure; import android.service.voice.VisualQueryDetectionService; import android.service.voice.VisualQueryDetectionServiceFailure; import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity; @@ -153,7 +154,8 @@ final class HotwordDetectionConnection { private int mRestartCount = 0; @NonNull private ServiceConnection mRemoteHotwordDetectionService; @NonNull private ServiceConnection mRemoteVisualQueryDetectionService; - private IBinder mAudioFlinger; + @GuardedBy("mLock") + @Nullable private IBinder mAudioFlinger; @GuardedBy("mLock") private boolean mDebugHotwordLogging = false; @@ -193,7 +195,7 @@ final class HotwordDetectionConnection { new Intent(VisualQueryDetectionService.SERVICE_INTERFACE); visualQueryDetectionServiceIntent.setComponent(mVisualQueryDetectionComponentName); - initAudioFlingerLocked(); + initAudioFlinger(); mHotwordDetectionServiceConnectionFactory = new ServiceConnectionFactory(hotwordDetectionServiceIntent, @@ -226,31 +228,41 @@ final class HotwordDetectionConnection { } } - private void initAudioFlingerLocked() { + private void initAudioFlinger() { if (DEBUG) { - Slog.d(TAG, "initAudioFlingerLocked"); + Slog.d(TAG, "initAudioFlinger"); } - mAudioFlinger = ServiceManager.waitForService("media.audio_flinger"); - if (mAudioFlinger == null) { + final IBinder audioFlinger = ServiceManager.waitForService("media.audio_flinger"); + if (audioFlinger == null) { + setAudioFlinger(null); throw new IllegalStateException("Service media.audio_flinger wasn't found."); } if (DEBUG) { Slog.d(TAG, "Obtained audio_flinger binder."); } try { - mAudioFlinger.linkToDeath(mAudioServerDeathRecipient, /* flags= */ 0); + audioFlinger.linkToDeath(mAudioServerDeathRecipient, /* flags= */ 0); } catch (RemoteException e) { Slog.w(TAG, "Audio server died before we registered a DeathRecipient; " - + "retrying init.", e); - initAudioFlingerLocked(); + + "retrying init.", e); + initAudioFlinger(); + return; + } + + setAudioFlinger(audioFlinger); + } + + private void setAudioFlinger(@Nullable IBinder audioFlinger) { + synchronized (mLock) { + mAudioFlinger = audioFlinger; } } private void audioServerDied() { Slog.w(TAG, "Audio server died; restarting the HotwordDetectionService."); + // TODO: Check if this needs to be scheduled on a different thread. + initAudioFlinger(); synchronized (mLock) { - // TODO: Check if this needs to be scheduled on a different thread. - initAudioFlingerLocked(); // We restart the process instead of simply sending over the new binder, to avoid race // conditions with audio reading in the service. restartProcessLocked(); @@ -576,8 +588,31 @@ final class HotwordDetectionConnection { } @Override - public void onError(int status) throws RemoteException { - mExternalCallback.onError(status); + public void onPreempted() throws RemoteException { + mExternalCallback.onSoundTriggerFailure(new SoundTriggerFailure( + SoundTriggerFailure.ERROR_CODE_UNEXPECTED_PREEMPTION, + "Unexpected startRecognition on already started ST session")); + } + + @Override + public void onModuleDied() throws RemoteException { + mExternalCallback.onSoundTriggerFailure(new SoundTriggerFailure( + SoundTriggerFailure.ERROR_CODE_MODULE_DIED, + "STHAL died")); + } + + @Override + public void onResumeFailed(int status) throws RemoteException { + mExternalCallback.onSoundTriggerFailure(new SoundTriggerFailure( + SoundTriggerFailure.ERROR_CODE_RECOGNITION_RESUME_FAILED, + "STService recognition resume failed with: " + status)); + } + + @Override + public void onPauseFailed(int status) throws RemoteException { + mExternalCallback.onSoundTriggerFailure(new SoundTriggerFailure( + SoundTriggerFailure.ERROR_CODE_RECOGNITION_RESUME_FAILED, + "STService recognition pause failed with: " + status)); } @Override diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/IEnrolledModelDb.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/IEnrolledModelDb.java new file mode 100644 index 000000000000..f10c2f6a2325 --- /dev/null +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/IEnrolledModelDb.java @@ -0,0 +1,90 @@ +/** + * 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.voiceinteraction; + +import android.hardware.soundtrigger.SoundTrigger.Keyphrase; +import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; + +import java.io.PrintWriter; + +/** + * Interface for registering and querying the enrolled keyphrase model database for + * {@link VoiceInteractionManagerService}. + * This interface only supports one keyphrase per {@link KeyphraseSoundModel}. + * The non-update methods are uniquely keyed on fields of the first keyphrase + * {@link KeyphraseSoundModel#getKeyphrases()}. + * @hide + */ +public interface IEnrolledModelDb { + + //TODO(273286174): We only support one keyphrase currently. + /** + * Register the given {@link KeyphraseSoundModel}, or updates it if it already exists. + * + * @param soundModel - The sound model to register in the database. + * Updates the sound model if the keyphrase id, users, locale match an existing entry. + * Must have one and only one associated {@link Keyphrase}. + * @return - {@code true} if successful, {@code false} if unsuccessful + */ + boolean updateKeyphraseSoundModel(KeyphraseSoundModel soundModel); + + /** + * Deletes the previously registered keyphrase sound model from the database. + * + * @param keyphraseId - The (first) keyphrase ID of the KeyphraseSoundModel to delete. + * @param userHandle - The user handle making this request. Must be included in the user + * list of the registered sound model. + * @param bcp47Locale - The locale of the (first) keyphrase associated with this model. + * @return - {@code true} if successful, {@code false} if unsuccessful + */ + boolean deleteKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale); + + //TODO(273286174): We only support one keyphrase currently. + /** + * Returns the first matching {@link KeyphraseSoundModel} for the keyphrase ID, locale pair, + * contingent on the userHandle existing in the user list for the model. + * Returns null if a match isn't found. + * + * @param keyphraseId - The (first) keyphrase ID of the KeyphraseSoundModel to query. + * @param userHandle - The user handle making this request. Must be included in the user + * list of the registered sound model. + * @param bcp47Locale - The locale of the (first) keyphrase associated with this model. + * @return - {@code true} if successful, {@code false} if unsuccessful + */ + KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, int userHandle, + String bcp47Locale); + + //TODO(273286174): We only support one keyphrase currently. + /** + * Returns the first matching {@link KeyphraseSoundModel} for the keyphrase ID, locale pair, + * contingent on the userHandle existing in the user list for the model. + * Returns null if a match isn't found. + * + * @param keyphrase - The text of (the first) keyphrase of the KeyphraseSoundModel to query. + * @param userHandle - The user handle making this request. Must be included in the user + * list of the registered sound model. + * @param bcp47Locale - The locale of the (first) keyphrase associated with this model. + * @return - {@code true} if successful, {@code false} if unsuccessful + */ + KeyphraseSoundModel getKeyphraseSoundModel(String keyphrase, int userHandle, + String bcp47Locale); + + /** + * Dumps contents of database for dumpsys + */ + void dump(PrintWriter pw); +} diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/TestModelEnrollmentDatabase.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/TestModelEnrollmentDatabase.java new file mode 100644 index 000000000000..9bbaf8e25f95 --- /dev/null +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/TestModelEnrollmentDatabase.java @@ -0,0 +1,148 @@ +/** + * 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.voiceinteraction; + +import android.annotation.NonNull; +import android.hardware.soundtrigger.SoundTrigger.Keyphrase; +import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; + +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * In memory model enrollment database for testing purposes. + * @hide + */ +public class TestModelEnrollmentDatabase implements IEnrolledModelDb { + + // Record representing the primary key used in the real model database. + private static final class EnrollmentKey { + private final int mKeyphraseId; + private final List<Integer> mUserIds; + private final String mLocale; + + EnrollmentKey(int keyphraseId, + @NonNull List<Integer> userIds, @NonNull String locale) { + mKeyphraseId = keyphraseId; + mUserIds = Objects.requireNonNull(userIds); + mLocale = Objects.requireNonNull(locale); + } + + int keyphraseId() { + return mKeyphraseId; + } + + List<Integer> userIds() { + return mUserIds; + } + + String locale() { + return mLocale; + } + + @Override + public String toString() { + StringJoiner sj = new StringJoiner(", ", "{", "}"); + sj.add("keyphraseId: " + mKeyphraseId); + sj.add("userIds: " + mUserIds.toString()); + sj.add("locale: " + mLocale.toString()); + return "EnrollmentKey: " + sj.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int res = 1; + res = prime * res + mKeyphraseId; + res = prime * res + mUserIds.hashCode(); + res = prime * res + mLocale.hashCode(); + return res; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + if (other == null) return false; + if (!(other instanceof EnrollmentKey)) return false; + EnrollmentKey that = (EnrollmentKey) other; + if (mKeyphraseId != that.mKeyphraseId) return false; + if (!mUserIds.equals(that.mUserIds)) return false; + if (!mLocale.equals(that.mLocale)) return false; + return true; + } + + } + + private final Map<EnrollmentKey, KeyphraseSoundModel> mModelMap = new HashMap<>(); + + @Override + public boolean updateKeyphraseSoundModel(KeyphraseSoundModel soundModel) { + final Keyphrase keyphrase = soundModel.getKeyphrases()[0]; + mModelMap.put(new EnrollmentKey(keyphrase.getId(), + Arrays.stream(keyphrase.getUsers()).boxed().toList(), + keyphrase.getLocale().toLanguageTag()), + soundModel); + return true; + } + + @Override + public boolean deleteKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale) { + return mModelMap.keySet().removeIf(key -> (key.keyphraseId() == keyphraseId) + && key.locale().equals(bcp47Locale) + && key.userIds().contains(userHandle)); + } + + @Override + public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, int userHandle, + String bcp47Locale) { + return mModelMap.entrySet() + .stream() + .filter((entry) -> (entry.getKey().keyphraseId() == keyphraseId) + && entry.getKey().locale().equals(bcp47Locale) + && entry.getKey().userIds().contains(userHandle)) + .findFirst() + .map((entry) -> entry.getValue()) + .orElse(null); + } + + @Override + public KeyphraseSoundModel getKeyphraseSoundModel(String keyphrase, int userHandle, + String bcp47Locale) { + return mModelMap.entrySet() + .stream() + .filter((entry) -> (entry.getValue().getKeyphrases()[0].getText().equals(keyphrase) + && entry.getKey().locale().equals(bcp47Locale) + && entry.getKey().userIds().contains(userHandle))) + .findFirst() + .map((entry) -> entry.getValue()) + .orElse(null); + } + + + /** + * Dumps contents of database for dumpsys + */ + public void dump(PrintWriter pw) { + pw.println("Using test enrollment database, with enrolled models:"); + pw.println(mModelMap); + } +} diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index e1da2ca2a086..1d7b966bab51 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -99,11 +99,11 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.FgThread; import com.android.server.LocalServices; +import com.android.server.SoundTriggerInternal; import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.LegacyPermissionManagerInternal; -import com.android.server.soundtrigger.SoundTriggerInternal; import com.android.server.utils.Slogf; import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.wm.ActivityTaskManagerInternal; @@ -125,7 +125,9 @@ public class VoiceInteractionManagerService extends SystemService { final Context mContext; final ContentResolver mResolver; - final DatabaseHelper mDbHelper; + // Can be overridden for testing purposes + private IEnrolledModelDb mDbHelper; + private final IEnrolledModelDb mRealDbHelper; final ActivityManagerInternal mAmInternal; final ActivityTaskManagerInternal mAtmInternal; final UserManagerInternal mUserManagerInternal; @@ -143,7 +145,7 @@ public class VoiceInteractionManagerService extends SystemService { mResolver = context.getContentResolver(); mUserManagerInternal = Objects.requireNonNull( LocalServices.getService(UserManagerInternal.class)); - mDbHelper = new DatabaseHelper(context); + mDbHelper = mRealDbHelper = new DatabaseHelper(context); mServiceStub = new VoiceInteractionManagerServiceStub(); mAmInternal = Objects.requireNonNull( LocalServices.getService(ActivityManagerInternal.class)); @@ -1605,6 +1607,42 @@ public class VoiceInteractionManagerService extends SystemService { } } + @Override + @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_VOICE_KEYPHRASES) + public void setModelDatabaseForTestEnabled(boolean enabled, IBinder token) { + super.setModelDatabaseForTestEnabled_enforcePermission(); + enforceCallerAllowedToEnrollVoiceModel(); + synchronized (this) { + if (enabled) { + // Replace the dbhelper with a new test db + final var db = new TestModelEnrollmentDatabase(); + try { + // Listen to our caller death, and make sure we revert to the real + // db if they left the model in a test state. + token.linkToDeath(() -> { + synchronized (this) { + if (mDbHelper == db) { + mDbHelper = mRealDbHelper; + mImpl.notifySoundModelsChangedLocked(); + } + } + }, 0); + } catch (RemoteException e) { + // If the caller is already dead, nothing to do. + return; + } + mDbHelper = db; + mImpl.notifySoundModelsChangedLocked(); + } else { + // Nothing to do if the db is already set to the real impl. + if (mDbHelper != mRealDbHelper) { + mDbHelper = mRealDbHelper; + mImpl.notifySoundModelsChangedLocked(); + } + } + } + } + //----------------- SoundTrigger APIs --------------------------------// @Override public boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale) { @@ -1712,28 +1750,27 @@ public class VoiceInteractionManagerService extends SystemService { final long caller = Binder.clearCallingIdentity(); try { KeyphraseSoundModel soundModel = - mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale); + mDbHelper.getKeyphraseSoundModel(keyphraseId, + callingUserId, bcp47Locale); if (soundModel == null || soundModel.getUuid() == null || soundModel.getKeyphrases() == null) { Slog.w(TAG, "No matching sound model found in startRecognition"); return SoundTriggerInternal.STATUS_ERROR; - } else { - // Regardless of the status of the start recognition, we need to make sure - // that we unload this model if needed later. - synchronized (VoiceInteractionManagerServiceStub.this) { - mLoadedKeyphraseIds.put(keyphraseId, this); - if (mSessionExternalCallback == null - || mSessionInternalCallback == null - || callback.asBinder() != mSessionExternalCallback.asBinder()) { - mSessionInternalCallback = createSoundTriggerCallbackLocked( - callback); - mSessionExternalCallback = callback; - } + } + // Regardless of the status of the start recognition, we need to make sure + // that we unload this model if needed later. + synchronized (VoiceInteractionManagerServiceStub.this) { + mLoadedKeyphraseIds.put(keyphraseId, this); + if (mSessionExternalCallback == null + || mSessionInternalCallback == null + || callback.asBinder() != mSessionExternalCallback.asBinder()) { + mSessionInternalCallback = createSoundTriggerCallbackLocked(callback); + mSessionExternalCallback = callback; } - return mSession.startRecognition(keyphraseId, soundModel, - mSessionInternalCallback, recognitionConfig, runInBatterySaverMode); } + return mSession.startRecognition(keyphraseId, soundModel, + mSessionInternalCallback, recognitionConfig, runInBatterySaverMode); } finally { Binder.restoreCallingIdentity(caller); } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 62be2a555bc4..0ad86c11d29a 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -71,7 +71,6 @@ import android.util.PrintWriterPrinter; import android.util.Slog; import android.view.IWindowManager; -import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IHotwordRecognitionStatusCallback; import com.android.internal.app.IVisualQueryDetectionAttentionListener; import com.android.internal.app.IVoiceActionCheckCallback; @@ -248,7 +247,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne Context.RECEIVER_EXPORTED); } - @GuardedBy("this") public void grantImplicitAccessLocked(int grantRecipientUid, @Nullable Intent intent) { final int grantRecipientAppId = UserHandle.getAppId(grantRecipientUid); final int grantRecipientUserId = UserHandle.getUserId(grantRecipientUid); @@ -258,7 +256,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne /* direct= */ true); } - @GuardedBy("this") public boolean showSessionLocked(@Nullable Bundle args, int flags, @Nullable String attributionTag, @Nullable IVoiceInteractionSessionShowCallback showCallback, @@ -331,7 +328,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public boolean hideSessionLocked() { if (mActiveSession != null) { return mActiveSession.hideLocked(); @@ -339,7 +335,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return false; } - @GuardedBy("this") public boolean deliverNewSessionLocked(IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor) { if (mActiveSession == null || token != mActiveSession.mToken) { @@ -350,7 +345,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return true; } - @GuardedBy("this") public int startVoiceActivityLocked(@Nullable String callingFeatureId, int callingPid, int callingUid, IBinder token, Intent intent, String resolvedType) { try { @@ -373,7 +367,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public int startAssistantActivityLocked(@Nullable String callingFeatureId, int callingPid, int callingUid, IBinder token, Intent intent, String resolvedType, @NonNull Bundle bundle) { @@ -397,7 +390,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void requestDirectActionsLocked(@NonNull IBinder token, int taskId, @NonNull IBinder assistToken, @Nullable RemoteCallback cancellationCallback, @NonNull RemoteCallback callback) { @@ -453,7 +445,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") void performDirectActionLocked(@NonNull IBinder token, @NonNull String actionId, @Nullable Bundle arguments, int taskId, IBinder assistToken, @Nullable RemoteCallback cancellationCallback, @@ -480,7 +471,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void setKeepAwakeLocked(IBinder token, boolean keepAwake) { try { if (mActiveSession == null || token != mActiveSession.mToken) { @@ -493,7 +483,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void closeSystemDialogsLocked(IBinder token) { try { if (mActiveSession == null || token != mActiveSession.mToken) { @@ -506,7 +495,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void finishLocked(IBinder token, boolean finishTask) { if (mActiveSession == null || (!finishTask && token != mActiveSession.mToken)) { Slog.w(TAG, "finish does not match active session"); @@ -516,7 +504,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession = null; } - @GuardedBy("this") public void setDisabledShowContextLocked(int callingUid, int flags) { int activeUid = mInfo.getServiceInfo().applicationInfo.uid; if (callingUid != activeUid) { @@ -526,7 +513,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mDisabledShowContext = flags; } - @GuardedBy("this") public int getDisabledShowContextLocked(int callingUid) { int activeUid = mInfo.getServiceInfo().applicationInfo.uid; if (callingUid != activeUid) { @@ -536,7 +522,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return mDisabledShowContext; } - @GuardedBy("this") public int getUserDisabledShowContextLocked(int callingUid) { int activeUid = mInfo.getServiceInfo().applicationInfo.uid; if (callingUid != activeUid) { @@ -550,7 +535,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return mInfo.getSupportsLocalInteraction(); } - @GuardedBy("this") public void startListeningVisibleActivityChangedLocked(@NonNull IBinder token) { if (DEBUG) { Slog.d(TAG, "startListeningVisibleActivityChangedLocked: token=" + token); @@ -563,7 +547,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession.startListeningVisibleActivityChangedLocked(); } - @GuardedBy("this") public void stopListeningVisibleActivityChangedLocked(@NonNull IBinder token) { if (DEBUG) { Slog.d(TAG, "stopListeningVisibleActivityChangedLocked: token=" + token); @@ -576,7 +559,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession.stopListeningVisibleActivityChangedLocked(); } - @GuardedBy("this") public void notifyActivityDestroyedLocked(@NonNull IBinder activityToken) { if (DEBUG) { Slog.d(TAG, "notifyActivityDestroyedLocked activityToken=" + activityToken); @@ -591,7 +573,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession.notifyActivityDestroyedLocked(activityToken); } - @GuardedBy("this") public void notifyActivityEventChangedLocked(@NonNull IBinder activityToken, int type) { if (DEBUG) { Slog.d(TAG, "notifyActivityEventChangedLocked type=" + type); @@ -606,7 +587,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession.notifyActivityEventChangedLocked(activityToken, type); } - @GuardedBy("this") public void updateStateLocked( @Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory, @@ -627,7 +607,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") private void verifyDetectorForHotwordDetectionLocked( @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback, @@ -685,7 +664,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne voiceInteractionServiceUid); } - @GuardedBy("this") private void verifyDetectorForVisualQueryDetectionLocked(@Nullable SharedMemory sharedMemory) { Slog.v(TAG, "verifyDetectorForVisualQueryDetectionLocked"); @@ -724,7 +702,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void initAndVerifyDetectorLocked( @NonNull Identity voiceInteractorIdentity, @Nullable PersistableBundle options, @@ -769,7 +746,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne detectorType); } - @GuardedBy("this") public void destroyDetectorLocked(IBinder token) { Slog.v(TAG, "destroyDetectorLocked"); @@ -788,7 +764,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void shutdownHotwordDetectionServiceLocked() { if (DEBUG) { Slog.d(TAG, "shutdownHotwordDetectionServiceLocked"); @@ -801,7 +776,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection = null; } - @GuardedBy("this") public void setVisualQueryDetectionAttentionListenerLocked( @Nullable IVisualQueryDetectionAttentionListener listener) { if (mHotwordDetectionConnection == null) { @@ -810,7 +784,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.setVisualQueryDetectionAttentionListenerLocked(listener); } - @GuardedBy("this") public void startPerceivingLocked(IVisualQueryDetectionVoiceInteractionCallback callback) { if (DEBUG) { Slog.d(TAG, "startPerceivingLocked"); @@ -824,7 +797,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.startPerceivingLocked(callback); } - @GuardedBy("this") public void stopPerceivingLocked() { if (DEBUG) { Slog.d(TAG, "stopPerceivingLocked"); @@ -838,7 +810,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.stopPerceivingLocked(); } - @GuardedBy("this") public void startListeningFromMicLocked( AudioFormat audioFormat, IMicrophoneHotwordDetectionVoiceInteractionCallback callback) { @@ -854,7 +825,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.startListeningFromMicLocked(audioFormat, callback); } - @GuardedBy("this") public void startListeningFromExternalSourceLocked( ParcelFileDescriptor audioStream, AudioFormat audioFormat, @@ -879,7 +849,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne options, token, callback); } - @GuardedBy("this") public void stopListeningFromMicLocked() { if (DEBUG) { Slog.d(TAG, "stopListeningFromMicLocked"); @@ -893,7 +862,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.stopListeningFromMicLocked(); } - @GuardedBy("this") public void triggerHardwareRecognitionEventForTestLocked( SoundTrigger.KeyphraseRecognitionEvent event, IHotwordRecognitionStatusCallback callback) { @@ -908,7 +876,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.triggerHardwareRecognitionEventForTestLocked(event, callback); } - @GuardedBy("this") public IRecognitionStatusCallback createSoundTriggerCallbackLocked( IHotwordRecognitionStatusCallback callback) { if (DEBUG) { @@ -933,12 +900,11 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return null; } - @GuardedBy("this") boolean isIsolatedProcessLocked(@NonNull ServiceInfo serviceInfo) { 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); @@ -960,7 +926,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.forceRestart(); } - @GuardedBy("this") void setDebugHotwordLoggingLocked(boolean logging) { if (mHotwordDetectionConnection == null) { Slog.w(TAG, "Failed to set temporary debug logging: no hotword detection active"); @@ -969,7 +934,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.setDebugHotwordLoggingLocked(logging); } - @GuardedBy("this") void resetHotwordDetectionConnectionLocked() { if (DEBUG) { Slog.d(TAG, "resetHotwordDetectionConnectionLocked"); @@ -984,7 +948,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection = null; } - @GuardedBy("this") public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { if (!mValid) { pw.print(" NOT VALID: "); @@ -1023,7 +986,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") void startLocked() { Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); intent.setComponent(mComponent); @@ -1048,7 +1010,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") void shutdownLocked() { // If there is an active session, cancel it to allow it to clean up its window and other // state. @@ -1076,7 +1037,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") void notifySoundModelsChangedLocked() { if (mService == null) { Slog.w(TAG, "Not bound to voice interaction service " + mComponent); diff --git a/telecomm/java/android/telecom/CallAttributes.java b/telecomm/java/android/telecom/CallAttributes.java index f3ef834168b5..52ff90f38113 100644 --- a/telecomm/java/android/telecom/CallAttributes.java +++ b/telecomm/java/android/telecom/CallAttributes.java @@ -59,7 +59,10 @@ public final class CallAttributes implements Parcelable { public static final String CALL_CAPABILITIES_KEY = "TelecomCapabilities"; /** @hide **/ - public static final String CALLER_PID = "CallerPid"; + public static final String CALLER_PID_KEY = "CallerPid"; + + /** @hide **/ + public static final String CALLER_UID_KEY = "CallerUid"; private CallAttributes(@NonNull PhoneAccountHandle phoneAccountHandle, @NonNull CharSequence displayName, diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index e39af5aa3327..9dd2a61671ec 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -2682,71 +2682,76 @@ public class TelecomManager { } /** - * Reports a new call with the specified {@link CallAttributes} to the telecom service. This - * method can be used to report both incoming and outgoing calls. By reporting the call, the - * system is aware of the call and can provide updates on services (ex. Another device wants to - * disconnect the call) or events (ex. a new Bluetooth route became available). - * + * Add a call to the Android system service Telecom. This allows the system to start tracking an + * incoming or outgoing call with the specified {@link CallAttributes}. Once the call is ready + * to be disconnected, use the {@link CallControl#disconnect(DisconnectCause, Executor, + * OutcomeReceiver)} which is provided by the {@code pendingControl#onResult(CallControl)}. * <p> - * The difference between this API call and {@link TelecomManager#placeCall(Uri, Bundle)} or - * {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)} is that this API - * will asynchronously provide an update on whether the new call was added successfully via - * an {@link OutcomeReceiver}. Additionally, callbacks will run on the executor thread that was - * passed in. - * * <p> - * Note: Only packages that register with + * <p> + * <b>Call Lifecycle</b>: Your app is given foreground execution priority as long as you have a + * valid call and are posting a {@link android.app.Notification.CallStyle} notification. + * When your application is given foreground execution priority, your app is treated as a + * foreground service. Foreground execution priority will prevent the + * {@link android.app.ActivityManager} from killing your application when it is placed the + * background. Foreground execution priority is removed from your app when all of your app's + * calls terminate or your app no longer posts a valid notification. + * <p> + * <p> + * <p> + * <b>Note</b>: Only packages that register with * {@link PhoneAccount#CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS} * can utilize this API. {@link PhoneAccount}s that set the capabilities * {@link PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION}, * {@link PhoneAccount#CAPABILITY_CALL_PROVIDER}, * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} * are not supported and will cause an exception to be thrown. - * * <p> - * Usage example: + * <p> + * <p> + * <b>Usage example:</b> * <pre> - * - * // An app should first define their own construct of a Call that overrides all the - * // {@link CallControlCallback}s and {@link CallEventCallback}s - * private class MyVoipCall { - * public String callId = ""; - * - * public CallControlCallEventCallback handshakes = new - * CallControlCallEventCallback() { - * // override/ implement all {@link CallControlCallback}s + * // Its up to your app on how you want to wrap the objects. One such implementation can be: + * class MyVoipCall { + * ... + * public CallControlCallEventCallback handshakes = new CallControlCallback() { + * ... * } - * public CallEventCallback events = new - * CallEventCallback() { - * // override/ implement all {@link CallEventCallback}s - * } - * public MyVoipCall(String id){ - * callId = id; - * } * - * PhoneAccountHandle handle = new PhoneAccountHandle( - * new ComponentName("com.example.voip.app", - * "com.example.voip.app.NewCallActivity"), "123"); + * public CallEventCallback events = new CallEventCallback() { + * ... + * } * - * CallAttributes callAttributes = new CallAttributes.Builder(handle, - * CallAttributes.DIRECTION_OUTGOING, - * "John Smith", Uri.fromParts("tel", "123", null)) - * .build(); + * public MyVoipCall(String id){ + * ... + * } + * } * * MyVoipCall myFirstOutgoingCall = new MyVoipCall("1"); * - * telecomManager.addCall(callAttributes, Runnable::run, new OutcomeReceiver() { + * telecomManager.addCall(callAttributes, + * Runnable::run, + * new OutcomeReceiver() { * public void onResult(CallControl callControl) { - * // The call has been added successfully + * // The call has been added successfully. For demonstration + * // purposes, the call is disconnected immediately ... + * callControl.disconnect( + * new DisconnectCause(DisconnectCause.LOCAL) ) * } - * }, myFirstOutgoingCall.handshakes, myFirstOutgoingCall.events); + * }, + * myFirstOutgoingCall.handshakes, + * myFirstOutgoingCall.events); * </pre> * - * @param callAttributes attributes of the new call (incoming or outgoing, address, etc. ) - * @param executor thread to run background CallEventCallback updates on - * @param pendingControl OutcomeReceiver that receives the result of addCall transaction - * @param handshakes object that overrides {@link CallControlCallback}s - * @param events object that overrides {@link CallEventCallback}s + * @param callAttributes attributes of the new call (incoming or outgoing, address, etc.) + * @param executor execution context to run {@link CallControlCallback} updates on + * @param pendingControl Receives the result of addCall transaction. Upon success, a + * CallControl object is provided which can be used to do things like + * disconnect the call that was added. + * @param handshakes callback that receives <b>actionable</b> updates that originate from + * Telecom. + * @param events callback that receives <b>non</b>-actionable updates that originate + * from Telecom. */ @RequiresPermission(android.Manifest.permission.MANAGE_OWN_CALLS) @SuppressLint("SamShouldBeLast") diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 78c61964edfd..559faf9b20de 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -3142,10 +3142,10 @@ public class SubscriptionManager { * * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} returns * true). To check for permissions for non-embedded subscription as well, + * see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}. * * @param info The subscription to check. * @return whether the app is authorized to manage this subscription per its metadata. - * * @see android.telephony.TelephonyManager#hasCarrierPrivileges */ public boolean canManageSubscription(SubscriptionInfo info) { @@ -3159,12 +3159,12 @@ public class SubscriptionManager { * * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} returns * true). To check for permissions for non-embedded subscription as well, + * see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}. * * @param info The subscription to check. * @param packageName Package name of the app to check. * * @return whether the app is authorized to manage this subscription per its access rules. - * * @see android.telephony.TelephonyManager#hasCarrierPrivileges * @hide */ diff --git a/telephony/java/android/telephony/satellite/AntennaDirection.aidl b/telephony/java/android/telephony/satellite/AntennaDirection.aidl new file mode 100644 index 000000000000..c838f6fbb8ac --- /dev/null +++ b/telephony/java/android/telephony/satellite/AntennaDirection.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 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.telephony.satellite; + +parcelable AntennaDirection; diff --git a/telephony/java/android/telephony/satellite/AntennaDirection.java b/telephony/java/android/telephony/satellite/AntennaDirection.java new file mode 100644 index 000000000000..02b0bc7364a2 --- /dev/null +++ b/telephony/java/android/telephony/satellite/AntennaDirection.java @@ -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 android.telephony.satellite; + +import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Antenna direction is provided as X/Y/Z values corresponding to the direction of the antenna + * main lobe as a unit vector in CTIA coordinate system (as specified in Appendix A of Wireless + * device CTIA OTAn test plan). CTIA coordinate system is defined relative to device’s screen + * when the device is held in default portrait mode with screen facing the user: + * + * Z axis is vertical along the plane of the device with positive Z pointing up and negative z + * pointing towards bottom of the device + * Y axis is horizontal along the plane of the device with positive Y pointing towards right of + * the phone screen and negative Y pointing towards left + * X axis is orthogonal to the Y-Z plane (phone screen), pointing away from the phone screen for + * positive X and pointing away from back of the phone for negative X. + * @hide + */ +public final class AntennaDirection implements Parcelable { + /** Antenna x axis direction. */ + private float mX; + + /** Antenna y axis direction. */ + private float mY; + + /** Antenna z axis direction. */ + private float mZ; + + /** + * @hide + */ + @UnsupportedAppUsage + public AntennaDirection(float x, float y, float z) { + mX = x; + mY = y; + mZ = z; + } + + private AntennaDirection(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeFloat(mX); + out.writeFloat(mY); + out.writeFloat(mZ); + } + + @NonNull + public static final Creator<AntennaDirection> CREATOR = + new Creator<>() { + @Override + public AntennaDirection createFromParcel(Parcel in) { + return new AntennaDirection(in); + } + + @Override + public AntennaDirection[] newArray(int size) { + return new AntennaDirection[size]; + } + }; + + @Override + @NonNull public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("X:"); + sb.append(mX); + sb.append(","); + + sb.append("Y:"); + sb.append(mY); + sb.append(","); + + sb.append("Z:"); + sb.append(mZ); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AntennaDirection that = (AntennaDirection) o; + return mX == that.mX + && mY == that.mY + && mZ == that.mZ; + } + + @Override + public int hashCode() { + return Objects.hash(mX, mY, mZ); + } + + public float getX() { + return mX; + } + + public float getY() { + return mY; + } + + public float getZ() { + return mZ; + } + + private void readFromParcel(Parcel in) { + mX = in.readFloat(); + mY = in.readFloat(); + mZ = in.readFloat(); + } +} diff --git a/telephony/java/android/telephony/satellite/AntennaPosition.aidl b/telephony/java/android/telephony/satellite/AntennaPosition.aidl new file mode 100644 index 000000000000..00525624329c --- /dev/null +++ b/telephony/java/android/telephony/satellite/AntennaPosition.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 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.telephony.satellite; + +parcelable AntennaPosition; diff --git a/telephony/java/android/telephony/satellite/AntennaPosition.java b/telephony/java/android/telephony/satellite/AntennaPosition.java new file mode 100644 index 000000000000..eefc8b00f8e8 --- /dev/null +++ b/telephony/java/android/telephony/satellite/AntennaPosition.java @@ -0,0 +1,117 @@ +/* + * 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.telephony.satellite; + +import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Antenna Position received from satellite modem which gives information about antenna + * direction to be used with satellite communication and suggested device hold positions. + * @hide + */ +public final class AntennaPosition implements Parcelable { + /** Antenna direction used for satellite communication. */ + @NonNull AntennaDirection mAntennaDirection; + + /** Enum corresponding to device hold position to be used by the end user. */ + @SatelliteManager.DeviceHoldPosition int mSuggestedHoldPosition; + + /** + * @hide + */ + @UnsupportedAppUsage + public AntennaPosition(@NonNull AntennaDirection antennaDirection, int suggestedHoldPosition) { + mAntennaDirection = antennaDirection; + mSuggestedHoldPosition = suggestedHoldPosition; + } + + private AntennaPosition(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeParcelable(mAntennaDirection, flags); + out.writeInt(mSuggestedHoldPosition); + } + + @NonNull + public static final Creator<AntennaPosition> CREATOR = + new Creator<>() { + @Override + public AntennaPosition createFromParcel(Parcel in) { + return new AntennaPosition(in); + } + + @Override + public AntennaPosition[] newArray(int size) { + return new AntennaPosition[size]; + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AntennaPosition that = (AntennaPosition) o; + return Objects.equals(mAntennaDirection, that.mAntennaDirection) + && mSuggestedHoldPosition == that.mSuggestedHoldPosition; + } + + @Override + public int hashCode() { + return Objects.hash(mAntennaDirection, mSuggestedHoldPosition); + } + + @Override + @NonNull public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("antennaDirection:"); + sb.append(mAntennaDirection); + sb.append(","); + + sb.append("suggestedHoldPosition:"); + sb.append(mSuggestedHoldPosition); + return sb.toString(); + } + + @NonNull + public AntennaDirection getAntennaDirection() { + return mAntennaDirection; + } + + @SatelliteManager.DeviceHoldPosition + public int getSuggestedHoldPosition() { + return mSuggestedHoldPosition; + } + + private void readFromParcel(Parcel in) { + mAntennaDirection = in.readParcelable(AntennaDirection.class.getClassLoader(), + AntennaDirection.class); + mSuggestedHoldPosition = in.readInt(); + } +} diff --git a/telephony/java/android/telephony/satellite/PointingInfo.java b/telephony/java/android/telephony/satellite/PointingInfo.java index e8a8576daf58..a559b32f0021 100644 --- a/telephony/java/android/telephony/satellite/PointingInfo.java +++ b/telephony/java/android/telephony/satellite/PointingInfo.java @@ -17,7 +17,6 @@ package android.telephony.satellite; import android.annotation.NonNull; -import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -34,7 +33,7 @@ public final class PointingInfo implements Parcelable { /** * @hide */ - @UnsupportedAppUsage + public PointingInfo(float satelliteAzimuthDegrees, float satelliteElevationDegrees) { mSatelliteAzimuthDegrees = satelliteAzimuthDegrees; mSatelliteElevationDegrees = satelliteElevationDegrees; diff --git a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java index 87c8db317195..6856cc0c5df2 100644 --- a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java +++ b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java @@ -17,11 +17,13 @@ package android.telephony.satellite; import android.annotation.NonNull; -import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -44,15 +46,24 @@ public final class SatelliteCapabilities implements Parcelable { private int mMaxBytesPerOutgoingDatagram; /** + * Antenna Position received from satellite modem which gives information about antenna + * direction to be used with satellite communication and suggested device hold positions. + * Map key: {@link SatelliteManager.DeviceHoldPosition} value: AntennaPosition + */ + @NonNull + private Map<Integer, AntennaPosition> mAntennaPositionMap; + + /** * @hide */ - @UnsupportedAppUsage public SatelliteCapabilities(Set<Integer> supportedRadioTechnologies, - boolean isPointingRequired, int maxBytesPerOutgoingDatagram) { + boolean isPointingRequired, int maxBytesPerOutgoingDatagram, + @NonNull Map<Integer, AntennaPosition> antennaPositionMap) { mSupportedRadioTechnologies = supportedRadioTechnologies == null ? new HashSet<>() : supportedRadioTechnologies; mIsPointingRequired = isPointingRequired; mMaxBytesPerOutgoingDatagram = maxBytesPerOutgoingDatagram; + mAntennaPositionMap = antennaPositionMap; } private SatelliteCapabilities(Parcel in) { @@ -77,6 +88,17 @@ public final class SatelliteCapabilities implements Parcelable { out.writeBoolean(mIsPointingRequired); out.writeInt(mMaxBytesPerOutgoingDatagram); + + if (mAntennaPositionMap != null && !mAntennaPositionMap.isEmpty()) { + int size = mAntennaPositionMap.size(); + out.writeInt(size); + for (Map.Entry<Integer, AntennaPosition> entry : mAntennaPositionMap.entrySet()) { + out.writeInt(entry.getKey()); + out.writeParcelable(entry.getValue(), flags); + } + } else { + out.writeInt(0); + } } @NonNull public static final Creator<SatelliteCapabilities> CREATOR = new Creator<>() { @@ -109,11 +131,32 @@ public final class SatelliteCapabilities implements Parcelable { sb.append(mIsPointingRequired); sb.append(","); - sb.append("maxBytesPerOutgoingDatagram"); + sb.append("maxBytesPerOutgoingDatagram:"); sb.append(mMaxBytesPerOutgoingDatagram); + sb.append(","); + + sb.append("antennaPositionMap:"); + sb.append(mAntennaPositionMap); return sb.toString(); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SatelliteCapabilities that = (SatelliteCapabilities) o; + return Objects.equals(mSupportedRadioTechnologies, that.mSupportedRadioTechnologies) + && mIsPointingRequired == that.mIsPointingRequired + && mMaxBytesPerOutgoingDatagram == that.mMaxBytesPerOutgoingDatagram + && Objects.equals(mAntennaPositionMap, that.mAntennaPositionMap); + } + + @Override + public int hashCode() { + return Objects.hash(mSupportedRadioTechnologies, mIsPointingRequired, + mMaxBytesPerOutgoingDatagram, mAntennaPositionMap); + } + /** * @return The list of technologies supported by the satellite modem. */ @@ -141,6 +184,16 @@ public final class SatelliteCapabilities implements Parcelable { return mMaxBytesPerOutgoingDatagram; } + /** + * Antenna Position received from satellite modem which gives information about antenna + * direction to be used with satellite communication and suggested device hold positions. + * @return Map key: {@link SatelliteManager.DeviceHoldPosition} value: AntennaPosition + */ + @NonNull + public Map<Integer, AntennaPosition> getAntennaPositionMap() { + return mAntennaPositionMap; + } + private void readFromParcel(Parcel in) { mSupportedRadioTechnologies = new HashSet<>(); int numSupportedRadioTechnologies = in.readInt(); @@ -152,5 +205,14 @@ public final class SatelliteCapabilities implements Parcelable { mIsPointingRequired = in.readBoolean(); mMaxBytesPerOutgoingDatagram = in.readInt(); + + mAntennaPositionMap = new HashMap<>(); + int antennaPositionMapSize = in.readInt(); + for (int i = 0; i < antennaPositionMapSize; i++) { + int key = in.readInt(); + AntennaPosition antennaPosition = in.readParcelable( + AntennaPosition.class.getClassLoader(), AntennaPosition.class); + mAntennaPositionMap.put(key, antennaPosition); + } } } diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagram.java b/telephony/java/android/telephony/satellite/SatelliteDatagram.java index 44f56f3d315c..d3cb8a07e4ba 100644 --- a/telephony/java/android/telephony/satellite/SatelliteDatagram.java +++ b/telephony/java/android/telephony/satellite/SatelliteDatagram.java @@ -17,7 +17,6 @@ package android.telephony.satellite; import android.annotation.NonNull; -import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -33,7 +32,6 @@ public final class SatelliteDatagram implements Parcelable { /** * @hide */ - @UnsupportedAppUsage public SatelliteDatagram(@NonNull byte[] data) { mData = data; } diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java index d0409bf5df49..b2dec71ecb32 100644 --- a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java +++ b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java @@ -17,7 +17,6 @@ package android.telephony.satellite; import android.annotation.NonNull; -import android.compat.annotation.UnsupportedAppUsage; import java.util.function.Consumer; @@ -37,7 +36,6 @@ public interface SatelliteDatagramCallback { * that they received the datagram. If the callback is not received within * five minutes, Telephony will resend the datagram. */ - @UnsupportedAppUsage void onSatelliteDatagramReceived(long datagramId, @NonNull SatelliteDatagram datagram, int pendingCount, @NonNull Consumer<Void> callback); } diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java index 20f9bc8bef05..c5830b8249c8 100644 --- a/telephony/java/android/telephony/satellite/SatelliteManager.java +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -23,7 +23,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; -import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; @@ -37,8 +36,8 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyFrameworkInitializer; import com.android.internal.telephony.IIntegerConsumer; -import com.android.internal.telephony.IVoidConsumer; import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.IVoidConsumer; import com.android.telephony.Rlog; import java.lang.annotation.Retention; @@ -83,7 +82,7 @@ public class SatelliteManager { * @param context The context the SatelliteManager belongs to. * @hide */ - @UnsupportedAppUsage + public SatelliteManager(@Nullable Context context) { this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); } @@ -129,7 +128,7 @@ public class SatelliteManager { * {@link #requestIsSatelliteEnabled(Executor, OutcomeReceiver)}. * @hide */ - @UnsupportedAppUsage + public static final String KEY_SATELLITE_ENABLED = "satellite_enabled"; /** @@ -137,7 +136,7 @@ public class SatelliteManager { * {@link #requestIsDemoModeEnabled(Executor, OutcomeReceiver)}. * @hide */ - @UnsupportedAppUsage + public static final String KEY_DEMO_MODE_ENABLED = "demo_mode_enabled"; /** @@ -145,7 +144,7 @@ public class SatelliteManager { * {@link #requestIsSatelliteSupported(Executor, OutcomeReceiver)}. * @hide */ - @UnsupportedAppUsage + public static final String KEY_SATELLITE_SUPPORTED = "satellite_supported"; /** @@ -153,7 +152,7 @@ public class SatelliteManager { * {@link #requestSatelliteCapabilities(Executor, OutcomeReceiver)}. * @hide */ - @UnsupportedAppUsage + public static final String KEY_SATELLITE_CAPABILITIES = "satellite_capabilities"; /** @@ -161,7 +160,7 @@ public class SatelliteManager { * {@link #requestIsSatelliteProvisioned(Executor, OutcomeReceiver)}. * @hide */ - @UnsupportedAppUsage + public static final String KEY_SATELLITE_PROVISIONED = "satellite_provisioned"; /** @@ -169,7 +168,7 @@ public class SatelliteManager { * {@link #requestIsSatelliteCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}. * @hide */ - @UnsupportedAppUsage + public static final String KEY_SATELLITE_COMMUNICATION_ALLOWED = "satellite_communication_allowed"; @@ -178,7 +177,7 @@ public class SatelliteManager { * {@link #requestTimeForNextSatelliteVisibility(Executor, OutcomeReceiver)}. * @hide */ - @UnsupportedAppUsage + public static final String KEY_SATELLITE_NEXT_VISIBILITY = "satellite_next_visibility"; /** @@ -334,6 +333,46 @@ public class SatelliteManager { @Retention(RetentionPolicy.SOURCE) public @interface NTRadioTechnology {} + /** Suggested device hold position is unknown. */ + public static final int DEVICE_HOLD_POSITION_UNKNOWN = 0; + /** User is suggested to hold the device in portrait mode. */ + public static final int DEVICE_HOLD_POSITION_PORTRAIT = 1; + /** User is suggested to hold the device in landscape mode with left hand. */ + public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2; + /** User is suggested to hold the device in landscape mode with right hand. */ + public static final int DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT = 3; + + /** @hide */ + @IntDef(prefix = {"DEVICE_HOLD_POSITION_"}, value = { + DEVICE_HOLD_POSITION_UNKNOWN, + DEVICE_HOLD_POSITION_PORTRAIT, + DEVICE_HOLD_POSITION_LANDSCAPE_LEFT, + DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DeviceHoldPosition {} + + /** Display mode is unknown. */ + public static final int DISPLAY_MODE_UNKNOWN = 0; + /** Display mode of the device used for satellite communication for non-foldable phones. */ + public static final int DISPLAY_MODE_FIXED = 1; + /** Display mode of the device used for satellite communication for foldabale phones when the + * device is opened. */ + public static final int DISPLAY_MODE_OPENED = 2; + /** Display mode of the device used for satellite communication for foldabable phones when the + * device is closed. */ + public static final int DISPLAY_MODE_CLOSED = 3; + + /** @hide */ + @IntDef(prefix = {"ANTENNA_POSITION_"}, value = { + DISPLAY_MODE_UNKNOWN, + DISPLAY_MODE_FIXED, + DISPLAY_MODE_OPENED, + DISPLAY_MODE_CLOSED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DisplayMode {} + /** * Request to enable or disable the satellite modem and demo mode. If the satellite modem is * enabled, this may also disable the cellular modem, and if the satellite modem is disabled, @@ -349,7 +388,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, @NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener) { @@ -392,7 +431,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void requestIsSatelliteEnabled(@NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { Objects.requireNonNull(executor); @@ -447,7 +486,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void requestIsDemoModeEnabled(@NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { Objects.requireNonNull(executor); @@ -500,7 +539,7 @@ public class SatelliteManager { * * @throws IllegalStateException if the Telephony process is not currently available. */ - @UnsupportedAppUsage + public void requestIsSatelliteSupported(@NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { Objects.requireNonNull(executor); @@ -554,7 +593,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void requestSatelliteCapabilities(@NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) { Objects.requireNonNull(executor); @@ -747,7 +786,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void startSatelliteTransmissionUpdates(@NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener, @NonNull SatelliteTransmissionUpdateCallback callback) { @@ -817,7 +856,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void stopSatelliteTransmissionUpdates( @NonNull SatelliteTransmissionUpdateCallback callback, @NonNull @CallbackExecutor Executor executor, @@ -873,7 +912,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData, @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor executor, @@ -923,7 +962,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void deprovisionSatelliteService(@NonNull String token, @NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener) { @@ -963,7 +1002,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + @SatelliteError public int registerForSatelliteProvisionStateChanged( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteProvisionStateCallback callback) { @@ -1006,7 +1045,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void unregisterForSatelliteProvisionStateChanged( @NonNull SatelliteProvisionStateCallback callback) { Objects.requireNonNull(callback); @@ -1045,7 +1084,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void requestIsSatelliteProvisioned(@NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { Objects.requireNonNull(executor); @@ -1097,7 +1136,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + @SatelliteError public int registerForSatelliteModemStateChanged( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteStateCallback callback) { @@ -1137,7 +1176,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void unregisterForSatelliteModemStateChanged(@NonNull SatelliteStateCallback callback) { Objects.requireNonNull(callback); ISatelliteStateCallback internalCallback = sSatelliteStateCallbackMap.remove(callback); @@ -1172,7 +1211,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + @SatelliteError public int registerForSatelliteDatagram( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteDatagramCallback callback) { @@ -1228,7 +1267,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void unregisterForSatelliteDatagram(@NonNull SatelliteDatagramCallback callback) { Objects.requireNonNull(callback); ISatelliteDatagramCallback internalCallback = @@ -1266,7 +1305,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void pollPendingSatelliteDatagrams(@NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener) { Objects.requireNonNull(executor); @@ -1319,7 +1358,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void sendSatelliteDatagram(@DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull @CallbackExecutor Executor executor, @@ -1365,7 +1404,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void requestIsSatelliteCommunicationAllowedForCurrentLocation( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { @@ -1423,7 +1462,7 @@ public class SatelliteManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @UnsupportedAppUsage + public void requestTimeForNextSatelliteVisibility(@NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Duration, SatelliteException> callback) { Objects.requireNonNull(executor); diff --git a/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java index 20875af94f5a..a62eb8b8a5fb 100644 --- a/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java +++ b/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java @@ -16,8 +16,6 @@ package android.telephony.satellite; -import android.compat.annotation.UnsupportedAppUsage; - /** * A callback class for monitoring satellite provision state change events. * @@ -30,6 +28,5 @@ public interface SatelliteProvisionStateCallback { * @param provisioned The new provision state. {@code true} means satellite is provisioned * {@code false} means satellite is not provisioned. */ - @UnsupportedAppUsage void onSatelliteProvisionStateChanged(boolean provisioned); } diff --git a/telephony/java/android/telephony/satellite/SatelliteStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteStateCallback.java index 3312e3a90281..d9ecaa3467e3 100644 --- a/telephony/java/android/telephony/satellite/SatelliteStateCallback.java +++ b/telephony/java/android/telephony/satellite/SatelliteStateCallback.java @@ -16,8 +16,6 @@ package android.telephony.satellite; -import android.compat.annotation.UnsupportedAppUsage; - /** * A callback class for monitoring satellite modem state change events. * @@ -28,6 +26,5 @@ public interface SatelliteStateCallback { * Called when satellite modem state changes. * @param state The new satellite modem state. */ - @UnsupportedAppUsage void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state); } diff --git a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java index 17fff4480679..d4fe57a0be2e 100644 --- a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java +++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java @@ -17,7 +17,6 @@ package android.telephony.satellite; import android.annotation.NonNull; -import android.compat.annotation.UnsupportedAppUsage; /** * A callback class for monitoring satellite position update and datagram transfer state change @@ -31,7 +30,6 @@ public interface SatelliteTransmissionUpdateCallback { * * @param pointingInfo The pointing info containing the satellite location. */ - @UnsupportedAppUsage void onSatellitePositionChanged(@NonNull PointingInfo pointingInfo); /** @@ -41,7 +39,6 @@ public interface SatelliteTransmissionUpdateCallback { * @param sendPendingCount The number of datagrams that are currently being sent. * @param errorCode If datagram transfer failed, the reason for failure. */ - @UnsupportedAppUsage void onSendDatagramStateChanged( @SatelliteManager.SatelliteDatagramTransferState int state, int sendPendingCount, @SatelliteManager.SatelliteError int errorCode); @@ -53,7 +50,6 @@ public interface SatelliteTransmissionUpdateCallback { * @param receivePendingCount The number of datagrams that are currently pending to be received. * @param errorCode If datagram transfer failed, the reason for failure. */ - @UnsupportedAppUsage void onReceiveDatagramStateChanged( @SatelliteManager.SatelliteDatagramTransferState int state, int receivePendingCount, @SatelliteManager.SatelliteError int errorCode); diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteCapabilities.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteCapabilities.aidl index cd69da18c5b0..eaf96abeb80a 100644 --- a/telephony/java/android/telephony/satellite/stub/SatelliteCapabilities.aidl +++ b/telephony/java/android/telephony/satellite/stub/SatelliteCapabilities.aidl @@ -17,7 +17,7 @@ package android.telephony.satellite.stub; import android.telephony.satellite.stub.NTRadioTechnology; - +import android.telephony.satellite.AntennaPosition; /** * {@hide} */ @@ -36,4 +36,14 @@ parcelable SatelliteCapabilities { * The maximum number of bytes per datagram that can be sent over satellite. */ int maxBytesPerOutgoingDatagram; + + /** + * Keys which are used to fill mAntennaPositionMap. + */ + int[] antennaPositionKeys; + + /** + * Antenna Position for different display modes received from satellite modem. + */ + AntennaPosition[] antennaPositionValues; } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index cbdf38ae95d4..ee9d6c1a2448 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2989,4 +2989,14 @@ interface ITelephony { * {@code false} otherwise. */ boolean setSatelliteServicePackageName(in String servicePackageName); + + /** + * This API can be used by only CTS to update the timeout duration in milliseconds that + * satellite should stay at listening mode to wait for the next incoming page before disabling + * listening mode. + * + * @param timeoutMillis The timeout duration in millisecond. + * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. + */ + boolean setSatelliteListeningTimeoutDuration(in long timeoutMillis); } diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java index cfebf3462b57..4299e0d616fb 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java +++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java @@ -87,7 +87,7 @@ public final class DynamicCodeLoggerIntegrationTests { // avoid flakiness we run these tests multiple times, allowing progressively longer between // code loading and checking the logs on each try.) private static final int AUDIT_LOG_RETRIES = 10; - private static final int RETRY_DELAY_MS = 2_000; + private static final int RETRY_DELAY_MS = 500; private static Context sContext; private static int sMyUid; @@ -253,7 +253,7 @@ public final class DynamicCodeLoggerIntegrationTests { "/DynamicCodeLoggerNativeExecutable", privateCopyFile); EventLog.writeEvent(EventLog.getTagCode("auditd"), - "type=1400 avc: granted { execute_no_trans } " + "type=1400 avc: granted { execute_no_trans } " + "path=\"" + privateCopyFile + "\" " + "scontext=u:r:untrusted_app: " + "tcontext=u:object_r:app_data_file: " diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml index f2ffc19f2a4e..7272abba897d 100644 --- a/tests/FlickerTests/AndroidTest.xml +++ b/tests/FlickerTests/AndroidTest.xml @@ -29,6 +29,7 @@ <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" /> <option name="teardown-command" value="settings delete system show_touches" /> <option name="teardown-command" value="settings delete system pointer_location" /> + <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true"/> 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 314b9e4a853b..f389e13a6884 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -260,7 +260,7 @@ fun FlickerTest.snapshotStartingWindowLayerCoversExactlyOnApp(component: ICompon snapshotLayers .mapNotNull { snapshotLayer -> snapshotLayer.layer.visibleRegion } .toTypedArray() - val snapshotRegion = RegionSubject(visibleAreas, this, timestamp) + val snapshotRegion = RegionSubject(visibleAreas, timestamp) val appVisibleRegion = it.visibleRegion(component) if (snapshotRegion.region.isNotEmpty) { snapshotRegion.coversExactly(appVisibleRegion.region) 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 6066d2e74209..34fa921f5777 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 @@ -88,7 +88,7 @@ open class CloseImeOnDismissPopupDialogTest(flicker: FlickerTest) : BaseTest(fli imeSnapshotLayers .mapNotNull { imeSnapshotLayer -> imeSnapshotLayer.layer.visibleRegion } .toTypedArray() - val imeVisibleRegion = RegionSubject(visibleAreas, this, timestamp) + val imeVisibleRegion = RegionSubject(visibleAreas, timestamp) val appVisibleRegion = it.visibleRegion(imeTestApp) if (imeVisibleRegion.region.isNotEmpty) { imeVisibleRegion.coversAtMost(appVisibleRegion.region) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt index 2fff00133eb8..d5208e060883 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt @@ -73,7 +73,16 @@ open class CloseImeToHomeOnFinishActivityTest(flicker: FlickerTest) : BaseTest(f @Test @IwTest(focusArea = "ime") override fun cujCompleted() { - super.cujCompleted() + runAndIgnoreAssumptionViolation { entireScreenCovered() } + runAndIgnoreAssumptionViolation { statusBarLayerIsVisibleAtStartAndEnd() } + runAndIgnoreAssumptionViolation { statusBarLayerPositionAtStartAndEnd() } + runAndIgnoreAssumptionViolation { statusBarWindowIsAlwaysVisible() } + runAndIgnoreAssumptionViolation { visibleWindowsShownMoreThanOneConsecutiveEntry() } + runAndIgnoreAssumptionViolation { taskBarLayerIsVisibleAtStartAndEnd() } + runAndIgnoreAssumptionViolation { taskBarWindowIsAlwaysVisible() } + runAndIgnoreAssumptionViolation { navBarLayerIsVisibleAtStartAndEnd() } + runAndIgnoreAssumptionViolation { navBarWindowIsAlwaysVisible() } + runAndIgnoreAssumptionViolation { navBarWindowIsVisibleAtStartAndEnd() } imeLayerBecomesInvisible() imeWindowBecomesInvisible() } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt index 4efee55b97b5..8f07f213521b 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt @@ -109,11 +109,11 @@ class OpenAppFromLockNotificationWithLockOverlayApp(flicker: FlickerTest) : override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd() /** {@inheritDoc} */ - @FlakyTest(bugId = 209599395) + @Presubmit @Test override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() - @FlakyTest(bugId = 266730606) + @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered() diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/BoundsInfoDrawHelper.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/BoundsInfoDrawHelper.java new file mode 100644 index 000000000000..6b924f335ef7 --- /dev/null +++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/BoundsInfoDrawHelper.java @@ -0,0 +1,116 @@ +/* + * 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.google.android.test.handwritingime; + +import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_EDITOR_BOUNDS; +import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_NONE; +import static com.google.android.test.handwritingime.HandwritingIme.BOUNDS_INFO_VISIBLE_LINE_BOUNDS; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.view.View; +import android.view.inputmethod.CursorAnchorInfo; +import android.view.inputmethod.EditorBoundsInfo; + +import androidx.annotation.Nullable; + +import com.android.internal.graphics.ColorUtils; + +import java.util.List; + +public class BoundsInfoDrawHelper { + private static final Paint sPaint = new Paint(); + private static final int EDITOR_BOUNDS_COLOR = + ColorUtils.setAlphaComponent(Color.DKGRAY, 128); + private static final int HANDWRITING_BOUNDS_COLOR = + ColorUtils.setAlphaComponent(Color.BLUE, 128); + private static final int VISIBLE_LINE_BOUNDS_COLOR = + ColorUtils.setAlphaComponent(Color.MAGENTA, 128); + + public static void draw(Canvas canvas, View inkView, int boundsInfoMode, + CursorAnchorInfo cursorAnchorInfo) { + if (boundsInfoMode == BOUNDS_INFO_NONE || cursorAnchorInfo == null) { + return; + } + + // The matrix in CursorAnchorInfo transforms the editor coordinates to on-screen + // coordinates. We then transform the matrix from the on-screen coordinates to the + // inkView's coordinates. So the result matrix transforms the editor coordinates + // to the inkView coordinates. + final Matrix matrix = cursorAnchorInfo.getMatrix(); + inkView.transformMatrixToLocal(matrix); + + if ((boundsInfoMode & BOUNDS_INFO_EDITOR_BOUNDS) != 0) { + drawEditorBoundsInfo(canvas, matrix, cursorAnchorInfo.getEditorBoundsInfo()); + } + + if ((boundsInfoMode & BOUNDS_INFO_VISIBLE_LINE_BOUNDS) != 0) { + drawVisibleLineBounds(canvas, matrix, cursorAnchorInfo.getVisibleLineBounds()); + } + } + + private static void setPaintForEditorBoundsInfo() { + sPaint.reset(); + sPaint.setStyle(Paint.Style.STROKE); + sPaint.setStrokeWidth(5f); + } + + private static void drawEditorBoundsInfo(Canvas canvas, Matrix matrix, + @Nullable EditorBoundsInfo editorBoundsInfo) { + if (editorBoundsInfo == null) { + return; + } + final RectF editorBounds = editorBoundsInfo.getEditorBounds(); + setPaintForEditorBoundsInfo(); + if (editorBounds != null) { + final RectF localEditorBounds = new RectF(editorBounds); + matrix.mapRect(localEditorBounds); + sPaint.setColor(EDITOR_BOUNDS_COLOR); + canvas.drawRect(localEditorBounds, sPaint); + } + + final RectF handwritingBounds = editorBoundsInfo.getHandwritingBounds(); + if (handwritingBounds != null) { + final RectF localHandwritingBounds = new RectF(handwritingBounds); + matrix.mapRect(localHandwritingBounds); + sPaint.setColor(HANDWRITING_BOUNDS_COLOR); + canvas.drawRect(localHandwritingBounds, sPaint); + } + } + + private static void setPaintForVisibleLineBounds() { + sPaint.reset(); + sPaint.setStyle(Paint.Style.STROKE); + sPaint.setStrokeWidth(2f); + sPaint.setColor(VISIBLE_LINE_BOUNDS_COLOR); + } + + private static void drawVisibleLineBounds(Canvas canvas, Matrix matrix, + List<RectF> visibleLineBounds) { + if (visibleLineBounds.isEmpty()) { + return; + } + setPaintForVisibleLineBounds(); + for (RectF lineBound : visibleLineBounds) { + matrix.mapRect(lineBound); + canvas.drawRect(lineBound, sPaint); + } + } +} diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java index 2fd236895467..8380dcf4b4a4 100644 --- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java +++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java @@ -25,7 +25,9 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; +import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.DeleteGesture; +import android.view.inputmethod.EditorInfo; import android.view.inputmethod.HandwritingGesture; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InsertGesture; @@ -34,6 +36,7 @@ import android.view.inputmethod.RemoveSpaceGesture; import android.view.inputmethod.SelectGesture; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.CheckBox; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.Spinner; @@ -43,9 +46,6 @@ import java.util.Random; import java.util.function.IntConsumer; public class HandwritingIme extends InputMethodService { - - public static final int HEIGHT_DP = 100; - private static final int OP_NONE = 0; private static final int OP_SELECT = 1; private static final int OP_DELETE = 2; @@ -62,6 +62,12 @@ public class HandwritingIme extends InputMethodService { private Spinner mRichGestureGranularitySpinner; private PointF mRichGestureStartPoint; + static final int BOUNDS_INFO_NONE = 0; + static final int BOUNDS_INFO_VISIBLE_LINE_BOUNDS = 1; + static final int BOUNDS_INFO_EDITOR_BOUNDS = 2; + private int mBoundsInfoMode = BOUNDS_INFO_NONE; + private LinearLayout mBoundsInfoCheckBoxes; + private final IntConsumer mResultConsumer = value -> Log.d(TAG, "Gesture result: " + value); interface HandwritingFinisher { @@ -201,12 +207,7 @@ public class HandwritingIme extends InputMethodService { public View onCreateInputView() { Log.d(TAG, "onCreateInputView"); final ViewGroup view = new FrameLayout(this); - final View inner = new View(this); - final float density = getResources().getDisplayMetrics().density; - final int height = (int) (HEIGHT_DP * density); view.setPadding(0, 0, 0, 0); - view.addView(inner, new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, height)); LinearLayout layout = new LinearLayout(this); layout.setLayoutParams(new LinearLayout.LayoutParams( @@ -214,9 +215,9 @@ public class HandwritingIme extends InputMethodService { layout.setOrientation(LinearLayout.VERTICAL); layout.addView(getRichGestureActionsSpinner()); layout.addView(getRichGestureGranularitySpinner()); - + layout.addView(getBoundsInfoCheckBoxes()); + layout.setBackgroundColor(getColor(R.color.holo_green_light)); view.addView(layout); - inner.setBackgroundColor(getColor(R.color.holo_green_light)); return view; } @@ -228,7 +229,7 @@ public class HandwritingIme extends InputMethodService { mRichGestureModeSpinner = new Spinner(this); mRichGestureModeSpinner.setPadding(100, 0, 100, 0); mRichGestureModeSpinner.setTooltipText("Handwriting IME mode"); - String[] items = new String[] { + String[] items = new String[]{ "Handwriting IME - Rich gesture disabled", "Rich gesture SELECT", "Rich gesture DELETE", @@ -259,6 +260,69 @@ public class HandwritingIme extends InputMethodService { return mRichGestureModeSpinner; } + private void updateCursorAnchorInfo(int boundsInfoMode) { + final InputConnection ic = getCurrentInputConnection(); + if (ic == null) return; + + if (boundsInfoMode == BOUNDS_INFO_NONE) { + ic.requestCursorUpdates(0); + return; + } + + final int cursorUpdateMode = InputConnection.CURSOR_UPDATE_MONITOR; + int cursorUpdateFilter = 0; + if ((boundsInfoMode & BOUNDS_INFO_EDITOR_BOUNDS) != 0) { + cursorUpdateFilter |= InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS; + } + + if ((boundsInfoMode & BOUNDS_INFO_VISIBLE_LINE_BOUNDS) != 0) { + cursorUpdateFilter |= InputConnection.CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS; + } + ic.requestCursorUpdates(cursorUpdateMode | cursorUpdateFilter); + } + + private void updateBoundsInfoMode() { + if (mInk != null) { + mInk.setBoundsInfoMode(mBoundsInfoMode); + } + updateCursorAnchorInfo(mBoundsInfoMode); + } + + private View getBoundsInfoCheckBoxes() { + if (mBoundsInfoCheckBoxes != null) { + return mBoundsInfoCheckBoxes; + } + mBoundsInfoCheckBoxes = new LinearLayout(this); + mBoundsInfoCheckBoxes.setPadding(100, 0, 100, 0); + mBoundsInfoCheckBoxes.setOrientation(LinearLayout.HORIZONTAL); + + final CheckBox editorBoundsInfoCheckBox = new CheckBox(this); + editorBoundsInfoCheckBox.setText("EditorBoundsInfo"); + editorBoundsInfoCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + mBoundsInfoMode |= BOUNDS_INFO_EDITOR_BOUNDS; + } else { + mBoundsInfoMode &= ~BOUNDS_INFO_EDITOR_BOUNDS; + } + updateBoundsInfoMode(); + }); + + final CheckBox visibleLineBoundsInfoCheckBox = new CheckBox(this); + visibleLineBoundsInfoCheckBox.setText("VisibleLineBounds"); + visibleLineBoundsInfoCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + mBoundsInfoMode |= BOUNDS_INFO_VISIBLE_LINE_BOUNDS; + } else { + mBoundsInfoMode &= ~BOUNDS_INFO_VISIBLE_LINE_BOUNDS; + } + updateBoundsInfoMode(); + }); + + mBoundsInfoCheckBoxes.addView(editorBoundsInfoCheckBox); + mBoundsInfoCheckBoxes.addView(visibleLineBoundsInfoCheckBox); + return mBoundsInfoCheckBoxes; + } + private View getRichGestureGranularitySpinner() { if (mRichGestureGranularitySpinner != null) { return mRichGestureGranularitySpinner; @@ -294,6 +358,7 @@ public class HandwritingIme extends InputMethodService { Log.d(TAG, "onPrepareStylusHandwriting "); if (mInk == null) { mInk = new InkView(this, new HandwritingFinisherImpl(), new StylusConsumer()); + mInk.setBoundsInfoMode(mBoundsInfoMode); } } @@ -323,4 +388,16 @@ public class HandwritingIme extends InputMethodService { private boolean areRichGesturesEnabled() { return mRichGestureMode != OP_NONE; } + + @Override + public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) { + if (mInk != null) { + mInk.setCursorAnchorInfo(cursorAnchorInfo); + } + } + + @Override + public void onStartInput(EditorInfo attribute, boolean restarting) { + updateCursorAnchorInfo(mBoundsInfoMode); + } } diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java index e94c79ecca00..86b324cf08d9 100644 --- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java +++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java @@ -26,6 +26,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowMetrics; +import android.view.inputmethod.CursorAnchorInfo; class InkView extends View { private static final long FINISH_TIMEOUT = 1500; @@ -37,6 +38,9 @@ class InkView extends View { private static final float STYLUS_MOVE_TOLERANCE = 1; private Runnable mFinishRunnable; + private CursorAnchorInfo mCursorAnchorInfo; + private int mBoundsInfoMode; + InkView(Context context, HandwritingIme.HandwritingFinisher hwController, HandwritingIme.StylusConsumer consumer) { super(context); @@ -66,6 +70,7 @@ class InkView extends View { canvas.drawPath(mPath, mPaint); canvas.drawARGB(20, 255, 50, 50); + BoundsInfoDrawHelper.draw(canvas, this, mBoundsInfoMode, mCursorAnchorInfo); } private void stylusStart(float x, float y) { @@ -156,4 +161,15 @@ class InkView extends View { return mFinishRunnable; } + void setCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) { + mCursorAnchorInfo = cursorAnchorInfo; + invalidate(); + } + + void setBoundsInfoMode(int boundsInfoMode) { + if (boundsInfoMode != mBoundsInfoMode) { + invalidate(); + } + mBoundsInfoMode = boundsInfoMode; + } } diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp index a4c48fd5f342..4fa6fbe1d4e1 100644 --- a/tests/Input/Android.bp +++ b/tests/Input/Android.bp @@ -25,7 +25,7 @@ android_test { "services.core.unboosted", "testables", "truth-prebuilt", - "ub-uiautomator", + "androidx.test.uiautomator_uiautomator", ], test_suites: ["device-tests"], } diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt index 0246426c1d33..d185ee6ae116 100644 --- a/tests/Input/src/com/android/test/input/AnrTest.kt +++ b/tests/Input/src/com/android/test/input/AnrTest.kt @@ -27,14 +27,15 @@ import android.os.IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLI import android.os.SystemClock import android.provider.Settings import android.provider.Settings.Global.HIDE_ERROR_DIALOGS -import android.support.test.uiautomator.By -import android.support.test.uiautomator.UiDevice -import android.support.test.uiautomator.UiObject2 -import android.support.test.uiautomator.Until import android.testing.PollingCheck import android.view.InputDevice import android.view.MotionEvent +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiObject2 +import androidx.test.uiautomator.Until + import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue diff --git a/tests/OdmApps/Android.bp b/tests/OdmApps/Android.bp index 5f03aa27e6df..a5c6d6513f50 100644 --- a/tests/OdmApps/Android.bp +++ b/tests/OdmApps/Android.bp @@ -28,5 +28,6 @@ java_test_host { test_suites: ["device-tests"], data: [ ":TestOdmApp", + ":TestOdmPrivApp", ], } diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index f8d885ae3faf..d7fa124623ce 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -417,9 +417,9 @@ public class PackageWatchdogTest { int failureReason, int mitigationCount) { if (versionedPackage.getVersionCode() == VERSION_CODE) { // Only rollback for specific versionCode - return PackageHealthObserverImpact.USER_IMPACT_MEDIUM; + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_30; } - return PackageHealthObserverImpact.USER_IMPACT_NONE; + return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; } }; @@ -442,13 +442,13 @@ public class PackageWatchdogTest { public void testPackageFailureNotifyAllDifferentImpacts() throws Exception { PackageWatchdog watchdog = createWatchdog(); TestObserver observerNone = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_NONE); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_0); TestObserver observerHigh = new TestObserver(OBSERVER_NAME_2, - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); TestObserver observerMid = new TestObserver(OBSERVER_NAME_3, - PackageHealthObserverImpact.USER_IMPACT_MEDIUM); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); TestObserver observerLow = new TestObserver(OBSERVER_NAME_4, - PackageHealthObserverImpact.USER_IMPACT_LOW); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); // Start observing for all impact observers watchdog.startObservingHealth(observerNone, Arrays.asList(APP_A, APP_B, APP_C, APP_D), @@ -499,9 +499,9 @@ public class PackageWatchdogTest { public void testPackageFailureNotifyLeastImpactSuccessively() throws Exception { PackageWatchdog watchdog = createWatchdog(); TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_LOW); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); TestObserver observerSecond = new TestObserver(OBSERVER_NAME_2, - PackageHealthObserverImpact.USER_IMPACT_MEDIUM); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); // Start observing for observerFirst and observerSecond with failure handling watchdog.startObservingHealth(observerFirst, Arrays.asList(APP_A), LONG_DURATION); @@ -517,7 +517,7 @@ public class PackageWatchdogTest { assertThat(observerSecond.mMitigatedPackages).isEmpty(); // After observerFirst handles failure, next action it has is high impact - observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_HIGH; + observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_100; observerFirst.mMitigatedPackages.clear(); observerSecond.mMitigatedPackages.clear(); @@ -531,7 +531,7 @@ public class PackageWatchdogTest { assertThat(observerFirst.mMitigatedPackages).isEmpty(); // After observerSecond handles failure, it has no further actions - observerSecond.mImpact = PackageHealthObserverImpact.USER_IMPACT_NONE; + observerSecond.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; observerFirst.mMitigatedPackages.clear(); observerSecond.mMitigatedPackages.clear(); @@ -545,7 +545,7 @@ public class PackageWatchdogTest { assertThat(observerSecond.mMitigatedPackages).isEmpty(); // After observerFirst handles failure, it too has no further actions - observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_NONE; + observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; observerFirst.mMitigatedPackages.clear(); observerSecond.mMitigatedPackages.clear(); @@ -566,9 +566,9 @@ public class PackageWatchdogTest { public void testPackageFailureNotifyOneSameImpact() throws Exception { PackageWatchdog watchdog = createWatchdog(); TestObserver observer1 = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2, - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); // Start observing for observer1 and observer2 with failure handling watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION); @@ -592,11 +592,11 @@ public class PackageWatchdogTest { TestController controller = new TestController(); PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */); TestObserver observer1 = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2, - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); TestObserver observer3 = new TestObserver(OBSERVER_NAME_3, - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); // Start observing with explicit health checks for APP_A and APP_B respectively @@ -645,7 +645,7 @@ public class PackageWatchdogTest { TestController controller = new TestController(); PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */); TestObserver observer = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_MEDIUM); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); // Start observing with explicit health checks for APP_A and APP_B controller.setSupportedPackages(Arrays.asList(APP_A, APP_B, APP_C)); @@ -711,7 +711,7 @@ public class PackageWatchdogTest { TestController controller = new TestController(); PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */); TestObserver observer = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_MEDIUM); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); // Start observing with explicit health checks for APP_A and // package observation duration == LONG_DURATION @@ -742,7 +742,7 @@ public class PackageWatchdogTest { TestController controller = new TestController(); PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */); TestObserver observer = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_MEDIUM); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); // Start observing with explicit health checks for APP_A and // package observation duration == SHORT_DURATION / 2 @@ -818,7 +818,7 @@ public class PackageWatchdogTest { // Start observing with failure handling TestObserver observer = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_HIGH); + PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); wd.startObservingHealth(observer, Collections.singletonList(APP_A), SHORT_DURATION); // Notify of NetworkStack failure @@ -1073,9 +1073,9 @@ public class PackageWatchdogTest { public void testBootLoopMitigationDoneForLowestUserImpact() { PackageWatchdog watchdog = createWatchdog(); TestObserver bootObserver1 = new TestObserver(OBSERVER_NAME_1); - bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LOW); + bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); TestObserver bootObserver2 = new TestObserver(OBSERVER_NAME_2); - bootObserver2.setImpact(PackageHealthObserverImpact.USER_IMPACT_MEDIUM); + bootObserver2.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); watchdog.registerHealthObserver(bootObserver1); watchdog.registerHealthObserver(bootObserver2); for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { @@ -1446,7 +1446,7 @@ public class PackageWatchdogTest { TestObserver(String name) { mName = name; - mImpact = PackageHealthObserverImpact.USER_IMPACT_MEDIUM; + mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30; } TestObserver(String name, int impact) { diff --git a/tests/SilkFX/res/drawable-nodpi/dark_gradient.xml b/tests/SilkFX/res/drawable-nodpi/dark_gradient.xml index d2653d0de0d4..f20dd424c617 100644 --- a/tests/SilkFX/res/drawable-nodpi/dark_gradient.xml +++ b/tests/SilkFX/res/drawable-nodpi/dark_gradient.xml @@ -18,6 +18,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#000000" - android:endColor="#181818" + android:endColor="#222222" android:angle="0"/> </shape>
\ No newline at end of file diff --git a/tests/WindowAnimationJank/Android.bp b/tests/WindowAnimationJank/Android.bp index ed86aa5f90ea..8542f885d645 100644 --- a/tests/WindowAnimationJank/Android.bp +++ b/tests/WindowAnimationJank/Android.bp @@ -25,7 +25,7 @@ android_test { name: "WindowAnimationJank", srcs: ["src/**/*.java"], static_libs: [ - "ub-uiautomator", + "androidx.test.uiautomator_uiautomator", "androidx.test.janktesthelper", "junit", ], diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java b/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java index 25314644ca7e..48a359c4d0c6 100644 --- a/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java @@ -18,11 +18,12 @@ import android.app.UiAutomation; import android.content.ComponentName; import android.content.Intent; import android.os.SystemClock; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.BySelector; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject2; -import android.support.test.uiautomator.Until; + +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.Until; /** * Set of helpers to manipulate test activities. diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java index a8ace162c4d0..cb7c5112cba7 100644 --- a/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java @@ -16,9 +16,8 @@ package android.windowanimationjank; -import android.support.test.uiautomator.UiDevice; - import androidx.test.jank.JankTestBase; +import androidx.test.uiautomator.UiDevice; /** * This adds additional system level jank monitor and its result is merged with primary monitor diff --git a/tests/testables/src/android/testing/TestWithLooperRule.java b/tests/testables/src/android/testing/TestWithLooperRule.java new file mode 100644 index 000000000000..99b303e0c43a --- /dev/null +++ b/tests/testables/src/android/testing/TestWithLooperRule.java @@ -0,0 +1,161 @@ +/* + * 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.testing; + +import android.testing.TestableLooper.LooperFrameworkMethod; +import android.testing.TestableLooper.RunWithLooper; + +import org.junit.internal.runners.statements.InvokeMethod; +import org.junit.rules.MethodRule; +import org.junit.runner.RunWith; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/* + * This rule is meant to be an alternative of using AndroidTestingRunner. + * It let tests to start from background thread, and assigns mainLooper or new + * Looper for the Statement. + */ +public class TestWithLooperRule implements MethodRule { + + /* + * This rule requires to be the inner most Rule, so the next statement is RunAfters + * instead of another rule. You can set it by '@Rule(order = Integer.MAX_VALUE)' + */ + @Override + public Statement apply(Statement base, FrameworkMethod method, Object target) { + // getting testRunner check, if AndroidTestingRunning then we skip this rule + RunWith runWithAnnotation = target.getClass().getAnnotation(RunWith.class); + if (runWithAnnotation != null) { + // if AndroidTestingRunner or it's subclass is in use, do nothing + if (AndroidTestingRunner.class.isAssignableFrom(runWithAnnotation.value())) { + return base; + } + } + + // check if RunWithLooper annotation is used. If not skip this rule + RunWithLooper looperAnnotation = method.getAnnotation(RunWithLooper.class); + if (looperAnnotation == null) { + looperAnnotation = target.getClass().getAnnotation(RunWithLooper.class); + } + if (looperAnnotation == null) { + return base; + } + + try { + wrapMethodInStatement(base, method, target); + } catch (Exception e) { + throw new RuntimeException(e); + } + return base; + } + + // This method is based on JUnit4 test runner flow. It might need to be revisited when JUnit is + // upgraded + // TODO(b/277743626): use a cleaner way to wrap each statements; may require some JUnit + // patching to facilitate this. + private void wrapMethodInStatement(Statement base, FrameworkMethod method, Object target) + throws Exception { + Statement next = base; + try { + while (next != null) { + switch (next.getClass().getSimpleName()) { + case "RunAfters": + this.<List<FrameworkMethod>>wrapFieldMethodFor(next, + next.getClass(), "afters", method, target); + next = getNextStatement(next, "next"); + break; + case "RunBefores": + this.<List<FrameworkMethod>>wrapFieldMethodFor(next, + next.getClass(), "befores", method, target); + next = getNextStatement(next, "next"); + break; + case "FailOnTimeout": + // Note: withPotentialTimeout() from BlockJUnit4ClassRunner might use + // FailOnTimeout which always wraps a new thread during InvokeMethod + // method evaluation. + next = getNextStatement(next, "originalStatement"); + break; + case "InvokeMethod": + this.<FrameworkMethod>wrapFieldMethodFor(next, + InvokeMethod.class, "testMethod", method, target); + return; + default: + throw new Exception( + String.format("Unexpected Statement received: [%s]", + next.getClass().getName()) + ); + } + } + } catch (Exception e) { + throw e; + } + } + + // Wrapping the befores, afters, and InvokeMethods with LooperFrameworkMethod + // within the statement. + private <T> void wrapFieldMethodFor(Statement base, Class<?> targetClass, String fieldStr, + FrameworkMethod method, Object target) + throws NoSuchFieldException, IllegalAccessException { + Field field = targetClass.getDeclaredField(fieldStr); + field.setAccessible(true); + T fieldInstance = (T) field.get(base); + if (fieldInstance instanceof FrameworkMethod) { + field.set(base, looperWrap(method, target, (FrameworkMethod) fieldInstance)); + } else { + // Befores and afters methods lists + field.set(base, looperWrap(method, target, (List<FrameworkMethod>) fieldInstance)); + } + } + + // Retrieve the next wrapped statement based on the selected field string + private Statement getNextStatement(Statement base, String fieldStr) + throws NoSuchFieldException, IllegalAccessException { + Field nextField = base.getClass().getDeclaredField(fieldStr); + nextField.setAccessible(true); + Object value = nextField.get(base); + return value instanceof Statement ? (Statement) value : null; + } + + protected FrameworkMethod looperWrap(FrameworkMethod method, Object test, + FrameworkMethod base) { + RunWithLooper annotation = method.getAnnotation(RunWithLooper.class); + if (annotation == null) annotation = test.getClass().getAnnotation(RunWithLooper.class); + if (annotation != null) { + return LooperFrameworkMethod.get(base, annotation.setAsMainLooper(), test); + } + return base; + } + + protected List<FrameworkMethod> looperWrap(FrameworkMethod method, Object test, + List<FrameworkMethod> methods) { + RunWithLooper annotation = method.getAnnotation(RunWithLooper.class); + if (annotation == null) annotation = test.getClass().getAnnotation(RunWithLooper.class); + if (annotation != null) { + methods = new ArrayList<>(methods); + for (int i = 0; i < methods.size(); i++) { + methods.set(i, LooperFrameworkMethod.get(methods.get(i), + annotation.setAsMainLooper(), test)); + } + } + return methods; + } +} diff --git a/tests/testables/src/android/testing/TestableResources.java b/tests/testables/src/android/testing/TestableResources.java index c60f07d56d92..27d5b66b355e 100644 --- a/tests/testables/src/android/testing/TestableResources.java +++ b/tests/testables/src/android/testing/TestableResources.java @@ -59,7 +59,8 @@ public class TestableResources { * Since resource ids are unique there is a single addOverride that will override the value * whenever it is gotten regardless of which method is used (i.e. getColor or getDrawable). * </p> - * @param id The resource id to be overridden + * + * @param id The resource id to be overridden * @param value The value of the resource, null to cause a {@link Resources.NotFoundException} * when gotten. */ @@ -74,28 +75,33 @@ public class TestableResources { * cause a {@link Resources.NotFoundException} whereas removing the override will actually * switch back to returning the default/real value of the resource. * </p> - * @param id */ public void removeOverride(int id) { mOverrides.remove(id); } private Object answer(InvocationOnMock invocationOnMock) throws Throwable { - try { - int id = invocationOnMock.getArgument(0); - int index = mOverrides.indexOfKey(id); - if (index >= 0) { - Object value = mOverrides.valueAt(index); - if (value == null) throw new Resources.NotFoundException(); - return value; + // Only try to override methods with an integer first argument + if (invocationOnMock.getArguments().length > 0) { + Object argument = invocationOnMock.getArgument(0); + if (argument instanceof Integer) { + try { + int id = (Integer)argument; + int index = mOverrides.indexOfKey(id); + if (index >= 0) { + Object value = mOverrides.valueAt(index); + if (value == null) throw new Resources.NotFoundException(); + return value; + } + } catch (Resources.NotFoundException e) { + // Let through NotFoundException. + throw e; + } catch (Throwable t) { + // Generic catching for the many things that can go wrong, fall back to + // the real implementation. + Log.i(TAG, "Falling back to default resources call " + t); + } } - } catch (Resources.NotFoundException e) { - // Let through NotFoundException. - throw e; - } catch (Throwable t) { - // Generic catching for the many things that can go wrong, fall back to - // the real implementation. - Log.i(TAG, "Falling back to default resources call " + t); } return invocationOnMock.callRealMethod(); } diff --git a/tests/testables/src/android/testing/TestableSettingsProvider.java b/tests/testables/src/android/testing/TestableSettingsProvider.java index c6f18fd453c5..b850cb8e6dfd 100644 --- a/tests/testables/src/android/testing/TestableSettingsProvider.java +++ b/tests/testables/src/android/testing/TestableSettingsProvider.java @@ -72,7 +72,11 @@ public class TestableSettingsProvider extends MockContentProvider { public Bundle call(String method, String arg, Bundle extras) { // Methods are "GET_system", "GET_global", "PUT_secure", etc. - final int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, UserHandle.myUserId()); + int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, UserHandle.USER_CURRENT); + if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) { + userId = UserHandle.myUserId(); + } + final String[] commands = method.split("_", 2); final String op = commands[0]; final String table = commands[1]; diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h index a146466402f6..e2c161482857 100644 --- a/tools/aapt/SdkConstants.h +++ b/tools/aapt/SdkConstants.h @@ -49,6 +49,7 @@ enum { SDK_S = 31, SDK_S_V2 = 32, SDK_TIRAMISU = 33, + SDK_UPSIDE_DOWN_CAKE = 34, SDK_CUR_DEVELOPMENT = 10000, }; diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h index 40bcef787815..e47704ea2725 100644 --- a/tools/aapt2/SdkConstants.h +++ b/tools/aapt2/SdkConstants.h @@ -59,6 +59,7 @@ enum : ApiVersion { SDK_S = 31, SDK_S_V2 = 32, SDK_TIRAMISU = 33, + SDK_UPSIDE_DOWN_CAKE = 34, SDK_CUR_DEVELOPMENT = 10000, }; diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java index 25fbabce71ae..166fbddc2f56 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java @@ -163,11 +163,11 @@ public final class NetworkProviderInfo implements Parcelable { /** * Sets the displayed connection strength of the remote device to the internet. * - * @param connectionStrength Connection strength in range 0 to 3. + * @param connectionStrength Connection strength in range 0 to 4. * @return Returns the Builder object. */ @NonNull - public Builder setConnectionStrength(@IntRange(from = 0, to = 3) int connectionStrength) { + public Builder setConnectionStrength(@IntRange(from = 0, to = 4) int connectionStrength) { mConnectionStrength = connectionStrength; return this; } @@ -205,8 +205,8 @@ public final class NetworkProviderInfo implements Parcelable { if (batteryPercentage < 0 || batteryPercentage > 100) { throw new IllegalArgumentException("BatteryPercentage must be in range 0-100"); } - if (connectionStrength < 0 || connectionStrength > 3) { - throw new IllegalArgumentException("ConnectionStrength must be in range 0-3"); + if (connectionStrength < 0 || connectionStrength > 4) { + throw new IllegalArgumentException("ConnectionStrength must be in range 0-4"); } } @@ -265,9 +265,9 @@ public final class NetworkProviderInfo implements Parcelable { /** * Gets the displayed connection strength of the remote device to the internet. * - * @return Returns the connection strength in range 0 to 3. + * @return Returns the connection strength in range 0 to 4. */ - @IntRange(from = 0, to = 3) + @IntRange(from = 0, to = 4) public int getConnectionStrength() { return mConnectionStrength; } 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 e5ef62b16dfd..feef0497c152 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java @@ -35,6 +35,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.IInterface; import android.os.RemoteException; +import android.text.TextUtils; import android.util.Log; import com.android.internal.R; @@ -173,10 +174,15 @@ public class SharedConnectivityManager { R.string.config_sharedConnectivityServicePackage); String serviceIntentAction = resources.getString( R.string.config_sharedConnectivityServiceIntentAction); + if (TextUtils.isEmpty(servicePackageName) || TextUtils.isEmpty(serviceIntentAction)) { + Log.e(TAG, "To support shared connectivity service on this device, the" + + " service's package name and intent action strings must not be empty"); + return null; + } return new SharedConnectivityManager(context, servicePackageName, serviceIntentAction); } catch (Resources.NotFoundException e) { Log.e(TAG, "To support shared connectivity service on this device, the service's" - + " package name and intent action string must be defined"); + + " package name and intent action strings must be defined"); } return null; } 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 b585bd5cfd7b..a03a6c2fc673 100644 --- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java +++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java @@ -105,6 +105,13 @@ public class SharedConnectivityManagerTest { } @Test + public void resourceStringsAreEmpty_createShouldReturnNull() { + when(mResources.getString(anyInt())).thenReturn(""); + + assertThat(SharedConnectivityManager.create(mContext)).isNull(); + } + + @Test public void bindingToServiceOnFirstCallbackRegistration() { SharedConnectivityManager manager = SharedConnectivityManager.create(mContext); manager.registerCallback(mExecutor, mClientCallback); |