diff options
923 files changed, 19802 insertions, 9442 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index c231b30503fa..c477a75d68ec 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -249,6 +249,14 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +java_aconfig_library { + name: "android.app.usage.flags-aconfig-java-host", + aconfig_declarations: "android.app.usage.flags-aconfig", + host_supported: true, + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + + // OS aconfig_declarations { name: "android.os.flags-aconfig", diff --git a/Android.bp b/Android.bp index 13b170353dd6..f6a9328d2501 100644 --- a/Android.bp +++ b/Android.bp @@ -220,6 +220,7 @@ java_library { "updatable-driver-protos", "ota_metadata_proto_java", "android.hidl.base-V1.0-java", + "android.hidl.manager-V1.2-java", "android.hardware.cas-V1-java", // AIDL "android.hardware.cas-V1.0-java", "android.hardware.cas-V1.1-java", diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig index c65e50640ee9..de6f0235cd83 100644 --- a/apex/jobscheduler/service/aconfig/job.aconfig +++ b/apex/jobscheduler/service/aconfig/job.aconfig @@ -12,4 +12,11 @@ flag { namespace: "backstage_power" description: "Throw an exception if an unsupported app uses JobInfo.setBias" bug: "300477393" -}
\ No newline at end of file +} + +flag { + name: "batch_jobs_on_network_activation" + namespace: "backstage_power" + description: "Have JobScheduler attempt to delay the start of some connectivity jobs until the network is actually active" + bug: "318394184" +} diff --git a/core/api/current.txt b/core/api/current.txt index 537f615f1f36..5abb92b1c2e4 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -4369,7 +4369,7 @@ package android.app { method public final android.media.session.MediaController getMediaController(); method @NonNull public android.view.MenuInflater getMenuInflater(); method @NonNull public android.window.OnBackInvokedDispatcher getOnBackInvokedDispatcher(); - method public final android.app.Activity getParent(); + method @Deprecated public final android.app.Activity getParent(); method @Nullable public android.content.Intent getParentActivityIntent(); method public android.content.SharedPreferences getPreferences(int); method @Nullable public android.net.Uri getReferrer(); @@ -4387,7 +4387,7 @@ package android.app { method public void invalidateOptionsMenu(); method public boolean isActivityTransitionRunning(); method public boolean isChangingConfigurations(); - method public final boolean isChild(); + method @Deprecated public final boolean isChild(); method public boolean isDestroyed(); method public boolean isFinishing(); method public boolean isImmersive(); @@ -12368,6 +12368,7 @@ package android.content.pm { public final class ModuleInfo implements android.os.Parcelable { method public int describeContents(); + method @FlaggedApi("android.content.pm.provide_info_of_apk_in_apex") @NonNull public java.util.Collection<java.lang.String> getApkInApexPackageNames(); method @Nullable public CharSequence getName(); method @Nullable public String getPackageName(); method public boolean isHidden(); @@ -12378,6 +12379,7 @@ package android.content.pm { public class PackageInfo implements android.os.Parcelable { ctor public PackageInfo(); method public int describeContents(); + method @FlaggedApi("android.content.pm.provide_info_of_apk_in_apex") @Nullable public String getApexPackageName(); method @FlaggedApi("android.content.pm.archiving") public long getArchiveTimeMillis(); method public long getLongVersionCode(); method public void setLongVersionCode(long); @@ -33391,6 +33393,7 @@ package android.os { public class Process { ctor public Process(); + method public static final int getAppUidForSdkSandboxUid(int); method public static final long getElapsedCpuTime(); method public static final int[] getExclusiveCores(); method public static final int getGidForName(String); @@ -33405,6 +33408,7 @@ package android.os { method public static final boolean isIsolated(); method public static final boolean isIsolatedUid(int); method public static final boolean isSdkSandbox(); + method public static final boolean isSdkSandboxUid(int); method public static final void killProcess(int); method public static final int myPid(); method @NonNull public static String myProcessName(); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index de330de19560..c1b9f64b9e8a 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -395,8 +395,6 @@ package android.os { } public class Process { - method public static final int getAppUidForSdkSandboxUid(int); - method public static final boolean isSdkSandboxUid(int); method public static final int toSdkSandboxUid(int); field public static final int NFC_UID = 1027; // 0x403 field public static final int VPN_UID = 1016; // 0x3f8 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index c7220b116230..572be192fb3e 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2344,9 +2344,7 @@ package android.os { } public class Process { - method public static final int getAppUidForSdkSandboxUid(int); method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException; - method public static final boolean isSdkSandboxUid(int); method public static final int toSdkSandboxUid(int); field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90 field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8 diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java index 45515ddb219a..c1c5c0e6e019 100644 --- a/core/java/android/accounts/AbstractAccountAuthenticator.java +++ b/core/java/android/accounts/AbstractAccountAuthenticator.java @@ -142,10 +142,7 @@ public abstract class AbstractAccountAuthenticator { private static final String KEY_ACCOUNT = "android.accounts.AbstractAccountAuthenticator.KEY_ACCOUNT"; - private final Context mContext; - public AbstractAccountAuthenticator(Context context) { - mContext = context; } private class Transport extends IAccountAuthenticator.Stub { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 5674a108baaa..5d4d5e23d6db 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1174,12 +1174,23 @@ public class Activity extends ContextThemeWrapper return mApplication; } - /** Is this activity embedded inside of another activity? */ + /** + * Whether this is a child {@link Activity} of an {@link ActivityGroup}. + * + * @deprecated {@link ActivityGroup} is deprecated. + */ + @Deprecated public final boolean isChild() { return mParent != null; } - /** Return the parent activity if this view is an embedded child. */ + /** + * Returns the parent {@link Activity} if this is a child {@link Activity} of an + * {@link ActivityGroup}. + * + * @deprecated {@link ActivityGroup} is deprecated. + */ + @Deprecated public final Activity getParent() { return mParent; } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 37692d363a4b..232fc926a802 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -1164,6 +1164,30 @@ public abstract class ActivityManagerInternal { */ public abstract void logFgsApiEnd(int apiType, int uid, int pid); + /** + * Checks whether an app will be able to start a foreground service or not. + * + * @param pid The process id belonging to the app to be checked. + * @param uid The UID of the app to be checked. + * @param packageName The package name of the app to be checked. + * @return whether the app will be able to start a foreground service or not. + */ + public abstract boolean canStartForegroundService( + int pid, int uid, @NonNull String packageName); + + /** + * Returns {@code true} if a foreground service started by an uid is allowed to have + * while-in-use permissions. + * + * @param pid The process id belonging to the app to be checked. + * @param uid The UID of the app to be checked. + * @param packageName The package name of the app to be checked. + * @return whether the foreground service is allowed to have while-in-use permissions. + * @hide + */ + public abstract boolean canAllowWhileInUsePermissionInFgs( + int pid, int uid, @NonNull String packageName); + /** * Temporarily allow foreground service started by an uid to have while-in-use permission * for durationMs. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6df0f6b2ac8b..7e5326e64398 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -208,9 +208,11 @@ import android.view.contentcapture.IContentCaptureOptionsCallback; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; import android.webkit.WebView; +import android.window.ITaskFragmentOrganizer; import android.window.SizeConfigurationBuckets; import android.window.SplashScreen; import android.window.SplashScreenView; +import android.window.TaskFragmentTransaction; import android.window.WindowContextInfo; import android.window.WindowProviderService; import android.window.WindowTokenClientController; @@ -2047,6 +2049,14 @@ public final class ActivityThread extends ClientTransactionHandler } @Override + public void scheduleTaskFragmentTransaction(@NonNull ITaskFragmentOrganizer organizer, + @NonNull TaskFragmentTransaction transaction) throws RemoteException { + // TODO(b/260873529): ITaskFragmentOrganizer can be cleanup to be a IBinder token + // after flag removal. + organizer.onTransactionReady(transaction); + } + + @Override public void requestDirectActions(@NonNull IBinder activityToken, @NonNull IVoiceInteractor interactor, @Nullable RemoteCallback cancellationCallback, @NonNull RemoteCallback callback) { diff --git a/core/java/android/app/AppCompatTaskInfo.java b/core/java/android/app/AppCompatTaskInfo.java index a998ff215304..0bae5e67b87b 100644 --- a/core/java/android/app/AppCompatTaskInfo.java +++ b/core/java/android/app/AppCompatTaskInfo.java @@ -97,6 +97,11 @@ public class AppCompatTaskInfo implements Parcelable { public boolean isUserFullscreenOverrideEnabled; /** + * Whether the system has forced the activity to be fullscreen + */ + public boolean isSystemFullscreenOverrideEnabled; + + /** * Hint about the letterbox state of the top activity. */ public boolean topActivityBoundsLetterboxed; @@ -202,7 +207,8 @@ public class AppCompatTaskInfo implements Parcelable { && topActivityLetterboxHeight == that.topActivityLetterboxHeight && topActivityLetterboxHorizontalPosition == that.topActivityLetterboxHorizontalPosition - && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled; + && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled + && isSystemFullscreenOverrideEnabled == that.isSystemFullscreenOverrideEnabled; } /** @@ -224,7 +230,8 @@ public class AppCompatTaskInfo implements Parcelable { && topActivityLetterboxWidth == that.topActivityLetterboxWidth && topActivityLetterboxHeight == that.topActivityLetterboxHeight && cameraCompatControlState == that.cameraCompatControlState - && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled; + && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled + && isSystemFullscreenOverrideEnabled == that.isSystemFullscreenOverrideEnabled; } /** @@ -243,6 +250,7 @@ public class AppCompatTaskInfo implements Parcelable { topActivityLetterboxWidth = source.readInt(); topActivityLetterboxHeight = source.readInt(); isUserFullscreenOverrideEnabled = source.readBoolean(); + isSystemFullscreenOverrideEnabled = source.readBoolean(); } /** @@ -262,6 +270,7 @@ public class AppCompatTaskInfo implements Parcelable { dest.writeInt(topActivityLetterboxWidth); dest.writeInt(topActivityLetterboxHeight); dest.writeBoolean(isUserFullscreenOverrideEnabled); + dest.writeBoolean(isSystemFullscreenOverrideEnabled); } @Override @@ -280,6 +289,7 @@ public class AppCompatTaskInfo implements Parcelable { + " topActivityLetterboxWidth=" + topActivityLetterboxWidth + " topActivityLetterboxHeight=" + topActivityLetterboxHeight + " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled + + " isSystemFullscreenOverrideEnabled=" + isSystemFullscreenOverrideEnabled + " cameraCompatControlState=" + cameraCompatControlStateToString(cameraCompatControlState) + "}"; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 4b24b1f2b2a1..1db1caf51800 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -71,6 +71,7 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Log; import android.util.LongSparseArray; import android.util.LongSparseLongArray; import android.util.Pools; @@ -7705,6 +7706,14 @@ public class AppOpsManager { @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) public void setUidMode(int code, int uid, @Mode int mode) { try { + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (code == OP_BLUETOOTH_CONNECT) { + Log.i(DEBUG_LOGGING_TAG, + "setUidMode called for OP_BLUETOOTH_CONNECT with mode: " + mode + + " for uid: " + uid + " calling uid: " + Binder.getCallingUid() + + " trace: " + + Arrays.toString(Thread.currentThread().getStackTrace())); + } mService.setUidMode(code, uid, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -7725,6 +7734,15 @@ public class AppOpsManager { @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) public void setUidMode(@NonNull String appOp, int uid, @Mode int mode) { try { + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (appOp.equals(OPSTR_BLUETOOTH_CONNECT)) { + Log.i(DEBUG_LOGGING_TAG, + "setUidMode called for OPSTR_BLUETOOTH_CONNECT with mode: " + mode + + " for uid: " + uid + " calling uid: " + Binder.getCallingUid() + + " trace: " + + Arrays.toString(Thread.currentThread().getStackTrace())); + } + mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -7765,6 +7783,14 @@ public class AppOpsManager { @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) public void setMode(int code, int uid, String packageName, @Mode int mode) { try { + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (code == OP_BLUETOOTH_CONNECT) { + Log.i(DEBUG_LOGGING_TAG, + "setMode called for OPSTR_BLUETOOTH_CONNECT with mode: " + mode + + " for uid: " + uid + " calling uid: " + Binder.getCallingUid() + + " trace: " + + Arrays.toString(Thread.currentThread().getStackTrace())); + } mService.setMode(code, uid, packageName, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -7787,6 +7813,14 @@ public class AppOpsManager { public void setMode(@NonNull String op, int uid, @Nullable String packageName, @Mode int mode) { try { + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (op.equals(OPSTR_BLUETOOTH_CONNECT)) { + Log.i(DEBUG_LOGGING_TAG, + "setMode called for OPSTR_BLUETOOTH_CONNECT with mode: " + mode + + " for uid: " + uid + " calling uid: " + Binder.getCallingUid() + + " trace: " + + Arrays.toString(Thread.currentThread().getStackTrace())); + } mService.setMode(strOpToOp(op), uid, packageName, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java index 343348b89625..f9ab55e00dc6 100644 --- a/core/java/android/app/AutomaticZenRule.java +++ b/core/java/android/app/AutomaticZenRule.java @@ -70,6 +70,8 @@ public final class AutomaticZenRule implements Parcelable { public static final int TYPE_SCHEDULE_CALENDAR = 2; /** * The type for rules triggered by bedtime/sleeping, like time of day, or snore detection. + * + * <p>Only the 'Wellbeing' app may own rules of this type. */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int TYPE_BEDTIME = 3; @@ -95,6 +97,8 @@ public final class AutomaticZenRule implements Parcelable { /** * The type for rules created and managed by a device owner. These rules may not be fully * editable by the device user. + * + * <p>Only a 'Device Owner' app may own rules of this type. */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int TYPE_MANAGED = 7; diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 5541e7aef160..a301c18bd374 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -48,6 +48,8 @@ import android.os.SharedMemory; import android.view.autofill.AutofillId; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; +import android.window.ITaskFragmentOrganizer; +import android.window.TaskFragmentTransaction; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; @@ -157,6 +159,8 @@ oneway interface IApplicationThread { void scheduleApplicationInfoChanged(in ApplicationInfo ai); void setNetworkBlockSeq(long procStateSeq); void scheduleTransaction(in ClientTransaction transaction); + void scheduleTaskFragmentTransaction(in ITaskFragmentOrganizer organizer, + in TaskFragmentTransaction transaction); void requestDirectActions(IBinder activityToken, IVoiceInteractor intractor, in RemoteCallback cancellationCallback, in RemoteCallback callback); void performDirectAction(IBinder activityToken, String actionId, diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 385fd509757b..14195c473c6d 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -241,6 +241,23 @@ public class StatusBarManager { public static final int CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE = 3; /** + * Broadcast action: sent to apps that hold the status bar permission when + * KeyguardManager#setPrivateNotificationsAllowed() is changed. + * + * Extras: #EXTRA_KM_PRIVATE_NOTIFS_ALLOWED + * @hide + */ + public static final String ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED + = "android.app.action.KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED"; + + /** + * Boolean, the latest value of KeyguardManager#getPrivateNotificationsAllowed() + * @hide + */ + public static final String EXTRA_KM_PRIVATE_NOTIFS_ALLOWED + = "android.app.extra.KM_PRIVATE_NOTIFS_ALLOWED"; + + /** * Session flag for {@link #registerSessionListener} indicating the listener * is interested in sessions on the keygaurd. * Keyguard Session Boundaries: diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 4a6349b1b02f..5c42b0ed975a 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2598,8 +2598,8 @@ public class DevicePolicyManager { * There can be at most one app that has this delegation. * If another app already had delegated certificate selection access, * it will lose the delegation when a new app is delegated. - * <p> The delegaetd app can also call {@link #grantKeyPairToApp} and - * {@link #revokeKeyPairFromApp} to directly grant KeyCain keys to other apps. + * <p> The delegated app can also call {@link #grantKeyPairToApp} and + * {@link #revokeKeyPairFromApp} to directly grant KeyChain keys to other apps. * <p> Can be granted by Device Owner or Profile Owner. */ public static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection"; diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index fb0edb954539..d11c6c50da3b 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -36,3 +36,10 @@ flag { description: "Guards the security fix that ensures all URIs in intents and Person.java are valid" bug: "281044385" } + +flag { + name: "keyguard_private_notifications" + namespace: "systemui" + description: "Fixes the behavior of KeyguardManager#setPrivateNotificationsAllowed()" + bug: "309920145" +} diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java index 3ce094ef7467..cbb0ae784f82 100644 --- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java +++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ResultInfo; +import android.content.Context; import android.content.res.CompatibilityInfo; import android.os.IBinder; import android.os.Parcel; @@ -85,6 +86,12 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { client.reportRelaunch(r); } + @Nullable + @Override + public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { + return client.getActivity(getActivityToken()); + } + // ObjectPoolItem implementation private ActivityRelaunchItem() {} diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index d2ef65aec698..1190bf6a604b 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -24,12 +24,14 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityClient; import android.app.ActivityOptions; +import android.app.ActivityThread; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.IActivityClientController; import android.app.ProfilerInfo; import android.app.ResultInfo; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo; @@ -115,6 +117,13 @@ public class LaunchActivityItem extends ClientTransactionItem { client.countLaunchingActivities(-1); } + @Nullable + @Override + public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { + // LaunchActivityItem may update the global config with #mCurConfig. + return ActivityThread.currentApplication(); + } + // ObjectPoolItem implementation private LaunchActivityItem() {} diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java index 961da19daeed..1353d1679427 100644 --- a/core/java/android/app/servertransaction/MoveToDisplayItem.java +++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; +import android.content.Context; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.os.IBinder; @@ -55,6 +56,12 @@ public class MoveToDisplayItem extends ActivityTransactionItem { Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } + @Nullable + @Override + public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { + return client.getActivity(getActivityToken()); + } + // ObjectPoolItem implementation private MoveToDisplayItem() {} diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index ee48e431ba8e..2e47feeef068 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -41,6 +41,8 @@ import android.content.Context; import android.content.res.Configuration; import android.os.IBinder; import android.os.Process; +import android.os.Trace; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; @@ -62,8 +64,11 @@ public class TransactionExecutor { private final PendingTransactionActions mPendingActions = new PendingTransactionActions(); private final TransactionExecutorHelper mHelper = new TransactionExecutorHelper(); - /** Keeps track of display ids whose Configuration got updated within a transaction. */ - private final ArraySet<Integer> mConfigUpdatedDisplayIds = new ArraySet<>(); + /** + * Keeps track of the Context whose Configuration got updated within a transaction, mapping to + * the config before the transaction. + */ + private final ArrayMap<Context, Configuration> mContextToPreChangedConfigMap = new ArrayMap<>(); /** Initialize an instance with transaction handler, that will execute all requested actions. */ public TransactionExecutor(@NonNull ClientTransactionHandler clientTransactionHandler) { @@ -83,24 +88,48 @@ public class TransactionExecutor { Slog.d(TAG, transactionToString(transaction, mTransactionHandler)); } - if (transaction.getTransactionItems() != null) { - executeTransactionItems(transaction); - } else { - // TODO(b/260873529): cleanup after launch. - executeCallbacks(transaction); - executeLifecycleState(transaction); + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "clientTransactionExecuted"); + try { + if (transaction.getTransactionItems() != null) { + executeTransactionItems(transaction); + } else { + // TODO(b/260873529): cleanup after launch. + executeCallbacks(transaction); + executeLifecycleState(transaction); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } - if (!mConfigUpdatedDisplayIds.isEmpty()) { + if (!mContextToPreChangedConfigMap.isEmpty()) { // Whether this transaction should trigger DisplayListener#onDisplayChanged. - final ClientTransactionListenerController controller = - ClientTransactionListenerController.getInstance(); - final int displayCount = mConfigUpdatedDisplayIds.size(); - for (int i = 0; i < displayCount; i++) { - final int displayId = mConfigUpdatedDisplayIds.valueAt(i); - controller.onDisplayChanged(displayId); + try { + // Calculate display ids that have config changed. + final ArraySet<Integer> configUpdatedDisplayIds = new ArraySet<>(); + final int contextCount = mContextToPreChangedConfigMap.size(); + for (int i = 0; i < contextCount; i++) { + final Context context = mContextToPreChangedConfigMap.keyAt(i); + final Configuration preTransactionConfig = + mContextToPreChangedConfigMap.valueAt(i); + final Configuration postTransactionConfig = context.getResources() + .getConfiguration(); + if (!areConfigurationsEqualForDisplay( + postTransactionConfig, preTransactionConfig)) { + configUpdatedDisplayIds.add(context.getDisplayId()); + } + } + + // Dispatch the display changed callbacks. + final ClientTransactionListenerController controller = + ClientTransactionListenerController.getInstance(); + final int displayCount = configUpdatedDisplayIds.size(); + for (int i = 0; i < displayCount; i++) { + final int displayId = configUpdatedDisplayIds.valueAt(i); + controller.onDisplayChanged(displayId); + } + } finally { + mContextToPreChangedConfigMap.clear(); } - mConfigUpdatedDisplayIds.clear(); } mPendingActions.clear(); @@ -182,26 +211,24 @@ public class TransactionExecutor { } } - // Can't read flag from isolated process. - final boolean isBundleClientTransactionFlagEnabled = !Process.isIsolated() - && bundleClientTransactionFlag(); - final Context configUpdatedContext = isBundleClientTransactionFlagEnabled + final boolean shouldTrackConfigUpdatedContext = + // No configuration change for local transaction. + !mTransactionHandler.isExecutingLocalTransaction() + // Can't read flag from isolated process. + && !Process.isIsolated() + && bundleClientTransactionFlag(); + final Context configUpdatedContext = shouldTrackConfigUpdatedContext ? item.getContextToUpdate(mTransactionHandler) : null; - final Configuration preExecutedConfig = configUpdatedContext != null - ? new Configuration(configUpdatedContext.getResources().getConfiguration()) - : null; + if (configUpdatedContext != null + && !mContextToPreChangedConfigMap.containsKey(configUpdatedContext)) { + // Keep track of the first pre-executed config of each changed Context. + mContextToPreChangedConfigMap.put(configUpdatedContext, + new Configuration(configUpdatedContext.getResources().getConfiguration())); + } item.execute(mTransactionHandler, mPendingActions); - if (configUpdatedContext != null) { - final Configuration postExecutedConfig = configUpdatedContext.getResources() - .getConfiguration(); - if (!areConfigurationsEqualForDisplay(postExecutedConfig, preExecutedConfig)) { - mConfigUpdatedDisplayIds.add(configUpdatedContext.getDisplayId()); - } - } - item.postExecute(mTransactionHandler, mPendingActions); if (r == null) { // Launch activity request will create an activity record. diff --git a/core/java/android/app/servertransaction/WindowStateResizeItem.java b/core/java/android/app/servertransaction/WindowStateResizeItem.java index f5920ecd012b..193b03ced0b0 100644 --- a/core/java/android/app/servertransaction/WindowStateResizeItem.java +++ b/core/java/android/app/servertransaction/WindowStateResizeItem.java @@ -22,7 +22,9 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityThread; import android.app.ClientTransactionHandler; +import android.content.Context; import android.os.Parcel; import android.os.RemoteException; import android.os.Trace; @@ -68,6 +70,13 @@ public class WindowStateResizeItem extends ClientTransactionItem { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } + @Nullable + @Override + public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { + // WindowStateResizeItem may update the global config with #mConfiguration. + return ActivityThread.currentApplication(); + } + // ObjectPoolItem implementation private WindowStateResizeItem() {} diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig index ec2e5fe23ab9..084cba37de09 100644 --- a/core/java/android/appwidget/flags.aconfig +++ b/core/java/android/appwidget/flags.aconfig @@ -20,3 +20,10 @@ flag { description: "Move state file IO to non-critical path" bug: "312949280" } + +flag { + name: "draw_data_parcel" + namespace: "app_widgets" + description: "Enable support for transporting draw instructions as data parcel" + bug: "286130467" +} diff --git a/core/java/android/content/pm/ModuleInfo.java b/core/java/android/content/pm/ModuleInfo.java index a7306a311ad8..a1c874725d4b 100644 --- a/core/java/android/content/pm/ModuleInfo.java +++ b/core/java/android/content/pm/ModuleInfo.java @@ -16,10 +16,15 @@ package android.content.pm; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Objects; /** @@ -46,6 +51,13 @@ public final class ModuleInfo implements Parcelable { /** Whether or not this module is hidden from the user. */ private boolean mHidden; + /** + * The list of the package names of all APK-in-APEX apps in the module, or + * null if there are none. + */ + @Nullable + private List<String> mApkInApexPackageNames; + // TODO: Decide whether we need an additional metadata bundle to support out of band // updates to ModuleInfo. // @@ -61,6 +73,9 @@ public final class ModuleInfo implements Parcelable { mPackageName = orig.mPackageName; mHidden = orig.mHidden; mApexModuleName = orig.mApexModuleName; + if (orig.mApkInApexPackageNames != null) { + mApkInApexPackageNames = List.copyOf(orig.mApkInApexPackageNames); + } } /** @hide Sets the public name of this module. */ @@ -107,6 +122,25 @@ public final class ModuleInfo implements Parcelable { return mApexModuleName; } + /** @hide Sets the list of the package name of APK-in-APEX apps in this module. */ + public ModuleInfo setApkInApexPackageNames(@NonNull Collection<String> apkInApexPackageNames) { + Objects.requireNonNull(apkInApexPackageNames); + mApkInApexPackageNames = List.copyOf(apkInApexPackageNames); + return this; + } + + /** + * Gets the list of the package name of all APK-in-APEX apps in the module. + */ + @NonNull + @FlaggedApi(android.content.pm.Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX) + public Collection<String> getApkInApexPackageNames() { + if (mApkInApexPackageNames == null) { + return Collections.emptyList(); + } + return mApkInApexPackageNames; + } + /** Returns a string representation of this object. */ public String toString() { return "ModuleInfo{" @@ -125,6 +159,7 @@ public final class ModuleInfo implements Parcelable { hashCode = 31 * hashCode + Objects.hashCode(mName); hashCode = 31 * hashCode + Objects.hashCode(mPackageName); hashCode = 31 * hashCode + Objects.hashCode(mApexModuleName); + hashCode = 31 * hashCode + Objects.hashCode(mApkInApexPackageNames); hashCode = 31 * hashCode + Boolean.hashCode(mHidden); return hashCode; } @@ -138,6 +173,7 @@ public final class ModuleInfo implements Parcelable { return Objects.equals(mName, other.mName) && Objects.equals(mPackageName, other.mPackageName) && Objects.equals(mApexModuleName, other.mApexModuleName) + && Objects.equals(mApkInApexPackageNames, other.mApkInApexPackageNames) && mHidden == other.mHidden; } @@ -147,6 +183,8 @@ public final class ModuleInfo implements Parcelable { dest.writeString(mPackageName); dest.writeBoolean(mHidden); dest.writeString(mApexModuleName); + // Parcel#writeStringList handles null case, we can use it directly + dest.writeStringList(mApkInApexPackageNames); } private ModuleInfo(Parcel source) { @@ -154,6 +192,7 @@ public final class ModuleInfo implements Parcelable { mPackageName = source.readString(); mHidden = source.readBoolean(); mApexModuleName = source.readString(); + mApkInApexPackageNames = source.createStringArrayList(); } public static final @android.annotation.NonNull Parcelable.Creator<ModuleInfo> CREATOR = diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index 4f61613b9c6e..c1c9928e0571 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -499,6 +499,16 @@ public class PackageInfo implements Parcelable { */ public boolean isActiveApex; + /** + * If the package is an APEX package (i.e. the value of {@link #isApex} + * is true), this field is the package name of the APEX. If the package + * is one APK-in-APEX app, this field is the package name of the parent + * APEX that contains the app. If the package is not one of the above + * two cases, this field is {@code null}. + */ + @Nullable + private String mApexPackageName; + public PackageInfo() { } @@ -535,6 +545,26 @@ public class PackageInfo implements Parcelable { mArchiveTimeMillis = value; } + /** + * If the package is an APEX package (i.e. the value of {@link #isApex} + * is true), returns the package name of the APEX. If the package + * is one APK-in-APEX app, returns the package name of the parent + * APEX that contains the app. If the package is not one of the above + * two cases, returns {@code null}. + */ + @Nullable + @FlaggedApi(android.content.pm.Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX) + public String getApexPackageName() { + return mApexPackageName; + } + + /** + * @hide + */ + public void setApexPackageName(@Nullable String apexPackageName) { + mApexPackageName = apexPackageName; + } + @Override public String toString() { return "PackageInfo{" @@ -603,6 +633,12 @@ public class PackageInfo implements Parcelable { dest.writeBoolean(isApex); dest.writeBoolean(isActiveApex); dest.writeLong(mArchiveTimeMillis); + if (mApexPackageName != null) { + dest.writeInt(1); + dest.writeString8(mApexPackageName); + } else { + dest.writeInt(0); + } dest.restoreAllowSquashing(prevAllowSquashing); } @@ -669,5 +705,9 @@ public class PackageInfo implements Parcelable { isApex = source.readBoolean(); isActiveApex = source.readBoolean(); mArchiveTimeMillis = source.readLong(); + int hasApexPackageName = source.readInt(); + if (hasApexPackageName != 0) { + mApexPackageName = source.readString8(); + } } } diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java index ad3ccc41cf6d..3fcb3daaa1f2 100644 --- a/core/java/android/credentials/CredentialManager.java +++ b/core/java/android/credentials/CredentialManager.java @@ -37,6 +37,7 @@ import android.os.OutcomeReceiver; import android.os.RemoteException; import android.provider.DeviceConfig; import android.util.Log; +import android.view.autofill.IAutoFillManagerClient; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -135,7 +136,8 @@ public final class CredentialManager { @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver<GetCandidateCredentialsResponse, - GetCandidateCredentialsException> callback + GetCandidateCredentialsException> callback, + @NonNull IAutoFillManagerClient clientCallback ) { requireNonNull(request, "request must not be null"); requireNonNull(callingPackage, "callingPackage must not be null"); @@ -153,6 +155,7 @@ public final class CredentialManager { mService.getCandidateCredentials( request, new GetCandidateCredentialsTransport(executor, callback), + clientCallback, callingPackage); } catch (RemoteException e) { e.rethrowFromSystemServer(); diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java index 1b130a9fb64d..530feadae836 100644 --- a/core/java/android/credentials/GetCandidateCredentialsResponse.java +++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java @@ -18,6 +18,7 @@ package android.credentials; import android.annotation.Hide; import android.annotation.NonNull; +import android.app.PendingIntent; import android.credentials.ui.GetCredentialProviderData; import android.os.Parcel; import android.os.Parcelable; @@ -35,22 +36,39 @@ import java.util.List; */ @Hide public final class GetCandidateCredentialsResponse implements Parcelable { - // TODO(b/299321990): Add members - @NonNull private final List<GetCredentialProviderData> mCandidateProviderDataList; + private final PendingIntent mPendingIntent; + + private final GetCredentialResponse mGetCredentialResponse; + /** * @hide */ @Hide public GetCandidateCredentialsResponse( - List<GetCredentialProviderData> candidateProviderDataList + GetCredentialResponse getCredentialResponse + ) { + mCandidateProviderDataList = null; + mPendingIntent = null; + mGetCredentialResponse = getCredentialResponse; + } + + /** + * @hide + */ + @Hide + public GetCandidateCredentialsResponse( + List<GetCredentialProviderData> candidateProviderDataList, + PendingIntent pendingIntent ) { Preconditions.checkCollectionNotEmpty( candidateProviderDataList, /*valueName=*/ "candidateProviderDataList"); mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList); + mPendingIntent = pendingIntent; + mGetCredentialResponse = null; } /** @@ -62,17 +80,40 @@ public final class GetCandidateCredentialsResponse implements Parcelable { return mCandidateProviderDataList; } + /** + * Returns candidate provider data list. + * + * @hide + */ + public GetCredentialResponse getGetCredentialResponse() { + return mGetCredentialResponse; + } + + /** + * Returns candidate provider data list. + * + * @hide + */ + public PendingIntent getPendingIntent() { + return mPendingIntent; + } + protected GetCandidateCredentialsResponse(Parcel in) { List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); in.readTypedList(candidateProviderDataList, GetCredentialProviderData.CREATOR); mCandidateProviderDataList = candidateProviderDataList; AnnotationValidations.validate(NonNull.class, null, mCandidateProviderDataList); + + mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); + mGetCredentialResponse = in.readTypedObject(GetCredentialResponse.CREATOR); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeTypedList(mCandidateProviderDataList); + dest.writeTypedObject(mPendingIntent, flags); + dest.writeTypedObject(mGetCredentialResponse, flags); } @Override diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl index d0815766024a..726bc979ea8f 100644 --- a/core/java/android/credentials/ICredentialManager.aidl +++ b/core/java/android/credentials/ICredentialManager.aidl @@ -22,6 +22,7 @@ import android.credentials.CredentialProviderInfo; import android.credentials.ClearCredentialStateRequest; import android.credentials.CreateCredentialRequest; import android.credentials.GetCandidateCredentialsRequest; +import android.view.autofill.IAutoFillManagerClient; import android.credentials.GetCredentialRequest; import android.credentials.RegisterCredentialDescriptionRequest; import android.credentials.UnregisterCredentialDescriptionRequest; @@ -47,7 +48,7 @@ interface ICredentialManager { @nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage); - @nullable ICancellationSignal getCandidateCredentials(in GetCredentialRequest request, in IGetCandidateCredentialsCallback callback, String callingPackage); + @nullable ICancellationSignal getCandidateCredentials(in GetCredentialRequest request, in IGetCandidateCredentialsCallback callback, in IAutoFillManagerClient clientCallback, String callingPackage); @nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage); diff --git a/core/java/android/credentials/ui/Constants.java b/core/java/android/credentials/ui/Constants.java index 7092f291eea5..37f850bc46c5 100644 --- a/core/java/android/credentials/ui/Constants.java +++ b/core/java/android/credentials/ui/Constants.java @@ -29,6 +29,13 @@ public class Constants { public static final String EXTRA_RESULT_RECEIVER = "android.credentials.ui.extra.RESULT_RECEIVER"; + /** + * The intent extra key for indicating whether the bottom sheet should be started directly + * on the 'All Options' screen. + */ + public static final String EXTRA_REQ_FOR_ALL_OPTIONS = + "android.credentials.ui.extra.REQ_FOR_ALL_OPTIONS"; + /** The intent action for when the enabled Credential Manager providers has been updated. */ public static final String CREDMAN_ENABLED_PROVIDERS_UPDATED = "android.credentials.ui.action.CREDMAN_ENABLED_PROVIDERS_UPDATED"; diff --git a/core/java/android/credentials/ui/IntentFactory.java b/core/java/android/credentials/ui/IntentFactory.java index 5e8372d68eb2..49321d514128 100644 --- a/core/java/android/credentials/ui/IntentFactory.java +++ b/core/java/android/credentials/ui/IntentFactory.java @@ -35,6 +35,31 @@ import java.util.ArrayList; */ @TestApi public class IntentFactory { + + /** + * Generate a new launch intent to the Credential Selector UI. + * + * @hide + */ + @NonNull + public static Intent createCredentialSelectorIntent( + @NonNull RequestInfo requestInfo, + @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. + @NonNull + ArrayList<ProviderData> enabledProviderDataList, + @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. + @NonNull + ArrayList<DisabledProviderData> disabledProviderDataList, + @NonNull ResultReceiver resultReceiver, + boolean isRequestForAllOptions) { + + Intent intent = createCredentialSelectorIntent(requestInfo, enabledProviderDataList, + disabledProviderDataList, resultReceiver); + intent.putExtra(Constants.EXTRA_REQ_FOR_ALL_OPTIONS, isRequestForAllOptions); + + return intent; + } + /** Generate a new launch intent to the Credential Selector UI. */ @NonNull public static Intent createCredentialSelectorIntent( diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java index e714887920e9..f5b3a7b56302 100644 --- a/core/java/android/hardware/HardwareBuffer.java +++ b/core/java/android/hardware/HardwareBuffer.java @@ -114,10 +114,16 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable { /** Format: 8 bits red */ @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V) public static final int R_8 = 0x38; - /** Format: 16 bits red */ + /** + * Format: 16 bits red. Bits should be represented in unsigned integer, instead of the + * implicit unsigned normalized. + */ @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V) public static final int R_16_UINT = 0x39; - /** Format: 16 bits each red, green */ + /** + * Format: 16 bits each red, green. Bits should be represented in unsigned integer, + * instead of the implicit unsigned normalized. + */ @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V) public static final int RG_1616_UINT = 0x3a; /** Format: 10 bits each red, green, blue, alpha */ diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 6626baffd134..7bea9aeeb86b 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -25,6 +25,7 @@ import android.hardware.input.IInputDeviceBatteryListener; import android.hardware.input.IInputDeviceBatteryState; import android.hardware.input.IKeyboardBacklightListener; import android.hardware.input.IKeyboardBacklightState; +import android.hardware.input.IStickyModifierStateListener; import android.hardware.input.ITabletModeChangedListener; import android.hardware.input.TouchCalibration; import android.os.CombinedVibration; @@ -241,4 +242,14 @@ interface IInputManager { void unregisterKeyboardBacklightListener(IKeyboardBacklightListener listener); HostUsiVersion getHostUsiVersionFromDisplayConfig(int displayId); + + @EnforcePermission("MONITOR_STICKY_MODIFIER_STATE") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.MONITOR_STICKY_MODIFIER_STATE)") + void registerStickyModifierStateListener(IStickyModifierStateListener listener); + + @EnforcePermission("MONITOR_STICKY_MODIFIER_STATE") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.MONITOR_STICKY_MODIFIER_STATE)") + void unregisterStickyModifierStateListener(IStickyModifierStateListener listener); } diff --git a/core/java/android/hardware/input/IStickyModifierStateListener.aidl b/core/java/android/hardware/input/IStickyModifierStateListener.aidl new file mode 100644 index 000000000000..bd139ab75698 --- /dev/null +++ b/core/java/android/hardware/input/IStickyModifierStateListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.input; + +/** @hide */ +oneway interface IStickyModifierStateListener { + + /** + * Called when the sticky modifier state is changed when A11y Sticky keys feature is enabled + */ + void onStickyModifierStateChanged(int modifierState, int lockedModifierState); +} diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index f941ad87bac5..4ebbde732747 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1297,6 +1297,42 @@ public final class InputManager { } /** + * Registers a Sticky modifier state change listener to be notified about {@link + * StickyModifierState} changes. + * + * @param executor an executor on which the callback will be called + * @param listener the {@link StickyModifierStateListener} + * @throws IllegalArgumentException if {@code listener} has already been registered previously. + * @throws NullPointerException if {@code listener} or {@code executor} is null. + * @hide + * @see #unregisterStickyModifierStateListener(StickyModifierStateListener) + */ + @RequiresPermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE) + public void registerStickyModifierStateListener(@NonNull Executor executor, + @NonNull StickyModifierStateListener listener) throws IllegalArgumentException { + if (!InputSettings.isAccessibilityStickyKeysFeatureEnabled()) { + return; + } + mGlobal.registerStickyModifierStateListener(executor, listener); + } + + /** + * Unregisters a previously added Sticky modifier state change listener. + * + * @param listener the {@link StickyModifierStateListener} + * @hide + * @see #registerStickyModifierStateListener(Executor, StickyModifierStateListener) + */ + @RequiresPermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE) + public void unregisterStickyModifierStateListener( + @NonNull StickyModifierStateListener listener) { + if (!InputSettings.isAccessibilityStickyKeysFeatureEnabled()) { + return; + } + mGlobal.unregisterStickyModifierStateListener(listener); + } + + /** * A callback used to be notified about battery state changes for an input device. The * {@link #onBatteryStateChanged(int, long, BatteryState)} method will be called once after the * listener is successfully registered to provide the initial battery state of the device. @@ -1378,4 +1414,23 @@ public final class InputManager { void onKeyboardBacklightChanged( int deviceId, @NonNull KeyboardBacklightState state, boolean isTriggeredByKeyPress); } + + /** + * A callback used to be notified about sticky modifier state changes when A11y Sticky keys + * feature is enabled. + * + * @see #registerStickyModifierStateListener(Executor, StickyModifierStateListener) + * @see #unregisterStickyModifierStateListener(StickyModifierStateListener) + * @hide + */ + public interface StickyModifierStateListener { + /** + * Called when the sticky modifier state changes. + * This method will be called once after the listener is successfully registered to provide + * the initial modifier state. + * + * @param state the new sticky modifier state, never null. + */ + void onStickyModifierStateChanged(@NonNull StickyModifierState state); + } } diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java index 24a69116e77e..7c104a0ca946 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -27,6 +27,7 @@ import android.hardware.input.InputManager.InputDeviceBatteryListener; import android.hardware.input.InputManager.InputDeviceListener; import android.hardware.input.InputManager.KeyboardBacklightListener; import android.hardware.input.InputManager.OnTabletModeChangedListener; +import android.hardware.input.InputManager.StickyModifierStateListener; import android.hardware.lights.Light; import android.hardware.lights.LightState; import android.hardware.lights.LightsManager; @@ -52,6 +53,7 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.InputMonitor; import android.view.KeyCharacterMap; +import android.view.KeyEvent; import android.view.PointerIcon; import com.android.internal.annotations.GuardedBy; @@ -100,6 +102,14 @@ public final class InputManagerGlobal { @GuardedBy("mKeyboardBacklightListenerLock") @Nullable private IKeyboardBacklightListener mKeyboardBacklightListener; + private final Object mStickyModifierStateListenerLock = new Object(); + @GuardedBy("mStickyModifierStateListenerLock") + @Nullable + private ArrayList<StickyModifierStateListenerDelegate> mStickyModifierStateListeners; + @GuardedBy("mStickyModifierStateListenerLock") + @Nullable + private IStickyModifierStateListener mStickyModifierStateListener; + // InputDeviceSensorManager gets notified synchronously from the binder thread when input // devices change, so it must be synchronized with the input device listeners. @GuardedBy("mInputDeviceListeners") @@ -905,6 +915,158 @@ public final class InputManagerGlobal { } } + private static final class StickyModifierStateListenerDelegate { + final InputManager.StickyModifierStateListener mListener; + final Executor mExecutor; + + StickyModifierStateListenerDelegate(StickyModifierStateListener listener, + Executor executor) { + mListener = listener; + mExecutor = executor; + } + + void notifyStickyModifierStateChange(int modifierState, int lockedModifierState) { + mExecutor.execute(() -> + mListener.onStickyModifierStateChanged( + new LocalStickyModifierState(modifierState, lockedModifierState))); + } + } + + private class LocalStickyModifierStateListener extends IStickyModifierStateListener.Stub { + + @Override + public void onStickyModifierStateChanged(int modifierState, int lockedModifierState) { + synchronized (mStickyModifierStateListenerLock) { + if (mStickyModifierStateListeners == null) return; + final int numListeners = mStickyModifierStateListeners.size(); + for (int i = 0; i < numListeners; i++) { + mStickyModifierStateListeners.get(i) + .notifyStickyModifierStateChange(modifierState, lockedModifierState); + } + } + } + } + + // Implementation of the android.hardware.input.StickyModifierState interface used to report + // the sticky modifier state via the StickyModifierStateListener interfaces. + private static final class LocalStickyModifierState extends StickyModifierState { + + private final int mModifierState; + private final int mLockedModifierState; + + LocalStickyModifierState(int modifierState, int lockedModifierState) { + mModifierState = modifierState; + mLockedModifierState = lockedModifierState; + } + + @Override + public boolean isShiftModifierOn() { + return (mModifierState & KeyEvent.META_SHIFT_ON) != 0; + } + + @Override + public boolean isShiftModifierLocked() { + return (mLockedModifierState & KeyEvent.META_SHIFT_ON) != 0; + } + + @Override + public boolean isCtrlModifierOn() { + return (mModifierState & KeyEvent.META_CTRL_ON) != 0; + } + + @Override + public boolean isCtrlModifierLocked() { + return (mLockedModifierState & KeyEvent.META_CTRL_ON) != 0; + } + + @Override + public boolean isMetaModifierOn() { + return (mModifierState & KeyEvent.META_META_ON) != 0; + } + + @Override + public boolean isMetaModifierLocked() { + return (mLockedModifierState & KeyEvent.META_META_ON) != 0; + } + + @Override + public boolean isAltModifierOn() { + return (mModifierState & KeyEvent.META_ALT_LEFT_ON) != 0; + } + + @Override + public boolean isAltModifierLocked() { + return (mLockedModifierState & KeyEvent.META_ALT_LEFT_ON) != 0; + } + + @Override + public boolean isAltGrModifierOn() { + return (mModifierState & KeyEvent.META_ALT_RIGHT_ON) != 0; + } + + @Override + public boolean isAltGrModifierLocked() { + return (mLockedModifierState & KeyEvent.META_ALT_RIGHT_ON) != 0; + } + } + + /** + * @see InputManager#registerStickyModifierStateListener(Executor, StickyModifierStateListener) + */ + @RequiresPermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE) + void registerStickyModifierStateListener(@NonNull Executor executor, + @NonNull StickyModifierStateListener listener) throws IllegalArgumentException { + Objects.requireNonNull(executor, "executor should not be null"); + Objects.requireNonNull(listener, "listener should not be null"); + + synchronized (mStickyModifierStateListenerLock) { + if (mStickyModifierStateListener == null) { + mStickyModifierStateListeners = new ArrayList<>(); + mStickyModifierStateListener = new LocalStickyModifierStateListener(); + + try { + mIm.registerStickyModifierStateListener(mStickyModifierStateListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + final int numListeners = mStickyModifierStateListeners.size(); + for (int i = 0; i < numListeners; i++) { + if (mStickyModifierStateListeners.get(i).mListener == listener) { + throw new IllegalArgumentException("Listener has already been registered!"); + } + } + StickyModifierStateListenerDelegate delegate = + new StickyModifierStateListenerDelegate(listener, executor); + mStickyModifierStateListeners.add(delegate); + } + } + + /** + * @see InputManager#unregisterStickyModifierStateListener(StickyModifierStateListener) + */ + @RequiresPermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE) + void unregisterStickyModifierStateListener( + @NonNull StickyModifierStateListener listener) { + Objects.requireNonNull(listener, "listener should not be null"); + + synchronized (mStickyModifierStateListenerLock) { + if (mStickyModifierStateListeners == null) { + return; + } + mStickyModifierStateListeners.removeIf((delegate) -> delegate.mListener == listener); + if (mStickyModifierStateListeners.isEmpty()) { + try { + mIm.unregisterStickyModifierStateListener(mStickyModifierStateListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mStickyModifierStateListeners = null; + mStickyModifierStateListener = null; + } + } + } + /** * @see InputManager#getKeyboardLayoutsForInputDevice(InputDeviceIdentifier) */ diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java index cb9c3335518a..d93953231eaf 100644 --- a/core/java/android/hardware/input/InputSettings.java +++ b/core/java/android/hardware/input/InputSettings.java @@ -18,6 +18,7 @@ package android.hardware.input; import static com.android.hardware.input.Flags.keyboardA11yBounceKeysFlag; import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag; +import static com.android.input.flags.Flags.enableInputFilterRustImpl; import android.Manifest; import android.annotation.FloatRange; @@ -338,6 +339,21 @@ public class InputSettings { } /** + * Whether Accessibility bounce keys feature is enabled. + * + * <p> + * Bounce keys’ is an accessibility feature to aid users who have physical disabilities, + * that allows the user to configure the device to ignore rapid, repeated keypresses of the + * same key. + * </p> + * + * @hide + */ + public static boolean isAccessibilityBounceKeysFeatureEnabled() { + return keyboardA11yBounceKeysFlag() && enableInputFilterRustImpl(); + } + + /** * Whether Accessibility bounce keys is enabled. * * <p> @@ -364,10 +380,10 @@ public class InputSettings { * @hide */ public static int getAccessibilityBounceKeysThreshold(@NonNull Context context) { - if (!keyboardA11yBounceKeysFlag()) { + if (!isAccessibilityBounceKeysFeatureEnabled()) { return 0; } - return Settings.System.getIntForUser(context.getContentResolver(), + return Settings.Secure.getIntForUser(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS, 0, UserHandle.USER_CURRENT); } @@ -388,7 +404,7 @@ public class InputSettings { @RequiresPermission(Manifest.permission.WRITE_SETTINGS) public static void setAccessibilityBounceKeysThreshold(@NonNull Context context, int thresholdTimeMillis) { - if (!keyboardA11yBounceKeysFlag()) { + if (!isAccessibilityBounceKeysFeatureEnabled()) { return; } if (thresholdTimeMillis < 0 @@ -397,12 +413,29 @@ public class InputSettings { "Provided Bounce keys threshold should be in range [0, " + MAX_ACCESSIBILITY_BOUNCE_KEYS_THRESHOLD_MILLIS + "]"); } - Settings.System.putIntForUser(context.getContentResolver(), + Settings.Secure.putIntForUser(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS, thresholdTimeMillis, UserHandle.USER_CURRENT); } /** + * Whether Accessibility sticky keys feature is enabled. + * + * <p> + * 'Sticky keys' is an accessibility feature that assists users who have physical + * disabilities or help users reduce repetitive strain injury. It serializes keystrokes + * instead of pressing multiple keys at a time, allowing the user to press and release a + * modifier key, such as Shift, Ctrl, Alt, or any other modifier key, and have it remain + * active until any other key is pressed. + * </p> + * + * @hide + */ + public static boolean isAccessibilityStickyKeysFeatureEnabled() { + return keyboardA11yStickyKeysFlag() && enableInputFilterRustImpl(); + } + + /** * Whether Accessibility sticky keys is enabled. * * <p> @@ -416,10 +449,10 @@ public class InputSettings { * @hide */ public static boolean isAccessibilityStickyKeysEnabled(@NonNull Context context) { - if (!keyboardA11yStickyKeysFlag()) { + if (!isAccessibilityStickyKeysFeatureEnabled()) { return false; } - return Settings.System.getIntForUser(context.getContentResolver(), + return Settings.Secure.getIntForUser(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_STICKY_KEYS, 0, UserHandle.USER_CURRENT) != 0; } @@ -439,10 +472,10 @@ public class InputSettings { @RequiresPermission(Manifest.permission.WRITE_SETTINGS) public static void setAccessibilityStickyKeysEnabled(@NonNull Context context, boolean enabled) { - if (!keyboardA11yStickyKeysFlag()) { + if (!isAccessibilityStickyKeysFeatureEnabled()) { return; } - Settings.System.putIntForUser(context.getContentResolver(), + Settings.Secure.putIntForUser(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_STICKY_KEYS, enabled ? 1 : 0, UserHandle.USER_CURRENT); } diff --git a/core/java/android/hardware/input/StickyModifierState.java b/core/java/android/hardware/input/StickyModifierState.java new file mode 100644 index 000000000000..a3f7a0ab542e --- /dev/null +++ b/core/java/android/hardware/input/StickyModifierState.java @@ -0,0 +1,127 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.input; + +/** + * The StickyModifierState class is a representation of a modifier state when A11y Sticky keys + * feature is enabled + * + * @hide + */ +public abstract class StickyModifierState { + + /** + * Represents whether current sticky modifier state includes 'Shift' modifier. + * <p> If {@code true} the next {@link android.view.KeyEvent} will contain 'Shift' modifier in + * its metaState. + * + * @return whether Shift modifier key is on. + */ + public abstract boolean isShiftModifierOn(); + + /** + * Represents whether current sticky modifier state includes 'Shift' modifier, and it is + * locked. + * <p> If {@code true} any subsequent {@link android.view.KeyEvent} will contain 'Shift' + * modifier in its metaState and this state will remain sticky (will not be cleared), until + * user presses 'Shift' key again to clear the locked state. + * + * @return whether Shift modifier key is locked. + */ + public abstract boolean isShiftModifierLocked(); + + /** + * Represents whether current sticky modifier state includes 'Ctrl' modifier. + * <p> If {@code true} the next {@link android.view.KeyEvent} will contain 'Ctrl' modifier in + * its metaState. + * + * @return whether Ctrl modifier key is on. + */ + public abstract boolean isCtrlModifierOn(); + + /** + * Represents whether current sticky modifier state includes 'Ctrl' modifier, and it is + * locked. + * <p> If {@code true} any subsequent {@link android.view.KeyEvent} will contain 'Ctrl' + * modifier in its metaState and this state will remain sticky (will not be cleared), until + * user presses 'Ctrl' key again to clear the locked state. + * + * @return whether Ctrl modifier key is locked. + */ + public abstract boolean isCtrlModifierLocked(); + + /** + * Represents whether current sticky modifier state includes 'Meta' modifier. + * <p> If {@code true} the next {@link android.view.KeyEvent} will contain 'Meta' modifier in + * its metaState. + * + * @return whether Meta modifier key is on. + */ + public abstract boolean isMetaModifierOn(); + + /** + * Represents whether current sticky modifier state includes 'Meta' modifier, and it is + * locked. + * <p> If {@code true} any subsequent {@link android.view.KeyEvent} will contain 'Meta' + * modifier in its metaState and this state will remain sticky (will not be cleared), until + * user presses 'Meta' key again to clear the locked state. + * + * @return whether Meta modifier key is locked. + */ + public abstract boolean isMetaModifierLocked(); + + /** + * Represents whether current sticky modifier state includes 'Alt' modifier. + * <p> If {@code true} the next {@link android.view.KeyEvent} will contain 'Alt' modifier in + * its metaState. + * + * @return whether Alt modifier key is on. + */ + public abstract boolean isAltModifierOn(); + + /** + * Represents whether current sticky modifier state includes 'Alt' modifier, and it is + * locked. + * <p> If {@code true} any subsequent {@link android.view.KeyEvent} will contain 'Alt' + * modifier in its metaState and this state will remain sticky (will not be cleared), until + * user presses 'Alt' key again to clear the locked state. + * + * @return whether Alt modifier key is locked. + */ + public abstract boolean isAltModifierLocked(); + + /** + * Represents whether current sticky modifier state includes 'AltGr' modifier. + * <p> If {@code true} the next {@link android.view.KeyEvent} will contain 'AltGr' modifier in + * its metaState. + * + * @return whether AltGr modifier key is on. + */ + public abstract boolean isAltGrModifierOn(); + + /** + * Represents whether current sticky modifier state includes 'AltGr' modifier, and it is + * locked. + * <p> If {@code true} any subsequent {@link android.view.KeyEvent} will contain 'AltGr' + * modifier in its metaState and this state will remain sticky (will not be cleared), until + * user presses 'AltGr' key again to clear the locked state. + * + * @return whether AltGr modifier key is locked. + */ + public abstract boolean isAltGrModifierLocked(); +} + diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 18d3e5e02fbe..71698e4f4469 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -127,6 +127,7 @@ import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.Flags; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InlineSuggestionsResponse; @@ -388,6 +389,9 @@ public class InputMethodService extends AbstractInputMethodService { private long mStylusHwSessionsTimeout = STYLUS_HANDWRITING_IDLE_TIMEOUT_MS; private Runnable mStylusWindowIdleTimeoutRunnable; private long mStylusWindowIdleTimeoutForTest; + /** Tracks last {@link MotionEvent#getToolType(int)} used for {@link MotionEvent#ACTION_DOWN}. + **/ + private int mLastUsedToolType; /** * Returns whether {@link InputMethodService} is responsible for rendering the back button and @@ -1005,7 +1009,7 @@ public class InputMethodService extends AbstractInputMethodService { */ @Override public void updateEditorToolType(@ToolType int toolType) { - onUpdateEditorToolType(toolType); + updateEditorToolTypeInternal(toolType); } /** @@ -1249,6 +1253,14 @@ public class InputMethodService extends AbstractInputMethodService { rootView.setSystemGestureExclusionRects(exclusionRects); } + private void updateEditorToolTypeInternal(int toolType) { + if (Flags.useHandwritingListenerForTooltype()) { + mLastUsedToolType = toolType; + mInputEditorInfo.setInitialToolType(toolType); + } + onUpdateEditorToolType(toolType); + } + /** * Concrete implementation of * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides @@ -3110,6 +3122,9 @@ public class InputMethodService extends AbstractInputMethodService { null /* icProto */); mInputStarted = true; mStartedInputConnection = ic; + if (Flags.useHandwritingListenerForTooltype()) { + editorInfo.setInitialToolType(mLastUsedToolType); + } mInputEditorInfo = editorInfo; initialize(); mInlineSuggestionSessionController.notifyOnStartInput( @@ -3354,6 +3369,10 @@ public class InputMethodService extends AbstractInputMethodService { * had not seen the event at all. */ public boolean onKeyDown(int keyCode, KeyEvent event) { + if (Flags.useHandwritingListenerForTooltype()) { + // any KeyEvent keyDown should reset last toolType. + updateEditorToolTypeInternal(MotionEvent.TOOL_TYPE_UNKNOWN); + } if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { final ExtractEditText eet = getExtractEditTextIfVisible(); if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) { diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index 8fcff78fb025..3149de4c39e7 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -673,6 +673,7 @@ public class GraphicsEnvironment { if (anglePkg.isEmpty()) { return; } + intent.setPackage(anglePkg); context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { @Override diff --git a/core/java/android/os/HwNoService.java b/core/java/android/os/HwNoService.java index 117c3ad7ee48..084031496629 100644 --- a/core/java/android/os/HwNoService.java +++ b/core/java/android/os/HwNoService.java @@ -16,37 +16,127 @@ package android.os; +import android.hidl.manager.V1_2.IServiceManager; +import android.util.Log; + +import java.util.ArrayList; + /** * A fake hwservicemanager that is used locally when HIDL isn't supported on the device. * * @hide */ -final class HwNoService implements IHwBinder, IHwInterface { +final class HwNoService extends IServiceManager.Stub implements IHwBinder, IHwInterface { + private static final String TAG = "HwNoService"; + /** @hide */ @Override - public void transact(int code, HwParcel request, HwParcel reply, int flags) {} + public String toString() { + return "[HwNoService]"; + } - /** @hide */ @Override - public IHwInterface queryLocalInterface(String descriptor) { - return new HwNoService(); + public android.hidl.base.V1_0.IBase get(String fqName, String name) + throws android.os.RemoteException { + Log.i(TAG, "get " + fqName + "/" + name + " with no hwservicemanager"); + return null; } - /** @hide */ @Override - public boolean linkToDeath(DeathRecipient recipient, long cookie) { + public boolean add(String name, android.hidl.base.V1_0.IBase service) + throws android.os.RemoteException { + Log.i(TAG, "get " + name + " with no hwservicemanager"); + return false; + } + + @Override + public byte getTransport(String fqName, String name) throws android.os.RemoteException { + Log.i(TAG, "getTransoport " + fqName + "/" + name + " with no hwservicemanager"); + return 0x0; + } + + @Override + public java.util.ArrayList<String> list() throws android.os.RemoteException { + Log.i(TAG, "list with no hwservicemanager"); + return new ArrayList<String>(); + } + + @Override + public java.util.ArrayList<String> listByInterface(String fqName) + throws android.os.RemoteException { + Log.i(TAG, "listByInterface with no hwservicemanager"); + return new ArrayList<String>(); + } + + @Override + public boolean registerForNotifications( + String fqName, String name, android.hidl.manager.V1_0.IServiceNotification callback) + throws android.os.RemoteException { + Log.i(TAG, "registerForNotifications with no hwservicemanager"); return true; } - /** @hide */ @Override - public boolean unlinkToDeath(DeathRecipient recipient) { + public ArrayList<android.hidl.manager.V1_0.IServiceManager.InstanceDebugInfo> debugDump() + throws android.os.RemoteException { + Log.i(TAG, "debugDump with no hwservicemanager"); + return new ArrayList<android.hidl.manager.V1_0.IServiceManager.InstanceDebugInfo>(); + } + + @Override + public void registerPassthroughClient(String fqName, String name) + throws android.os.RemoteException { + Log.i(TAG, "registerPassthroughClient with no hwservicemanager"); + } + + @Override + public boolean unregisterForNotifications( + String fqName, String name, android.hidl.manager.V1_0.IServiceNotification callback) + throws android.os.RemoteException { + Log.i(TAG, "unregisterForNotifications with no hwservicemanager"); return true; } - /** @hide */ @Override - public IHwBinder asBinder() { - return this; + public boolean registerClientCallback( + String fqName, + String name, + android.hidl.base.V1_0.IBase server, + android.hidl.manager.V1_2.IClientCallback cb) + throws android.os.RemoteException { + Log.i( + TAG, + "registerClientCallback for " + fqName + "/" + name + " with no hwservicemanager"); + return true; + } + + @Override + public boolean unregisterClientCallback( + android.hidl.base.V1_0.IBase server, android.hidl.manager.V1_2.IClientCallback cb) + throws android.os.RemoteException { + Log.i(TAG, "unregisterClientCallback with no hwservicemanager"); + return true; + } + + @Override + public boolean addWithChain( + String name, android.hidl.base.V1_0.IBase service, java.util.ArrayList<String> chain) + throws android.os.RemoteException { + Log.i(TAG, "addWithChain with no hwservicemanager"); + return true; + } + + @Override + public java.util.ArrayList<String> listManifestByInterface(String fqName) + throws android.os.RemoteException { + Log.i(TAG, "listManifestByInterface for " + fqName + " with no hwservicemanager"); + return new ArrayList<String>(); + } + + @Override + public boolean tryUnregister(String fqName, String name, android.hidl.base.V1_0.IBase service) + throws android.os.RemoteException { + Log.i(TAG, "tryUnregister for " + fqName + "/" + name + " with no hwservicemanager"); + return true; } } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 80ec458cd715..f952fcf36e60 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -21,6 +21,7 @@ import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UptimeMillisLong; @@ -978,12 +979,10 @@ public class Process { } /** - * Returns whether the provided UID belongs to a SDK sandbox process. - * - * @hide + * Returns whether the provided UID belongs to an sdk sandbox process + * @see android.app.sdksandbox.SdkSandboxManager */ - @SystemApi(client = MODULE_LIBRARIES) - @TestApi + @SuppressLint("UnflaggedApi") // promoting from @SystemApi. @android.ravenwood.annotation.RavenwoodKeep public static final boolean isSdkSandboxUid(int uid) { uid = UserHandle.getAppId(uid); @@ -991,15 +990,20 @@ public class Process { } /** + * Returns the app uid corresponding to an sdk sandbox uid. + * @see android.app.sdksandbox.SdkSandboxManager * - * Returns the app process corresponding to an sdk sandbox process. + * @param uid the sdk sandbox uid + * @return the app uid for the given sdk sandbox uid * - * @hide + * @throws IllegalArgumentException if input is not an sdk sandbox uid */ - @SystemApi(client = MODULE_LIBRARIES) - @TestApi + @SuppressLint("UnflaggedApi") // promoting from @SystemApi. @android.ravenwood.annotation.RavenwoodKeep public static final int getAppUidForSdkSandboxUid(int uid) { + if (!isSdkSandboxUid(uid)) { + throw new IllegalArgumentException("Input UID is not an SDK sandbox UID"); + } return uid - (FIRST_SDK_SANDBOX_UID - FIRST_APPLICATION_UID); } diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index e32a8f32ce95..8c8af0ead227 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -2373,13 +2373,29 @@ public final class StrictMode { /** Assume locked until we hear otherwise */ private static volatile boolean sCeStorageUnlocked = false; + /** + * Avoid (potentially) costly and repeated lookups to the same mount service. + * Note that we don't use the Singleton wrapper as lookup may fail early during boot. + */ + private static volatile IStorageManager sStorageManager; + private static boolean isCeStorageUnlocked(int userId) { - final IStorageManager storage = IStorageManager.Stub + IStorageManager storage = sStorageManager; + if (storage == null) { + storage = IStorageManager.Stub .asInterface(ServiceManager.getService("mount")); + // As the queried handle may be null early during boot, only stash valid handles, + // avoiding races with concurrent service queries. + if (storage != null) { + sStorageManager = storage; + } + } if (storage != null) { try { return storage.isCeStorageUnlocked(userId); } catch (RemoteException ignored) { + // Conservatively clear the ref, allowing refresh if the remote process restarts. + sStorageManager = null; } } return false; diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 83d237d6e53b..d64614628b61 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -91,3 +91,10 @@ flag { is_fixed_read_only: true bug: "315037695" } + +flag { + name: "strict_mode_restricted_network" + namespace: "backstage_power" + description: "Guards StrictMode APIs for detecting restricted network access." + bug: "317250784" +} diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig index 4e5588cce1c9..fe6c4a4321e9 100644 --- a/core/java/android/security/responsible_apis_flags.aconfig +++ b/core/java/android/security/responsible_apis_flags.aconfig @@ -20,3 +20,10 @@ flag { description: "Enables toasts when ASM restrictions are triggered" bug: "230590090" } + +flag { + name: "content_uri_permission_apis" + namespace: "responsible_apis" + description: "Enables the content URI permission APIs" + bug: "293467489" +} diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index cb1b5d3d20b8..5ad2502d1546 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -37,6 +37,7 @@ import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; +import android.view.autofill.IAutoFillManagerClient; import com.android.internal.os.IResultReceiver; @@ -621,6 +622,23 @@ public abstract class AutofillService extends Service { new FillCallback(callback, request.getId()))); } + + @Override + public void onFillCredentialRequest(FillRequest request, IFillCallback callback, + IAutoFillManagerClient autofillClientCallback) { + ICancellationSignal transport = CancellationSignal.createTransport(); + try { + callback.onCancellable(transport); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + mHandler.sendMessage(obtainMessage( + AutofillService::onFillCredentialRequest, + AutofillService.this, request, CancellationSignal.fromTransport(transport), + new FillCallback(callback, request.getId()), + autofillClientCallback)); + } + @Override public void onSaveRequest(SaveRequest request, ISaveCallback callback) { mHandler.sendMessage(obtainMessage( @@ -683,6 +701,15 @@ public abstract class AutofillService extends Service { @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback); /** + * Variant of onFillRequest for internal credential manager proxy autofill service only. + * + * @hide + */ + public void onFillCredentialRequest(@NonNull FillRequest request, + @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback, + IAutoFillManagerClient autofillClientCallback) {} + + /** * Called when the user requests the service to save the contents of a screen. * * <p>If the service could not handle the request right away—for example, because it must diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl index d88e0945bdca..03ead3266521 100644 --- a/core/java/android/service/autofill/IAutoFillService.aidl +++ b/core/java/android/service/autofill/IAutoFillService.aidl @@ -20,6 +20,7 @@ import android.service.autofill.FillRequest; import android.service.autofill.IFillCallback; import android.service.autofill.ISaveCallback; import android.service.autofill.SaveRequest; +import android.view.autofill.IAutoFillManagerClient; import com.android.internal.os.IResultReceiver; /** @@ -30,6 +31,8 @@ import com.android.internal.os.IResultReceiver; oneway interface IAutoFillService { void onConnectedStateChanged(boolean connected); void onFillRequest(in FillRequest request, in IFillCallback callback); + void onFillCredentialRequest(in FillRequest request, in IFillCallback callback, + in IAutoFillManagerClient client); void onSaveRequest(in SaveRequest request, in ISaveCallback callback); void onSavedPasswordCountRequest(in IResultReceiver receiver); } diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 78248d9775f4..e1965ef25562 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -53,7 +53,6 @@ import android.view.contentcapture.ContentCaptureSessionId; import android.view.contentcapture.DataRemovalRequest; import android.view.contentcapture.DataShareRequest; import android.view.contentcapture.IContentCaptureDirectManager; -import android.view.contentcapture.MainContentCaptureSession; import com.android.internal.os.IResultReceiver; import com.android.internal.util.FrameworkStatsLog; @@ -724,7 +723,7 @@ public abstract class ContentCaptureService extends Service { final Bundle extras; if (binder != null) { extras = new Bundle(); - extras.putBinder(MainContentCaptureSession.EXTRA_BINDER, binder); + extras.putBinder(ContentCaptureSession.EXTRA_BINDER, binder); } else { extras = null; } diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java index b1680abfadeb..3c1a2796de95 100644 --- a/core/java/android/service/notification/ZenPolicy.java +++ b/core/java/android/service/notification/ZenPolicy.java @@ -256,7 +256,7 @@ public final class ZenPolicy implements Parcelable { * @return {@link #CONVERSATION_SENDERS_UNSET}, {@link #CONVERSATION_SENDERS_ANYONE}, * {@link #CONVERSATION_SENDERS_IMPORTANT}, {@link #CONVERSATION_SENDERS_NONE}. */ - public @PeopleType int getPriorityConversationSenders() { + public @ConversationSenders int getPriorityConversationSenders() { return mConversationSenders; } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 54116a2749e0..692dad49ec89 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -26,6 +26,8 @@ import static android.graphics.Matrix.MSKEW_Y; import static android.view.View.SYSTEM_UI_FLAG_VISIBLE; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static com.android.window.flags.Flags.noConsecutiveVisibilityEvents; + import android.animation.AnimationHandler; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -1431,27 +1433,36 @@ public abstract class WallpaperService extends Service { } if (didSurface && !mReportedVisible) { - // This wallpaper is currently invisible, but its - // surface has changed. At this point let's tell it - // again that it is invisible in case the report about - // the surface caused it to start running. We really - // don't want wallpapers running when not visible. if (mIsCreating) { - // Some wallpapers will ignore this call if they - // had previously been told they were invisble, - // so if we are creating a new surface then toggle - // the state to get them to notice. - if (DEBUG) Log.v(TAG, "onVisibilityChanged(true) at surface: " - + this); - Trace.beginSection("WPMS.Engine.onVisibilityChanged-true"); - onVisibilityChanged(true); + // The surface has been created, but the wallpaper isn't visible. + // Trigger onVisibilityChanged(true) then onVisibilityChanged(false) + // to make sure the wallpaper is stopped even after the events + // onSurfaceCreated() and onSurfaceChanged(). + if (noConsecutiveVisibilityEvents()) { + if (DEBUG) Log.v(TAG, "toggling doVisibilityChanged"); + Trace.beginSection("WPMS.Engine.doVisibilityChanged-true"); + doVisibilityChanged(true); + Trace.endSection(); + Trace.beginSection("WPMS.Engine.doVisibilityChanged-false"); + doVisibilityChanged(false); + Trace.endSection(); + } else { + if (DEBUG) { + Log.v(TAG, "onVisibilityChanged(true) at surface: " + this); + } + Trace.beginSection("WPMS.Engine.onVisibilityChanged-true"); + onVisibilityChanged(true); + Trace.endSection(); + } + } + if (!noConsecutiveVisibilityEvents()) { + if (DEBUG) { + Log.v(TAG, "onVisibilityChanged(false) at surface: " + this); + } + Trace.beginSection("WPMS.Engine.onVisibilityChanged-false"); + onVisibilityChanged(false); Trace.endSection(); } - if (DEBUG) Log.v(TAG, "onVisibilityChanged(false) at surface: " - + this); - Trace.beginSection("WPMS.Engine.onVisibilityChanged-false"); - onVisibilityChanged(false); - Trace.endSection(); } } finally { mIsCreating = false; diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java index 712d1d67c942..f819c9b2f5dc 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -16,6 +16,7 @@ package android.view; +import static android.content.res.Resources.ID_NULL; import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE; import static android.view.DisplayCutoutProto.BOUND_BOTTOM; @@ -23,8 +24,12 @@ import static android.view.DisplayCutoutProto.BOUND_LEFT; import static android.view.DisplayCutoutProto.BOUND_RIGHT; import static android.view.DisplayCutoutProto.BOUND_TOP; import static android.view.DisplayCutoutProto.INSETS; +import static android.view.DisplayCutoutProto.SIDE_OVERRIDES; import static android.view.DisplayCutoutProto.WATERFALL_INSETS; import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_180; +import static android.view.Surface.ROTATION_270; +import static android.view.Surface.ROTATION_90; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; @@ -49,6 +54,7 @@ import android.view.Surface.Rotation; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -112,6 +118,9 @@ public final class DisplayCutout { private static float sCachedPhysicalPixelDisplaySizeRatio; @GuardedBy("CACHE_LOCK") + private static int[] sCachedSideOverrides; + + @GuardedBy("CACHE_LOCK") private static CutoutPathParserInfo sCachedCutoutPathParserInfo; @GuardedBy("CACHE_LOCK") private static Path sCachedCutoutPath; @@ -150,6 +159,15 @@ public final class DisplayCutout { */ public static final int BOUNDS_POSITION_LENGTH = 4; + private static final int INVALID_SIDE_OVERRIDE = -1; + private static final String SIDE_STRING_TOP = "top"; + private static final String SIDE_STRING_BOTTOM = "bottom"; + private static final String SIDE_STRING_RIGHT = "right"; + private static final String SIDE_STRING_LEFT = "left"; + + // The side index is always under the natural rotation of the device. + private int[] mSideOverrides; + /** @hide */ @IntDef(prefix = { "BOUNDS_POSITION_" }, value = { BOUNDS_POSITION_LEFT, @@ -402,8 +420,8 @@ public final class DisplayCutout { // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE) public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft, @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom) { - this(safeInsets.toRect(), Insets.NONE, boundLeft, boundTop, boundRight, boundBottom, null, - true); + this(getCopyOrRef(safeInsets.toRect(), true), Insets.NONE, + new Bounds(boundLeft, boundTop, boundRight, boundBottom, true), null, null); } /** @@ -426,11 +444,41 @@ public final class DisplayCutout { * @param info the cutout path parser info. * @hide */ + @VisibleForTesting public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft, @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom, @NonNull Insets waterfallInsets, @Nullable CutoutPathParserInfo info) { - this(safeInsets.toRect(), waterfallInsets, boundLeft, boundTop, boundRight, boundBottom, - info, true); + this(getCopyOrRef(safeInsets.toRect(), true), waterfallInsets, + new Bounds(boundLeft, boundTop, boundRight, boundBottom, true), info, null); + } + + /** + * Creates a DisplayCutout instance. + * + * <p>Note that this is only useful for tests. For production code, developers should always + * use a {@link DisplayCutout} obtained from the system.</p> + * + * @param safeInsets the insets from each edge which avoid the display cutout as returned by + * {@link #getSafeInsetTop()} etc. + * @param boundLeft the left bounding rect of the display cutout in pixels. If null is passed, + * it's treated as an empty rectangle (0,0)-(0,0). + * @param boundTop the top bounding rect of the display cutout in pixels. If null is passed, + * it's treated as an empty rectangle (0,0)-(0,0). + * @param boundRight the right bounding rect of the display cutout in pixels. If null is + * passed, it's treated as an empty rectangle (0,0)-(0,0). + * @param boundBottom the bottom bounding rect of the display cutout in pixels. If null is + * passed, it's treated as an empty rectangle (0,0)-(0,0). + * @param waterfallInsets the insets for the curved areas in waterfall display. + * @param info the cutout path parser info. + * @hide + */ + public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft, + @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom, + @NonNull Insets waterfallInsets, @Nullable CutoutPathParserInfo info, + @Nullable int[] sideOverrides) { + this(safeInsets.toRect(), waterfallInsets, + new Bounds(boundLeft, boundTop, boundRight, boundBottom, true), + info, sideOverrides); } /** @@ -454,8 +502,8 @@ public final class DisplayCutout { public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft, @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom, @NonNull Insets waterfallInsets) { - this(safeInsets.toRect(), waterfallInsets, boundLeft, boundTop, boundRight, boundBottom, - null, true); + this(getCopyOrRef(safeInsets.toRect(), true), waterfallInsets, + new Bounds(boundLeft, boundTop, boundRight, boundBottom, true), null, null); } /** @@ -473,8 +521,8 @@ public final class DisplayCutout { // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE) @Deprecated public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) { - this(safeInsets, Insets.NONE, extractBoundsFromList(safeInsets, boundingRects), null, - true /* copyArguments */); + this(getCopyOrRef(safeInsets, true), Insets.NONE, + new Bounds(extractBoundsFromList(safeInsets, boundingRects), true), null, null); } /** @@ -498,26 +546,29 @@ public final class DisplayCutout { private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect boundLeft, Rect boundTop, Rect boundRight, Rect boundBottom, CutoutPathParserInfo info, boolean copyArguments) { - mSafeInsets = getCopyOrRef(safeInsets, copyArguments); - mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets; - mBounds = new Bounds(boundLeft, boundTop, boundRight, boundBottom, copyArguments); - mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info; + this(getCopyOrRef(safeInsets, copyArguments), waterfallInsets, + new Bounds(boundLeft, boundTop, boundRight, boundBottom, copyArguments), info, + null); } private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Rect[] bounds, CutoutPathParserInfo info, boolean copyArguments) { - mSafeInsets = getCopyOrRef(safeInsets, copyArguments); - mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets; - mBounds = new Bounds(bounds, copyArguments); - mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info; + this(getCopyOrRef(safeInsets, copyArguments), waterfallInsets, + new Bounds(bounds, copyArguments), info, null); } private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds, CutoutPathParserInfo info) { + this(safeInsets, waterfallInsets, bounds, info, null); + } + + private DisplayCutout(Rect safeInsets, Insets waterfallInsets, Bounds bounds, + CutoutPathParserInfo info, int[] sideOverrides) { mSafeInsets = safeInsets; mWaterfallInsets = waterfallInsets == null ? Insets.NONE : waterfallInsets; mBounds = bounds; mCutoutPathParserInfo = info == null ? EMPTY_PARSER_INFO : info; + mSideOverrides = sideOverrides; } private static Rect getCopyOrRef(Rect r, boolean copyArguments) { @@ -795,6 +846,7 @@ public final class DisplayCutout { result = 48271 * result + mBounds.hashCode(); result = 48271 * result + mWaterfallInsets.hashCode(); result = 48271 * result + mCutoutPathParserInfo.hashCode(); + result = 48271 * result + Arrays.hashCode(mSideOverrides); return result; } @@ -807,7 +859,8 @@ public final class DisplayCutout { DisplayCutout c = (DisplayCutout) o; return mSafeInsets.equals(c.mSafeInsets) && mBounds.equals(c.mBounds) && mWaterfallInsets.equals(c.mWaterfallInsets) - && mCutoutPathParserInfo.equals(c.mCutoutPathParserInfo); + && mCutoutPathParserInfo.equals(c.mCutoutPathParserInfo) + && Arrays.equals(mSideOverrides, c.mSideOverrides); } return false; } @@ -818,9 +871,48 @@ public final class DisplayCutout { + " waterfall=" + mWaterfallInsets + " boundingRect={" + mBounds + "}" + " cutoutPathParserInfo={" + mCutoutPathParserInfo + "}" + + " sideOverrides=" + sideOverridesToString(mSideOverrides) + "}"; } + private static String sideOverridesToString(int[] sideOverrides) { + if (sideOverrides == null) { + return "null"; + } + final StringBuilder sb = new StringBuilder(); + sb.append("{"); + final int length = sideOverrides.length; + if (length != BOUNDS_POSITION_LENGTH) { + sb.append("length=").append(sideOverrides.length).append(". "); + } + boolean hasContent = false; + for (int i = ROTATION_0; i < length; i++) { + final int override = sideOverrides[i]; + if (override != INVALID_SIDE_OVERRIDE) { + if (hasContent) { + sb.append(", "); + } + sb.append(Surface.rotationToString(i)).append(": "); + switch(override) { + case BOUNDS_POSITION_LEFT: + sb.append(SIDE_STRING_LEFT); + break; + case BOUNDS_POSITION_TOP: + sb.append(SIDE_STRING_TOP); + break; + case BOUNDS_POSITION_RIGHT: + sb.append(SIDE_STRING_RIGHT); + break; + case BOUNDS_POSITION_BOTTOM: + sb.append(SIDE_STRING_BOTTOM); + break; + } + hasContent = true; + } + } + return sb.append("}").toString(); + } + /** * @hide */ @@ -832,6 +924,11 @@ public final class DisplayCutout { mBounds.getRect(BOUNDS_POSITION_RIGHT).dumpDebug(proto, BOUND_RIGHT); mBounds.getRect(BOUNDS_POSITION_BOTTOM).dumpDebug(proto, BOUND_BOTTOM); mWaterfallInsets.toRect().dumpDebug(proto, WATERFALL_INSETS); + if (mSideOverrides != null) { + for (int sideOverride : mSideOverrides) { + proto.write(SIDE_OVERRIDES, sideOverride); + } + } proto.end(token); } @@ -899,7 +996,7 @@ public final class DisplayCutout { */ public DisplayCutout replaceSafeInsets(Rect safeInsets) { return new DisplayCutout(new Rect(safeInsets), mWaterfallInsets, mBounds, - mCutoutPathParserInfo); + mCutoutPathParserInfo, mSideOverrides); } private static int atLeastZero(int value) { @@ -1031,8 +1128,10 @@ public final class DisplayCutout { Insets insets; final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); final TypedArray array = res.obtainTypedArray(R.array.config_waterfallCutoutArray); - if (index >= 0 && index < array.length() && array.getResourceId(index, 0) > 0) { - final int resourceId = array.getResourceId(index, 0); + final int resourceId = index >= 0 && index < array.length() + ? array.getResourceId(index, ID_NULL) + : ID_NULL; + if (resourceId != ID_NULL) { final TypedArray waterfall = res.obtainTypedArray(resourceId); insets = Insets.of( waterfall.getDimensionPixelSize(0 /* waterfall left edge size */, 0), @@ -1047,6 +1146,48 @@ public final class DisplayCutout { return insets; } + private static int[] getDisplayCutoutSideOverrides(Resources res, String displayUniqueId) + throws IllegalArgumentException { + if (!Flags.movableCutoutConfiguration()) { + return null; + } + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray( + R.array.config_displayCutoutSideOverrideArray); + final int resourceId = index >= 0 && index < array.length() + ? array.getResourceId(index, ID_NULL) + : ID_NULL; + final String[] rawOverrides = resourceId != ID_NULL + ? array.getResources().getStringArray(resourceId) + : res.getStringArray(R.array.config_mainBuiltInDisplayCutoutSideOverride); + array.recycle(); + final int[] override = new int[]{INVALID_SIDE_OVERRIDE, INVALID_SIDE_OVERRIDE, + INVALID_SIDE_OVERRIDE, INVALID_SIDE_OVERRIDE}; + for (String rawOverride : rawOverrides) { + int rotation; + String[] split = rawOverride.split(" *, *"); + switch (split[0]) { + case "0" -> rotation = ROTATION_0; + case "90" -> rotation = ROTATION_90; + case "180" -> rotation = ROTATION_180; + case "270" -> rotation = ROTATION_270; + default -> throw new IllegalArgumentException("Invalid side override definition: " + + rawOverride); + } + int side; + switch (split[1]) { + case SIDE_STRING_LEFT -> side = BOUNDS_POSITION_LEFT; + case SIDE_STRING_TOP -> side = BOUNDS_POSITION_TOP; + case SIDE_STRING_RIGHT -> side = BOUNDS_POSITION_RIGHT; + case SIDE_STRING_BOTTOM -> side = BOUNDS_POSITION_BOTTOM; + default -> throw new IllegalArgumentException("Invalid side override definition: " + + rawOverride); + } + override[rotation] = side; + } + return override; + } + /** * Creates the display cutout according to * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest @@ -1060,7 +1201,8 @@ public final class DisplayCutout { getDisplayCutoutApproximationRect(res, displayUniqueId), physicalDisplayWidth, physicalDisplayHeight, displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT, - getWaterfallInsets(res, displayUniqueId)).second; + getWaterfallInsets(res, displayUniqueId), + getDisplayCutoutSideOverrides(res, displayUniqueId)).second; } /** @@ -1070,17 +1212,17 @@ public final class DisplayCutout { */ @VisibleForTesting(visibility = PRIVATE) public static DisplayCutout fromSpec(String pathSpec, int displayWidth, - int displayHeight, float density, Insets waterfallInsets) { + int displayHeight, float density, Insets waterfallInsets, int[] sideOverrides) { return pathAndDisplayCutoutFromSpec( pathSpec, null, displayWidth, displayHeight, displayWidth, displayHeight, density, - waterfallInsets).second; + waterfallInsets, sideOverrides).second; } /** * Gets the cutout path and the corresponding DisplayCutout instance from the spec string. * - * @param pathSpec the spec string read from config_mainBuiltInDisplayCutout. - * @param rectSpec the spec string read from config_mainBuiltInDisplayCutoutRectApproximation. + * @param pathSpec the spec string read from config for certain display. + * @param rectSpec the rect approximation spec string read from config for certain display. * @param physicalDisplayWidth the max physical display width the display supports. * @param physicalDisplayHeight the max physical display height the display supports. * @param displayWidth the display width. @@ -1091,7 +1233,8 @@ public final class DisplayCutout { */ private static Pair<Path, DisplayCutout> pathAndDisplayCutoutFromSpec( String pathSpec, String rectSpec, int physicalDisplayWidth, int physicalDisplayHeight, - int displayWidth, int displayHeight, float density, Insets waterfallInsets) { + int displayWidth, int displayHeight, float density, Insets waterfallInsets, + int[] sideOverrides) { // Always use the rect approximation spec to create the cutout if it's not null because // transforming and sending a Region constructed from a path is very costly. String spec = rectSpec != null ? rectSpec : pathSpec; @@ -1107,7 +1250,8 @@ public final class DisplayCutout { && sCachedDisplayHeight == displayHeight && sCachedDensity == density && waterfallInsets.equals(sCachedWaterfallInsets) - && sCachedPhysicalPixelDisplaySizeRatio == physicalPixelDisplaySizeRatio) { + && sCachedPhysicalPixelDisplaySizeRatio == physicalPixelDisplaySizeRatio + && Arrays.equals(sCachedSideOverrides, sideOverrides)) { return sCachedCutout; } } @@ -1123,7 +1267,6 @@ public final class DisplayCutout { final Rect boundRight = cutoutSpec.getRightBound(); final Rect boundBottom = cutoutSpec.getBottomBound(); - if (!waterfallInsets.equals(Insets.NONE)) { safeInset.set( Math.max(waterfallInsets.left, safeInset.left), @@ -1135,10 +1278,21 @@ public final class DisplayCutout { final CutoutPathParserInfo cutoutPathParserInfo = new CutoutPathParserInfo( displayWidth, displayHeight, physicalDisplayWidth, physicalDisplayHeight, density, pathSpec.trim(), ROTATION_0, 1f /* scale */, physicalPixelDisplaySizeRatio); + final int sideOverride = getSideOverride(sideOverrides, ROTATION_0); + final Rect[] bounds = new Bounds(boundLeft, boundTop, boundRight, boundBottom, false) + .getRects(); + final int rotateDistance = getRotationToOverride(sideOverride, bounds, + ROTATION_0 /* defaultRotation */); + if (rotateDistance != ROTATION_0) { + Collections.rotate(Arrays.asList(bounds), rotateDistance); + } + final Rect safeInsets = DisplayCutout.computeSafeInsets(displayWidth, displayHeight, + waterfallInsets, bounds); + final DisplayCutout cutout = new DisplayCutout(safeInsets, waterfallInsets, + new Bounds(bounds[BOUNDS_POSITION_LEFT], bounds[BOUNDS_POSITION_TOP], + bounds[BOUNDS_POSITION_RIGHT], bounds[BOUNDS_POSITION_BOTTOM], false), + cutoutPathParserInfo, sideOverrides); - final DisplayCutout cutout = new DisplayCutout( - safeInset, waterfallInsets, boundLeft, boundTop, boundRight, boundBottom, - cutoutPathParserInfo , false /* copyArguments */); final Pair<Path, DisplayCutout> result = new Pair<>(cutoutSpec.getPath(), cutout); synchronized (CACHE_LOCK) { sCachedSpec = spec; @@ -1148,6 +1302,7 @@ public final class DisplayCutout { sCachedCutout = result; sCachedWaterfallInsets = waterfallInsets; sCachedPhysicalPixelDisplaySizeRatio = physicalPixelDisplaySizeRatio; + sCachedSideOverrides = sideOverrides; } return result; } @@ -1181,7 +1336,10 @@ public final class DisplayCutout { if (newBounds[i].isEmpty()) continue; RotationUtils.rotateBounds(newBounds[i], displayBounds, rotation); } - Collections.rotate(Arrays.asList(newBounds), -rotation); + final int defaultRotation = -rotation; + final int override = getSideOverride(mSideOverrides, toRotation); + Collections.rotate(Arrays.asList(newBounds), + getRotationToOverride(override, newBounds, defaultRotation)); final CutoutPathParserInfo info = getCutoutPathParserInfo(); final CutoutPathParserInfo newInfo = new CutoutPathParserInfo( info.getDisplayWidth(), info.getDisplayHeight(), info.getPhysicalDisplayWidth(), @@ -1193,51 +1351,87 @@ public final class DisplayCutout { final DisplayCutout tmp = DisplayCutout.constructDisplayCutout(newBounds, waterfallInsets, newInfo); final Rect safeInsets = DisplayCutout.computeSafeInsets(endWidth, endHeight, tmp); + tmp.mSideOverrides = mSideOverrides; return tmp.replaceSafeInsets(safeInsets); } + private static int getSideOverride(int[] sideOverrides, @Rotation int rotation) { + if (sideOverrides == null || sideOverrides.length != 4) { + return INVALID_SIDE_OVERRIDE; + } + return sideOverrides[rotation]; + } + + /** @return the rotation needed to rotate from the original side to the overridden one. */ + private static @Rotation int getRotationToOverride(int sideOverride, Rect[] bounds, + @Rotation int defaultRotation) { + if (sideOverride == INVALID_SIDE_OVERRIDE) { + return defaultRotation; + } + int side = -1; + for (int i = 0; i <= BOUNDS_POSITION_BOTTOM; i++) { + if (bounds[i].isEmpty()) { + continue; + } + if (side != -1) { + // We don't rotate at all when there are multiple non empty cutout bounds. + return defaultRotation; + } + side = i; + } + if (side == -1) { + return defaultRotation; + } + int rotation = sideOverride - side; + if (rotation < 0) { + rotation += 4; + } + return rotation; + } + /** * Compute the insets derived from a cutout. This is usually used to populate the safe-insets * of the cutout via {@link #replaceSafeInsets}. * @hide */ public static Rect computeSafeInsets(int displayW, int displayH, DisplayCutout cutout) { + return computeSafeInsets(displayW, displayH, cutout.getWaterfallInsets(), + cutout.getBoundingRectsAll()); + } + + private static Rect computeSafeInsets(int displayW, int displayH, Insets waterFallInsets, + Rect[] bounds) { if (displayW == displayH) { throw new UnsupportedOperationException("not implemented: display=" + displayW + "x" - + displayH + " cutout=" + cutout); + + displayH + " bounding rects=" + Arrays.toString(bounds)); } - int leftInset = Math.max(cutout.getWaterfallInsets().left, findCutoutInsetForSide( - displayW, displayH, cutout.getBoundingRectLeft(), Gravity.LEFT)); - int topInset = Math.max(cutout.getWaterfallInsets().top, findCutoutInsetForSide( - displayW, displayH, cutout.getBoundingRectTop(), Gravity.TOP)); - int rightInset = Math.max(cutout.getWaterfallInsets().right, findCutoutInsetForSide( - displayW, displayH, cutout.getBoundingRectRight(), Gravity.RIGHT)); - int bottomInset = Math.max(cutout.getWaterfallInsets().bottom, findCutoutInsetForSide( - displayW, displayH, cutout.getBoundingRectBottom(), Gravity.BOTTOM)); + int leftInset = Math.max(waterFallInsets.left, findCutoutInsetForSide( + displayW, displayH, bounds[BOUNDS_POSITION_LEFT], Gravity.LEFT)); + int topInset = Math.max(waterFallInsets.top, findCutoutInsetForSide( + displayW, displayH, bounds[BOUNDS_POSITION_TOP], Gravity.TOP)); + int rightInset = Math.max(waterFallInsets.right, findCutoutInsetForSide( + displayW, displayH, bounds[BOUNDS_POSITION_RIGHT], Gravity.RIGHT)); + int bottomInset = Math.max(waterFallInsets.bottom, findCutoutInsetForSide( + displayW, displayH, bounds[BOUNDS_POSITION_BOTTOM], Gravity.BOTTOM)); return new Rect(leftInset, topInset, rightInset, bottomInset); } - private static int findCutoutInsetForSide(int displayW, int displayH, Rect boundingRect, - int gravity) { + private static int findCutoutInsetForSide(int displayW, int displayH, + @NonNull Rect boundingRect, int gravity) { if (boundingRect.isEmpty()) { return 0; } int inset = 0; - switch (gravity) { - case Gravity.TOP: - return Math.max(inset, boundingRect.bottom); - case Gravity.BOTTOM: - return Math.max(inset, displayH - boundingRect.top); - case Gravity.LEFT: - return Math.max(inset, boundingRect.right); - case Gravity.RIGHT: - return Math.max(inset, displayW - boundingRect.left); - default: - throw new IllegalArgumentException("unknown gravity: " + gravity); - } + return switch (gravity) { + case Gravity.TOP -> Math.max(inset, boundingRect.bottom); + case Gravity.BOTTOM -> Math.max(inset, displayH - boundingRect.top); + case Gravity.LEFT -> Math.max(inset, boundingRect.right); + case Gravity.RIGHT -> Math.max(inset, displayW - boundingRect.left); + default -> throw new IllegalArgumentException("unknown gravity: " + gravity); + }; } /** @@ -1293,6 +1487,7 @@ public final class DisplayCutout { out.writeInt(cutout.mCutoutPathParserInfo.getRotation()); out.writeFloat(cutout.mCutoutPathParserInfo.getScale()); out.writeFloat(cutout.mCutoutPathParserInfo.getPhysicalPixelDisplaySizeRatio()); + out.writeIntArray(cutout.mSideOverrides); } } @@ -1348,9 +1543,10 @@ public final class DisplayCutout { final CutoutPathParserInfo info = new CutoutPathParserInfo( displayWidth, displayHeight, physicalDisplayWidth, physicalDisplayHeight, density, cutoutSpec, rotation, scale, physicalPixelDisplaySizeRatio); + final int[] sideOverrides = in.createIntArray(); - return new DisplayCutout( - safeInsets, waterfallInsets, bounds, info, false /* copyArguments */); + return new DisplayCutout(safeInsets, waterfallInsets, + new Bounds(bounds, false /* copyArguments */), info, sideOverrides); } public DisplayCutout get() { @@ -1382,8 +1578,10 @@ public final class DisplayCutout { mInner.mCutoutPathParserInfo.getRotation(), scale, mInner.mCutoutPathParserInfo.getPhysicalPixelDisplaySizeRatio()); + final int[] sideOverrides = mInner.mSideOverrides; - mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds, info); + mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds, info, + sideOverrides); } @Override diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 19e6836ed261..9c430cd4acb4 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -54,6 +54,7 @@ public abstract class InputEventReceiver { InputChannel inputChannel, MessageQueue messageQueue); private static native void nativeDispose(long receiverPtr); private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled); + private static native boolean nativeProbablyHasInput(long receiverPtr); private static native void nativeReportTimeline(long receiverPtr, int inputEventId, long gpuCompletedTime, long presentTime); private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr, @@ -92,6 +93,17 @@ public abstract class InputEventReceiver { } /** + * Checks the receiver for input availability. + * May return false negatives. + */ + public boolean probablyHasInput() { + if (mReceiverPtr == 0) { + return false; + } + return nativeProbablyHasInput(mReceiverPtr); + } + + /** * Disposes the receiver. * Must be called on the same Looper thread to which the receiver is attached. */ diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index ad0bf7c95c70..785055441d59 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -274,7 +274,8 @@ public class Surface implements Parcelable { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"FRAME_RATE_CATEGORY_"}, value = {FRAME_RATE_CATEGORY_DEFAULT, FRAME_RATE_CATEGORY_NO_PREFERENCE, - FRAME_RATE_CATEGORY_LOW, FRAME_RATE_CATEGORY_NORMAL, FRAME_RATE_CATEGORY_HIGH}) + FRAME_RATE_CATEGORY_LOW, FRAME_RATE_CATEGORY_NORMAL, + FRAME_RATE_CATEGORY_HIGH_HINT, FRAME_RATE_CATEGORY_HIGH}) public @interface FrameRateCategory {} // From native_window.h or window.h. Keep these in sync. @@ -308,11 +309,21 @@ public class Surface implements Parcelable { public static final int FRAME_RATE_CATEGORY_NORMAL = 3; /** + * Hints that, as a result of a user interaction, an animation is likely to start. + * This category is a signal that a user interaction heuristic determined the need of a + * high refresh rate, and is not an explicit request from the app. + * As opposed to {@link #FRAME_RATE_CATEGORY_HIGH}, this vote may be ignored in favor of + * more explicit votes. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_HIGH_HINT = 4; + + /** * Indicates a frame rate suitable for animations that require a high frame rate, which may * increase smoothness but may also increase power usage. * @hide */ - public static final int FRAME_RATE_CATEGORY_HIGH = 4; + public static final int FRAME_RATE_CATEGORY_HIGH = 5; /** * Create an empty surface, which will later be filled in by readFromParcel(). diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ec994590e339..2b99e1e9f79b 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -32,6 +32,7 @@ import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_H import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; +import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout; import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; import static android.view.flags.Flags.viewVelocityApi; @@ -955,6 +956,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static boolean sAlwaysRemeasureExactly = false; /** + * When true makes it possible to use onMeasure caches also when the force layout flag is + * enabled. This helps avoiding multiple measures in the same frame with the same dimensions. + */ + private static boolean sUseMeasureCacheDuringForceLayoutFlagValue; + + /** * Allow setForeground/setBackground to be called (and ignored) on a textureview, * without throwing */ @@ -2396,6 +2403,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision(); + sUseMeasureCacheDuringForceLayoutFlagValue = enableUseMeasureCacheDuringForceLayout(); } /** @@ -10760,11 +10768,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return; } - session.internalNotifyViewTreeEvent(/* started= */ true); + session.notifyViewTreeEvent(/* started= */ true); try { dispatchProvideContentCaptureStructure(); } finally { - session.internalNotifyViewTreeEvent(/* started= */ false); + session.notifyViewTreeEvent(/* started= */ false); } } @@ -22848,6 +22856,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Determines whether an unprocessed input event is available on the window. + * + * This is only a performance hint (a.k.a. the Input Hint) and may return false negative + * results. Callers should not rely on availability of the input event based on the return + * value of this method. + * + * The Input Hint functionality is experimental, and can be removed in the future OS releases. + * + * This method only returns nontrivial results on a View that is attached to a Window. Such View + * can be acquired using `Activity.getWindow().getDecorView()`, and only after the view + * hierarchy is attached (via {@link android.app.Activity#setContentView(android.view.View)}). + * + * In multi-window mode the View can provide the Input Hint only for the window it is attached + * to. Therefore, checking input availability for the whole application would require asking + * for the hint from more than one View. + * + * The initial implementation does not return false positives, but callers should not rely on + * it: false positives may occur in future OS releases. + * + * @hide + */ + public boolean probablyHasInput() { + ViewRootImpl viewRootImpl = getViewRootImpl(); + if (viewRootImpl == null) { + return false; + } + return viewRootImpl.probablyHasInput(); + } + + /** * Destroys all hardware rendering resources. This method is invoked * when the system needs to reclaim resources. Upon execution of this * method, you should free any OpenGL resources created by the view. @@ -27417,7 +27455,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, resolveRtlPropertiesIfNeeded(); - int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); + int cacheIndex; + if (sUseMeasureCacheDuringForceLayoutFlagValue) { + cacheIndex = mMeasureCache.indexOfKey(key); + } else { + cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); + } + if (cacheIndex < 0 || sIgnoreMeasureCache) { if (isTraversalTracingEnabled()) { Trace.beginSection(mTracingStrings.onMeasure); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 287c7b29813f..fbefbf31a9f0 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -49,6 +49,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.os.SystemClock; +import android.service.autofill.Flags; import android.util.AttributeSet; import android.util.IntArray; import android.util.Log; @@ -3752,7 +3753,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager && !child.isActivityDeniedForAutofillForUnimportantView()) || (shouldIncludeAllChildrenViewWithAutofillTypeNotNone(afm) && child.getAutofillType() != AUTOFILL_TYPE_NONE) - || shouldIncludeAllChildrenViews(afm)){ + || shouldIncludeAllChildrenViews(afm) + || (Flags.includeInvisibleViewGroupInAssistStructure() + && child instanceof ViewGroup && child.getVisibility() != View.VISIBLE)) { + // If the child is a ViewGroup object and its visibility is not visible, include + // it as part of the assist structure. The children of these invisible ViewGroup + // objects are parsed and included in the assist structure. When the Autofill + // Provider determines the visibility of these children, it looks at their + // visibility as well as their parent's visibility. Omitting invisible parents + // will lead to the Autofill Provider incorrectly assuming that these children + // of invisible parents are actually visible. list.add(child); } else if (child instanceof ViewGroup) { ((ViewGroup) child).populateChildrenForAutofill(list, flags); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2babf1c8d5b3..8529b4e044fa 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -209,7 +209,6 @@ import android.view.animation.Interpolator; import android.view.autofill.AutofillManager; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; -import android.view.contentcapture.MainContentCaptureSession; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputMethodManager; import android.widget.Scroller; @@ -4103,7 +4102,7 @@ public final class ViewRootImpl implements ViewParent, final ContentCaptureManager manager = mAttachInfo.mContentCaptureManager; if (manager != null && mAttachInfo.mContentCaptureEvents != null) { - final MainContentCaptureSession session = manager.getMainContentCaptureSession(); + final ContentCaptureSession session = manager.getMainContentCaptureSession(); session.notifyContentCaptureEvents(mAttachInfo.mContentCaptureEvents); } mAttachInfo.mContentCaptureEvents = null; @@ -5020,7 +5019,7 @@ public final class ViewRootImpl implements ViewParent, // Initial dispatch of window bounds to content capture if (mAttachInfo.mContentCaptureManager != null) { - MainContentCaptureSession session = + ContentCaptureSession session = mAttachInfo.mContentCaptureManager.getMainContentCaptureSession(); session.notifyWindowBoundsChanged(session.getId(), getConfiguration().windowConfiguration.getBounds()); @@ -8805,7 +8804,7 @@ public final class ViewRootImpl implements ViewParent, mSurfaceControl.setTransformHint(transformHint); if (mAttachInfo.mContentCaptureManager != null) { - MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager + ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager .getMainContentCaptureSession(); mainSession.notifyWindowBoundsChanged(mainSession.getId(), getConfiguration().windowConfiguration.getBounds()); @@ -10555,6 +10554,18 @@ public final class ViewRootImpl implements ViewParent, } /** + * Checks the input event receiver for input availability. + * May return false negatives. + * @hide + */ + public boolean probablyHasInput() { + if (mInputEventReceiver == null) { + return false; + } + return mInputEventReceiver.probablyHasInput(); + } + + /** * Adds a scroll capture callback to this window. * * @param callback the callback to add diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index a38092a21178..49d2ceb8fecf 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -2067,10 +2067,10 @@ public final class AccessibilityManager { } /** - * Start sequence (infinite) type of flash notification. Use - * {@code Context.getOpPackageName()} as the identifier of this flash notification. + * Start sequence (infinite) type of flash notification. Use {@code Context} to retrieve the + * package name as the identifier of this flash notification. * The notification can be cancelled later by calling {@link #stopFlashNotificationSequence} - * with same {@code Context.getOpPackageName()}. + * with same {@code Context}. * If the binder associated with this {@link AccessibilityManager} instance dies then the * sequence will stop automatically. It is strongly recommended to call * {@link #stopFlashNotificationSequence} within a reasonable amount of time after calling @@ -2104,8 +2104,8 @@ public final class AccessibilityManager { } /** - * Stop sequence (infinite) type of flash notification. The flash notification with - * {@code Context.getOpPackageName()} as identifier will be stopped if exist. + * Stop sequence (infinite) type of flash notification. The flash notification with the + * package name retrieved from {@code Context} as identifier will be stopped if exist. * It is strongly recommended to call this method within a reasonable amount of time after * calling {@link #startFlashNotificationSequence} method. * diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java index 44b4353871a2..70c899f1efc7 100644 --- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -17,10 +17,16 @@ package android.view.contentcapture; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.ComponentName; import android.graphics.Insets; +import android.graphics.Rect; +import android.os.IBinder; +import android.util.SparseArray; import android.view.autofill.AutofillId; import android.view.contentcapture.ViewNode.ViewStructureImpl; +import java.util.ArrayList; + /** * A session that is explicitly created by the app (and hence is a descendant of * {@link MainContentCaptureSession}). @@ -40,17 +46,30 @@ final class ChildContentCaptureSession extends ContentCaptureSession { } @Override - MainContentCaptureSession getMainCaptureSession() { - if (mParent instanceof MainContentCaptureSession) { - return (MainContentCaptureSession) mParent; - } + ContentCaptureSession getMainCaptureSession() { return mParent.getMainCaptureSession(); } @Override + void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, + @NonNull ComponentName component, int flags) { + getMainCaptureSession().start(token, shareableActivityToken, component, flags); + } + + @Override + boolean isDisabled() { + return getMainCaptureSession().isDisabled(); + } + + @Override + boolean setDisabled(boolean disabled) { + return getMainCaptureSession().setDisabled(disabled); + } + + @Override ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) { final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext); - getMainCaptureSession().notifyChildSessionStarted(mId, child.mId, clientContext); + internalNotifyChildSessionStarted(mId, child.mId, clientContext); return child; } @@ -61,51 +80,80 @@ final class ChildContentCaptureSession extends ContentCaptureSession { @Override public void updateContentCaptureContext(@Nullable ContentCaptureContext context) { - getMainCaptureSession().notifyContextUpdated(mId, context); + internalNotifyContextUpdated(mId, context); } @Override void onDestroy() { - getMainCaptureSession().notifyChildSessionFinished(mParent.mId, mId); + internalNotifyChildSessionFinished(mParent.mId, mId); + } + + @Override + void internalNotifyChildSessionStarted(int parentSessionId, int childSessionId, + @NonNull ContentCaptureContext clientContext) { + getMainCaptureSession() + .internalNotifyChildSessionStarted(parentSessionId, childSessionId, clientContext); + } + + @Override + void internalNotifyChildSessionFinished(int parentSessionId, int childSessionId) { + getMainCaptureSession().internalNotifyChildSessionFinished(parentSessionId, childSessionId); + } + + @Override + void internalNotifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) { + getMainCaptureSession().internalNotifyContextUpdated(sessionId, context); } @Override - void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) { - getMainCaptureSession().notifyViewAppeared(mId, node); + void internalNotifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) { + getMainCaptureSession().internalNotifyViewAppeared(sessionId, node); } @Override - void internalNotifyViewDisappeared(@NonNull AutofillId id) { - getMainCaptureSession().notifyViewDisappeared(mId, id); + void internalNotifyViewDisappeared(int sessionId, @NonNull AutofillId id) { + getMainCaptureSession().internalNotifyViewDisappeared(sessionId, id); } @Override - void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text) { - getMainCaptureSession().notifyViewTextChanged(mId, id, text); + void internalNotifyViewTextChanged( + int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) { + getMainCaptureSession().internalNotifyViewTextChanged(sessionId, id, text); } @Override - void internalNotifyViewInsetsChanged(@NonNull Insets viewInsets) { - getMainCaptureSession().notifyViewInsetsChanged(mId, viewInsets); + void internalNotifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) { + getMainCaptureSession().internalNotifyViewInsetsChanged(mId, viewInsets); } @Override - public void internalNotifyViewTreeEvent(boolean started) { - getMainCaptureSession().notifyViewTreeEvent(mId, started); + public void internalNotifyViewTreeEvent(int sessionId, boolean started) { + getMainCaptureSession().internalNotifyViewTreeEvent(sessionId, started); } @Override void internalNotifySessionResumed() { - getMainCaptureSession().notifySessionResumed(); + getMainCaptureSession().internalNotifySessionResumed(); } @Override void internalNotifySessionPaused() { - getMainCaptureSession().notifySessionPaused(); + getMainCaptureSession().internalNotifySessionPaused(); } @Override boolean isContentCaptureEnabled() { return getMainCaptureSession().isContentCaptureEnabled(); } + + @Override + public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) { + getMainCaptureSession().notifyWindowBoundsChanged(sessionId, bounds); + } + + @Override + public void notifyContentCaptureEvents( + @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) { + getMainCaptureSession().notifyContentCaptureEvents(contentCaptureEvents); + } } diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index a8297472445f..bcef37f6e0c4 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -499,10 +499,14 @@ public final class ContentCaptureManager { @Nullable @GuardedBy("mLock") - private Handler mHandler; + private Handler mUiHandler; + + @Nullable + @GuardedBy("mLock") + private Handler mContentCaptureHandler; @GuardedBy("mLock") - private MainContentCaptureSession mMainSession; + private ContentCaptureSession mMainSession; @Nullable // set on-demand by addDumpable() private Dumper mDumpable; @@ -587,11 +591,10 @@ public final class ContentCaptureManager { */ @NonNull @UiThread - public MainContentCaptureSession getMainContentCaptureSession() { + public ContentCaptureSession getMainContentCaptureSession() { synchronized (mLock) { if (mMainSession == null) { - mMainSession = new MainContentCaptureSession( - mContext, this, prepareContentCaptureHandler(), mService); + mMainSession = prepareMainSession(); if (sVerbose) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession); } return mMainSession; @@ -600,15 +603,36 @@ public final class ContentCaptureManager { @NonNull @GuardedBy("mLock") + private ContentCaptureSession prepareMainSession() { + if (runOnBackgroundThreadEnabled()) { + return new MainContentCaptureSessionV2( + mContext, + this, + prepareUiHandler(), + prepareContentCaptureHandler(), + mService + ); + } else { + return new MainContentCaptureSession(mContext, this, prepareUiHandler(), mService); + } + } + + @NonNull + @GuardedBy("mLock") private Handler prepareContentCaptureHandler() { - if (mHandler == null) { - if (runOnBackgroundThreadEnabled()) { - mHandler = BackgroundThread.getHandler(); - } else { - mHandler = Handler.createAsync(Looper.getMainLooper()); - } + if (mContentCaptureHandler == null) { + mContentCaptureHandler = BackgroundThread.getHandler(); + } + return mContentCaptureHandler; + } + + @NonNull + @GuardedBy("mLock") + private Handler prepareUiHandler() { + if (mUiHandler == null) { + mUiHandler = Handler.createAsync(Looper.getMainLooper()); } - return mHandler; + return mUiHandler; } /** @hide */ @@ -726,7 +750,7 @@ public final class ContentCaptureManager { public boolean isContentCaptureEnabled() { if (mOptions.lite) return false; - final MainContentCaptureSession mainSession; + final ContentCaptureSession mainSession; synchronized (mLock) { mainSession = mMainSession; } @@ -777,7 +801,7 @@ public final class ContentCaptureManager { Log.d(TAG, "setContentCaptureEnabled(): setting to " + enabled + " for " + mContext); } - MainContentCaptureSession mainSession; + ContentCaptureSession mainSession; synchronized (mLock) { if (enabled) { mFlags &= ~ContentCaptureContext.FLAG_DISABLED_BY_APP; @@ -803,7 +827,7 @@ public final class ContentCaptureManager { final boolean flagSecureEnabled = (params.flags & WindowManager.LayoutParams.FLAG_SECURE) != 0; - MainContentCaptureSession mainSession; + ContentCaptureSession mainSession; boolean alreadyDisabledByApp; synchronized (mLock) { alreadyDisabledByApp = (mFlags & ContentCaptureContext.FLAG_DISABLED_BY_APP) != 0; diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index bb815c0e8317..0ca36ba28e3a 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -27,9 +27,13 @@ import android.annotation.Nullable; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; +import android.content.ComponentName; import android.graphics.Insets; +import android.graphics.Rect; +import android.os.IBinder; import android.util.DebugUtils; import android.util.Log; +import android.util.SparseArray; import android.view.View; import android.view.ViewStructure; import android.view.autofill.AutofillId; @@ -37,6 +41,7 @@ import android.view.contentcapture.ViewNode.ViewStructureImpl; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.IResultReceiver; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; @@ -60,6 +65,18 @@ public abstract class ContentCaptureSession implements AutoCloseable { private static final SecureRandom ID_GENERATOR = new SecureRandom(); /** + * Name of the {@link IResultReceiver} extra used to pass the binder interface to the service. + * @hide + */ + public static final String EXTRA_BINDER = "binder"; + + /** + * Name of the {@link IResultReceiver} extra used to pass the content capture enabled state. + * @hide + */ + public static final String EXTRA_ENABLED_STATE = "enabled"; + + /** * Initial state, when there is no session. * * @hide @@ -262,7 +279,19 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** @hide */ @NonNull - abstract MainContentCaptureSession getMainCaptureSession(); + abstract ContentCaptureSession getMainCaptureSession(); + + abstract void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, + @NonNull ComponentName component, int flags); + + abstract boolean isDisabled(); + + /** + * Sets the disabled state of content capture. + * + * @return whether disabled state was changed. + */ + abstract boolean setDisabled(boolean disabled); /** * Gets the id used to identify this session. @@ -400,10 +429,11 @@ public abstract class ContentCaptureSession implements AutoCloseable { throw new IllegalArgumentException("Invalid node class: " + node.getClass()); } - internalNotifyViewAppeared((ViewStructureImpl) node); + internalNotifyViewAppeared(mId, (ViewStructureImpl) node); } - abstract void internalNotifyViewAppeared(@NonNull ViewNode.ViewStructureImpl node); + abstract void internalNotifyViewAppeared( + int sessionId, @NonNull ViewNode.ViewStructureImpl node); /** * Notifies the Content Capture Service that a node has been removed from the view structure. @@ -420,10 +450,10 @@ public abstract class ContentCaptureSession implements AutoCloseable { Objects.requireNonNull(id); if (!isContentCaptureEnabled()) return; - internalNotifyViewDisappeared(id); + internalNotifyViewDisappeared(mId, id); } - abstract void internalNotifyViewDisappeared(@NonNull AutofillId id); + abstract void internalNotifyViewDisappeared(int sessionId, @NonNull AutofillId id); /** * Notifies the Content Capture Service that a list of nodes has appeared in the view structure. @@ -445,12 +475,12 @@ public abstract class ContentCaptureSession implements AutoCloseable { } } - internalNotifyViewTreeEvent(/* started= */ true); + internalNotifyViewTreeEvent(mId, /* started= */ true); for (int i = 0; i < appearedNodes.size(); i++) { ViewStructure v = appearedNodes.get(i); - internalNotifyViewAppeared((ViewStructureImpl) v); + internalNotifyViewAppeared(mId, (ViewStructureImpl) v); } - internalNotifyViewTreeEvent(/* started= */ false); + internalNotifyViewTreeEvent(mId, /* started= */ false); } /** @@ -476,15 +506,15 @@ public abstract class ContentCaptureSession implements AutoCloseable { if (!isContentCaptureEnabled()) return; if (CompatChanges.isChangeEnabled(NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS)) { - internalNotifyViewTreeEvent(/* started= */ true); + internalNotifyViewTreeEvent(mId, /* started= */ true); } // TODO(b/123036895): use a internalNotifyViewsDisappeared that optimizes how the event is // parcelized for (long id : virtualIds) { - internalNotifyViewDisappeared(new AutofillId(hostId, id, mId)); + internalNotifyViewDisappeared(mId, new AutofillId(hostId, id, mId)); } if (CompatChanges.isChangeEnabled(NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS)) { - internalNotifyViewTreeEvent(/* started= */ false); + internalNotifyViewTreeEvent(mId, /* started= */ false); } } @@ -499,10 +529,10 @@ public abstract class ContentCaptureSession implements AutoCloseable { if (!isContentCaptureEnabled()) return; - internalNotifyViewTextChanged(id, text); + internalNotifyViewTextChanged(mId, id, text); } - abstract void internalNotifyViewTextChanged(@NonNull AutofillId id, + abstract void internalNotifyViewTextChanged(int sessionId, @NonNull AutofillId id, @Nullable CharSequence text); /** @@ -513,13 +543,18 @@ public abstract class ContentCaptureSession implements AutoCloseable { if (!isContentCaptureEnabled()) return; - internalNotifyViewInsetsChanged(viewInsets); + internalNotifyViewInsetsChanged(mId, viewInsets); } - abstract void internalNotifyViewInsetsChanged(@NonNull Insets viewInsets); + abstract void internalNotifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets); + + /** @hide */ + public void notifyViewTreeEvent(boolean started) { + internalNotifyViewTreeEvent(mId, started); + } /** @hide */ - public abstract void internalNotifyViewTreeEvent(boolean started); + abstract void internalNotifyViewTreeEvent(int sessionId, boolean started); /** * Notifies the Content Capture Service that a session has resumed. @@ -543,6 +578,21 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void internalNotifySessionPaused(); + abstract void internalNotifyChildSessionStarted(int parentSessionId, int childSessionId, + @NonNull ContentCaptureContext clientContext); + + abstract void internalNotifyChildSessionFinished(int parentSessionId, int childSessionId); + + abstract void internalNotifyContextUpdated( + int sessionId, @Nullable ContentCaptureContext context); + + /** @hide */ + public abstract void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds); + + /** @hide */ + public abstract void notifyContentCaptureEvents( + @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents); + /** * Creates a {@link ViewStructure} for a "standard" view. * diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 19ba316257a3..a90c94eac967 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -31,7 +31,6 @@ import static android.view.contentcapture.ContentCaptureHelper.getSanitizedStrin import static android.view.contentcapture.ContentCaptureHelper.sDebug; import static android.view.contentcapture.ContentCaptureHelper.sVerbose; import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE; -import static android.view.contentcapture.flags.Flags.runOnBackgroundThreadEnabled; import android.annotation.NonNull; import android.annotation.Nullable; @@ -70,10 +69,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +// TODO(b/309411951): Replace V2 as the only main session once the experiment is done. /** * Main session associated with a context. * @@ -82,6 +81,7 @@ import java.util.concurrent.atomic.AtomicInteger; * * @hide */ +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public final class MainContentCaptureSession extends ContentCaptureSession { private static final String TAG = MainContentCaptureSession.class.getSimpleName(); @@ -97,18 +97,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { */ private static final int MSG_FLUSH = 1; - /** - * Name of the {@link IResultReceiver} extra used to pass the binder interface to the service. - * @hide - */ - public static final String EXTRA_BINDER = "binder"; - - /** - * Name of the {@link IResultReceiver} extra used to pass the content capture enabled state. - * @hide - */ - public static final String EXTRA_ENABLED_STATE = "enabled"; - @NonNull private final AtomicBoolean mDisabled = new AtomicBoolean(false); @@ -154,15 +142,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { public ComponentName mComponentName; /** - * Thread-safe queue of events held to be processed as a batch. - * - * Because it is not guaranteed that the events will be enqueued from a single thread, the - * implementation must be thread-safe to prevent unexpected behaviour. - */ - @NonNull - private final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue; - - /** * List of events held to be sent to the {@link ContentCaptureService} as a batch. * * @hide @@ -221,14 +200,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { binder = resultData.getBinder(EXTRA_BINDER); if (binder == null) { Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result"); - mainSession.runOnContentCaptureThread(() -> mainSession.resetSession( + mainSession.mHandler.post(() -> mainSession.resetSession( STATE_DISABLED | STATE_INTERNAL_ERROR)); return; } } else { binder = null; } - mainSession.runOnContentCaptureThread(() -> + mainSession.mHandler.post(() -> mainSession.onSessionStarted(resultCode, binder)); } } @@ -249,39 +228,27 @@ public final class MainContentCaptureSession extends ContentCaptureSession { mFlushHistory = logHistorySize > 0 ? new LocalLog(logHistorySize) : null; mSessionStateReceiver = new SessionStateReceiver(this); - - mEventProcessQueue = new ConcurrentLinkedQueue<>(); } @Override - MainContentCaptureSession getMainCaptureSession() { + ContentCaptureSession getMainCaptureSession() { return this; } @Override ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) { final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext); - notifyChildSessionStarted(mId, child.mId, clientContext); + internalNotifyChildSessionStarted(mId, child.mId, clientContext); return child; } /** * Starts this session. */ + @Override void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, @NonNull ComponentName component, int flags) { - if (runOnBackgroundThreadEnabled()) { - runOnContentCaptureThread( - () -> startImpl(token, shareableActivityToken, component, flags)); - } else { - // Preserve the control arm behaviour. - startImpl(token, shareableActivityToken, component, flags); - } - } - - private void startImpl(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, - @NonNull ComponentName component, int flags) { - checkOnContentCaptureThread(); + checkOnUiThread(); if (!isContentCaptureEnabled()) return; if (sVerbose) { @@ -315,15 +282,17 @@ public final class MainContentCaptureSession extends ContentCaptureSession { Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e); } } + @Override void onDestroy() { - clearAndRunOnContentCaptureThread(() -> { + mHandler.removeMessages(MSG_FLUSH); + mHandler.post(() -> { try { flush(FLUSH_REASON_SESSION_FINISHED); } finally { destroySession(); } - }, MSG_FLUSH); + }); } /** @@ -336,7 +305,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void onSessionStarted(int resultCode, @Nullable IBinder binder) { - checkOnContentCaptureThread(); + checkOnUiThread(); if (binder != null) { mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder); mDirectServiceVulture = () -> { @@ -385,7 +354,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) { - checkOnContentCaptureThread(); + checkOnUiThread(); final int eventType = event.getType(); if (sVerbose) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event); if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED @@ -429,14 +398,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } private void sendContentProtectionEvent(@NonNull ContentCaptureEvent event) { - checkOnContentCaptureThread(); + checkOnUiThread(); if (mContentProtectionEventProcessor != null) { mContentProtectionEventProcessor.processEvent(event); } } private void sendContentCaptureEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) { - checkOnContentCaptureThread(); + checkOnUiThread(); final int eventType = event.getType(); final int maxBufferSize = mManager.mOptions.maxBufferSize; if (mEvents == null) { @@ -571,12 +540,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } private boolean hasStarted() { - checkOnContentCaptureThread(); + checkOnUiThread(); return mState != UNKNOWN_STATE; } private void scheduleFlush(@FlushReason int reason, boolean checkExisting) { - checkOnContentCaptureThread(); + checkOnUiThread(); if (sVerbose) { Log.v(TAG, "handleScheduleFlush(" + getDebugState(reason) + ", checkExisting=" + checkExisting); @@ -617,11 +586,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { + flushFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush)); } // Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage() - mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, flushFrequencyMs); + mHandler.postDelayed(() -> + flushIfNeeded(reason), MSG_FLUSH, flushFrequencyMs); } private void flushIfNeeded(@FlushReason int reason) { - checkOnContentCaptureThread(); + checkOnUiThread(); if (mEvents == null || mEvents.isEmpty()) { if (sVerbose) Log.v(TAG, "Nothing to flush"); return; @@ -633,16 +603,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) @Override public void flush(@FlushReason int reason) { - if (runOnBackgroundThreadEnabled()) { - runOnContentCaptureThread(() -> flushImpl(reason)); - } else { - // Preserve the control arm behaviour. - flushImpl(reason); - } - } - - private void flushImpl(@FlushReason int reason) { - checkOnContentCaptureThread(); + checkOnUiThread(); if (mEvents == null || mEvents.size() == 0) { if (sVerbose) { Log.v(TAG, "Don't flush for empty event buffer."); @@ -703,7 +664,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @Override public void updateContentCaptureContext(@Nullable ContentCaptureContext context) { - notifyContextUpdated(mId, context); + internalNotifyContextUpdated(mId, context); } /** @@ -711,7 +672,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { */ @NonNull private ParceledListSlice<ContentCaptureEvent> clearEvents() { - checkOnContentCaptureThread(); + checkOnUiThread(); // NOTE: we must save a reference to the current mEvents and then set it to to null, // otherwise clearing it would clear it in the receiving side if the service is also local. if (mEvents == null) { @@ -726,7 +687,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { /** hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void destroySession() { - checkOnContentCaptureThread(); + checkOnUiThread(); if (sDebug) { Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with " + (mEvents == null ? 0 : mEvents.size()) + " event(s) for " @@ -746,9 +707,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } mDirectServiceInterface = null; mContentProtectionEventProcessor = null; - if (runOnBackgroundThreadEnabled()) { - mEventProcessQueue.clear(); - } } // TODO(b/122454205): once we support multiple sessions, we might need to move some of these @@ -756,7 +714,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { /** @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void resetSession(int newState) { - checkOnContentCaptureThread(); + checkOnUiThread(); if (sVerbose) { Log.v(TAG, "handleResetSession(" + getActivityName() + "): from " + getStateAsString(mState) + " to " + getStateAsString(newState)); @@ -781,91 +739,22 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } @Override - void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) { - notifyViewAppeared(mId, node); - } - - @Override - void internalNotifyViewDisappeared(@NonNull AutofillId id) { - notifyViewDisappeared(mId, id); - } - - @Override - void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text) { - notifyViewTextChanged(mId, id, text); - } - - @Override - void internalNotifyViewInsetsChanged(@NonNull Insets viewInsets) { - notifyViewInsetsChanged(mId, viewInsets); - } - - @Override - public void internalNotifyViewTreeEvent(boolean started) { - notifyViewTreeEvent(mId, started); - } - - @Override - public void internalNotifySessionResumed() { - notifySessionResumed(mId); - } - - @Override - public void internalNotifySessionPaused() { - notifySessionPaused(mId); - } - - @Override - boolean isContentCaptureEnabled() { - return super.isContentCaptureEnabled() && mManager.isContentCaptureEnabled(); - } - - // Called by ContentCaptureManager.isContentCaptureEnabled - boolean isDisabled() { - return mDisabled.get(); - } - - /** - * Sets the disabled state of content capture. - * - * @return whether disabled state was changed. - */ - boolean setDisabled(boolean disabled) { - return mDisabled.compareAndSet(!disabled, disabled); - } - - // TODO(b/122454205): refactor "notifyXXXX" methods below to a common "Buffer" object that is - // shared between ActivityContentCaptureSession and ChildContentCaptureSession objects. Such - // change should also get get rid of the "internalNotifyXXXX" methods above - void notifyChildSessionStarted(int parentSessionId, int childSessionId, - @NonNull ContentCaptureContext clientContext) { - final ContentCaptureEvent event = - new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED) - .setParentSessionId(parentSessionId) - .setClientContext(clientContext); - enqueueEvent(event, FORCE_FLUSH); - } - - void notifyChildSessionFinished(int parentSessionId, int childSessionId) { - final ContentCaptureEvent event = - new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED) - .setParentSessionId(parentSessionId); - enqueueEvent(event, FORCE_FLUSH); - } - - void notifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) { + void internalNotifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) { final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED) .setViewNode(node.mNode); - enqueueEvent(event); + mHandler.post(() -> sendEvent(event)); } - void notifyViewDisappeared(int sessionId, @NonNull AutofillId id) { + @Override + void internalNotifyViewDisappeared(int sessionId, @NonNull AutofillId id) { final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED) .setAutofillId(id); - enqueueEvent(event); + mHandler.post(() -> sendEvent(event)); } - void notifyViewTextChanged(int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) { + @Override + void internalNotifyViewTextChanged( + int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) { // Since the same CharSequence instance may be reused in the TextView, we need to make // a copy of its content so that its value will not be changed by subsequent updates // in the TextView. @@ -891,113 +780,108 @@ public final class MainContentCaptureSession extends ContentCaptureSession { .setAutofillId(id).setText(eventText) .setComposingIndex(composingStart, composingEnd) .setSelectionIndex(startIndex, endIndex); - enqueueEvent(event); + mHandler.post(() -> sendEvent(event)); } - void notifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) { + @Override + void internalNotifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) { final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED) .setInsets(viewInsets); - enqueueEvent(event); + mHandler.post(() -> sendEvent(event)); } - void notifyViewTreeEvent(int sessionId, boolean started) { + @Override + public void internalNotifyViewTreeEvent(int sessionId, boolean started) { final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED; final boolean disableFlush = mManager.getFlushViewTreeAppearingEventDisabled(); final boolean forceFlush = disableFlush ? !started : FORCE_FLUSH; final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type); - enqueueEvent(event, forceFlush); + mHandler.post(() -> sendEvent(event, FORCE_FLUSH)); } - void notifySessionResumed(int sessionId) { - final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_SESSION_RESUMED); - enqueueEvent(event, FORCE_FLUSH); + @Override + public void internalNotifySessionResumed() { + final ContentCaptureEvent event = new ContentCaptureEvent(mId, TYPE_SESSION_RESUMED); + mHandler.post(() -> sendEvent(event, FORCE_FLUSH)); } - void notifySessionPaused(int sessionId) { - final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_SESSION_PAUSED); - enqueueEvent(event, FORCE_FLUSH); + @Override + public void internalNotifySessionPaused() { + final ContentCaptureEvent event = new ContentCaptureEvent(mId, TYPE_SESSION_PAUSED); + mHandler.post(() -> sendEvent(event, FORCE_FLUSH)); } - void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) { - final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED) - .setClientContext(context); - enqueueEvent(event, FORCE_FLUSH); + @Override + boolean isContentCaptureEnabled() { + return super.isContentCaptureEnabled() && mManager.isContentCaptureEnabled(); } - /** public because is also used by ViewRootImpl */ - public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) { + @Override + boolean isDisabled() { + return mDisabled.get(); + } + + @Override + boolean setDisabled(boolean disabled) { + return mDisabled.compareAndSet(!disabled, disabled); + } + + @Override + void internalNotifyChildSessionStarted(int parentSessionId, int childSessionId, + @NonNull ContentCaptureContext clientContext) { final ContentCaptureEvent event = - new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED) - .setBounds(bounds); - enqueueEvent(event); + new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED) + .setParentSessionId(parentSessionId) + .setClientContext(clientContext); + mHandler.post(() -> sendEvent(event, FORCE_FLUSH)); } - private List<ContentCaptureEvent> clearBufferEvents() { - final ArrayList<ContentCaptureEvent> bufferEvents = new ArrayList<>(); - ContentCaptureEvent event; - while ((event = mEventProcessQueue.poll()) != null) { - bufferEvents.add(event); - } - return bufferEvents; + @Override + void internalNotifyChildSessionFinished(int parentSessionId, int childSessionId) { + final ContentCaptureEvent event = + new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED) + .setParentSessionId(parentSessionId); + mHandler.post(() -> sendEvent(event, FORCE_FLUSH)); } - private void enqueueEvent(@NonNull final ContentCaptureEvent event) { - enqueueEvent(event, /* forceFlush */ false); + @Override + void internalNotifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) { + final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED) + .setClientContext(context); + mHandler.post(() -> sendEvent(event, FORCE_FLUSH)); } - /** - * Enqueue the event into {@code mEventProcessBuffer} if it is not an urgent request. Otherwise, - * clear the buffer events then starting sending out current event. - */ - private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) { - if (runOnBackgroundThreadEnabled()) { - if (forceFlush) { - // The buffer events are cleared in the same thread first to prevent new events - // being added during the time of context switch. This would disrupt the sequence - // of events. - final List<ContentCaptureEvent> batchEvents = clearBufferEvents(); - runOnContentCaptureThread(() -> { - for (int i = 0; i < batchEvents.size(); i++) { - sendEvent(batchEvents.get(i)); - } - sendEvent(event, /* forceFlush= */ true); - }); - } else { - mEventProcessQueue.offer(event); - } - } else { - mHandler.post(() -> sendEvent(event, forceFlush)); - } + @Override + public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) { + final ContentCaptureEvent event = + new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED) + .setBounds(bounds); + mHandler.post(() -> sendEvent(event)); } - /** public because is also used by ViewRootImpl */ + @Override public void notifyContentCaptureEvents( @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) { - if (runOnBackgroundThreadEnabled()) { - runOnContentCaptureThread(() -> notifyContentCaptureEventsImpl(contentCaptureEvents)); - } else { - // Preserve the control arm behaviour. - notifyContentCaptureEventsImpl(contentCaptureEvents); - } + notifyContentCaptureEventsImpl(contentCaptureEvents); } private void notifyContentCaptureEventsImpl( @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) { - checkOnContentCaptureThread(); + checkOnUiThread(); try { if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents"); } for (int i = 0; i < contentCaptureEvents.size(); i++) { int sessionId = contentCaptureEvents.keyAt(i); - notifyViewTreeEvent(sessionId, /* started= */ true); + internalNotifyViewTreeEvent(sessionId, /* started= */ true); ArrayList<Object> events = contentCaptureEvents.valueAt(i); for_each_event: for (int j = 0; j < events.size(); j++) { Object event = events.get(j); if (event instanceof AutofillId) { - notifyViewDisappeared(sessionId, (AutofillId) event); + internalNotifyViewDisappeared(sessionId, (AutofillId) event); } else if (event instanceof View) { View view = (View) event; ContentCaptureSession session = view.getContentCaptureSession(); @@ -1015,12 +899,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { view.onProvideContentCaptureStructure(structure, /* flags= */ 0); session.notifyViewAppeared(structure); } else if (event instanceof Insets) { - notifyViewInsetsChanged(sessionId, (Insets) event); + internalNotifyViewInsetsChanged(sessionId, (Insets) event); } else { Log.w(TAG, "invalid content capture event: " + event); } } - notifyViewTreeEvent(sessionId, /* started= */ false); + internalNotifyViewTreeEvent(sessionId, /* started= */ false); } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); @@ -1131,9 +1015,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession { * Therefore, accessing internal properties in {@link MainContentCaptureSession} should * always delegate to the assigned thread from {@code mHandler} for synchronization.</p> */ - private void checkOnContentCaptureThread() { - final boolean onContentCaptureThread = mHandler.getLooper().isCurrentThread(); - if (!onContentCaptureThread) { + private void checkOnUiThread() { + final boolean onUiThread = mHandler.getLooper().isCurrentThread(); + if (!onUiThread) { mWrongThreadCount.incrementAndGet(); Log.e(TAG, "MainContentCaptureSession running on " + Thread.currentThread()); } @@ -1144,38 +1028,4 @@ public final class MainContentCaptureSession extends ContentCaptureSession { Counter.logIncrement( CONTENT_CAPTURE_WRONG_THREAD_METRIC_ID, mWrongThreadCount.getAndSet(0)); } - - /** - * Ensures that {@code r} will be running on the assigned thread. - * - * <p>This is to prevent unnecessary delegation to Handler that results in fragmented runnable. - * </p> - */ - private void runOnContentCaptureThread(@NonNull Runnable r) { - if (runOnBackgroundThreadEnabled()) { - if (!mHandler.getLooper().isCurrentThread()) { - mHandler.post(r); - } else { - r.run(); - } - } else { - // Preserve the control arm behaviour to always post to the handler. - mHandler.post(r); - } - } - - private void clearAndRunOnContentCaptureThread(@NonNull Runnable r, int what) { - if (runOnBackgroundThreadEnabled()) { - if (!mHandler.getLooper().isCurrentThread()) { - mHandler.removeMessages(what); - mHandler.post(r); - } else { - r.run(); - } - } else { - // Preserve the control arm behaviour to always post to the handler. - mHandler.removeMessages(what); - mHandler.post(r); - } - } } diff --git a/core/java/android/view/contentcapture/MainContentCaptureSessionV2.java b/core/java/android/view/contentcapture/MainContentCaptureSessionV2.java new file mode 100644 index 000000000000..bf1d31c8496d --- /dev/null +++ b/core/java/android/view/contentcapture/MainContentCaptureSessionV2.java @@ -0,0 +1,1184 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.view.contentcapture; + +import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_PAUSED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_RESUMED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_INSETS_CHANGED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_WINDOW_BOUNDS_CHANGED; +import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString; +import static android.view.contentcapture.ContentCaptureHelper.sDebug; +import static android.view.contentcapture.ContentCaptureHelper.sVerbose; +import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.pm.ParceledListSlice; +import android.graphics.Insets; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.IBinder.DeathRecipient; +import android.os.RemoteException; +import android.os.Trace; +import android.service.contentcapture.ContentCaptureService; +import android.text.Selection; +import android.text.Spannable; +import android.text.TextUtils; +import android.util.LocalLog; +import android.util.Log; +import android.util.SparseArray; +import android.util.TimeUtils; +import android.view.View; +import android.view.ViewStructure; +import android.view.autofill.AutofillId; +import android.view.contentcapture.ViewNode.ViewStructureImpl; +import android.view.contentprotection.ContentProtectionEventProcessor; +import android.view.inputmethod.BaseInputConnection; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.IResultReceiver; +import com.android.modules.expresslog.Counter; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Main session associated with a context. + * + * <p>This is forked from {@link MainContentCaptureSession} to hold the logic of running operations + * in the background thread.</p> + * + * @hide + */ +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public final class MainContentCaptureSessionV2 extends ContentCaptureSession { + + private static final String TAG = MainContentCaptureSession.class.getSimpleName(); + + private static final String CONTENT_CAPTURE_WRONG_THREAD_METRIC_ID = + "content_capture.value_content_capture_wrong_thread_count"; + + // For readability purposes... + private static final boolean FORCE_FLUSH = true; + + /** + * Handler message used to flush the buffer. + */ + private static final int MSG_FLUSH = 1; + + @NonNull + private final AtomicBoolean mDisabled = new AtomicBoolean(false); + + @NonNull + private final ContentCaptureManager.StrippedContext mContext; + + @NonNull + private final ContentCaptureManager mManager; + + @NonNull + private final Handler mUiHandler; + + @NonNull + private final Handler mContentCaptureHandler; + + /** + * Interface to the system_server binder object - it's only used to start the session (and + * notify when the session is finished). + */ + @NonNull + private final IContentCaptureManager mSystemServerInterface; + + /** + * Direct interface to the service binder object - it's used to send the events, including the + * last ones (when the session is finished) + * + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @Nullable + public IContentCaptureDirectManager mDirectServiceInterface; + + @Nullable + private DeathRecipient mDirectServiceVulture; + + private int mState = UNKNOWN_STATE; + + @Nullable + private IBinder mApplicationToken; + @Nullable + private IBinder mShareableActivityToken; + + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @Nullable + public ComponentName mComponentName; + + /** + * Thread-safe queue of events held to be processed as a batch. + * + * Because it is not guaranteed that the events will be enqueued from a single thread, the + * implementation must be thread-safe to prevent unexpected behaviour. + */ + @NonNull + private final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue; + + /** + * List of events held to be sent to the {@link ContentCaptureService} as a batch. + * + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @Nullable + public ArrayList<ContentCaptureEvent> mEvents; + + // Used just for debugging purposes (on dump) + private long mNextFlush; + + /** + * Whether the next buffer flush is queued by a text changed event. + */ + private boolean mNextFlushForTextChanged = false; + + @Nullable + private final LocalLog mFlushHistory; + + private final AtomicInteger mWrongThreadCount = new AtomicInteger(0); + + /** + * Binder object used to update the session state. + */ + @NonNull + private final SessionStateReceiver mSessionStateReceiver; + + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @Nullable + public ContentProtectionEventProcessor mContentProtectionEventProcessor; + + private static class SessionStateReceiver extends IResultReceiver.Stub { + private final WeakReference<MainContentCaptureSessionV2> mMainSession; + + SessionStateReceiver(MainContentCaptureSessionV2 session) { + mMainSession = new WeakReference<>(session); + } + + @Override + public void send(int resultCode, Bundle resultData) { + final MainContentCaptureSessionV2 mainSession = mMainSession.get(); + if (mainSession == null) { + Log.w(TAG, "received result after mina session released"); + return; + } + final IBinder binder; + if (resultData != null) { + // Change in content capture enabled. + final boolean hasEnabled = resultData.getBoolean(EXTRA_ENABLED_STATE); + if (hasEnabled) { + final boolean disabled = (resultCode == RESULT_CODE_FALSE); + mainSession.mDisabled.set(disabled); + return; + } + binder = resultData.getBinder(EXTRA_BINDER); + if (binder == null) { + Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result"); + mainSession.runOnContentCaptureThread(() -> mainSession.resetSession( + STATE_DISABLED | STATE_INTERNAL_ERROR)); + return; + } + } else { + binder = null; + } + mainSession.runOnContentCaptureThread(() -> + mainSession.onSessionStarted(resultCode, binder)); + } + } + + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) + public MainContentCaptureSessionV2( + @NonNull ContentCaptureManager.StrippedContext context, + @NonNull ContentCaptureManager manager, + @NonNull Handler uiHandler, + @NonNull Handler contentCaptureHandler, + @NonNull IContentCaptureManager systemServerInterface) { + mContext = context; + mManager = manager; + mUiHandler = uiHandler; + mContentCaptureHandler = contentCaptureHandler; + mSystemServerInterface = systemServerInterface; + + final int logHistorySize = mManager.mOptions.logHistorySize; + mFlushHistory = logHistorySize > 0 ? new LocalLog(logHistorySize) : null; + + mSessionStateReceiver = new SessionStateReceiver(this); + + mEventProcessQueue = new ConcurrentLinkedQueue<>(); + } + + @Override + ContentCaptureSession getMainCaptureSession() { + return this; + } + + @Override + ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) { + final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext); + internalNotifyChildSessionStarted(mId, child.mId, clientContext); + return child; + } + + /** + * Starts this session. + */ + @Override + void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, + @NonNull ComponentName component, int flags) { + runOnContentCaptureThread( + () -> startImpl(token, shareableActivityToken, component, flags)); + } + + private void startImpl(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, + @NonNull ComponentName component, int flags) { + checkOnContentCaptureThread(); + if (!isContentCaptureEnabled()) return; + + if (sVerbose) { + Log.v(TAG, "start(): token=" + token + ", comp=" + + ComponentName.flattenToShortString(component)); + } + + if (hasStarted()) { + // TODO(b/122959591): make sure this is expected (and when), or use Log.w + if (sDebug) { + Log.d(TAG, "ignoring handleStartSession(" + token + "/" + + ComponentName.flattenToShortString(component) + " while on state " + + getStateAsString(mState)); + } + return; + } + mState = STATE_WAITING_FOR_SERVER; + mApplicationToken = token; + mShareableActivityToken = shareableActivityToken; + mComponentName = component; + + if (sVerbose) { + Log.v(TAG, "handleStartSession(): token=" + token + ", act=" + + getDebugState() + ", id=" + mId); + } + + try { + mSystemServerInterface.startSession(mApplicationToken, mShareableActivityToken, + component, mId, flags, mSessionStateReceiver); + } catch (RemoteException e) { + Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e); + } + } + @Override + void onDestroy() { + clearAndRunOnContentCaptureThread(() -> { + try { + flush(FLUSH_REASON_SESSION_FINISHED); + } finally { + destroySession(); + } + }, MSG_FLUSH); + } + + /** + * Callback from {@code system_server} after call to {@link + * IContentCaptureManager#startSession(IBinder, ComponentName, String, int, IResultReceiver)}. + * + * @param resultCode session state + * @param binder handle to {@code IContentCaptureDirectManager} + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public void onSessionStarted(int resultCode, @Nullable IBinder binder) { + checkOnContentCaptureThread(); + if (binder != null) { + mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder); + mDirectServiceVulture = () -> { + Log.w(TAG, "Keeping session " + mId + " when service died"); + mState = STATE_SERVICE_DIED; + mDisabled.set(true); + }; + try { + binder.linkToDeath(mDirectServiceVulture, 0); + } catch (RemoteException e) { + Log.w(TAG, "Failed to link to death on " + binder + ": " + e); + } + } + + if (isContentProtectionEnabled()) { + mContentProtectionEventProcessor = + new ContentProtectionEventProcessor( + mManager.getContentProtectionEventBuffer(), + mContentCaptureHandler, + mSystemServerInterface, + mComponentName.getPackageName(), + mManager.mOptions.contentProtectionOptions); + } else { + mContentProtectionEventProcessor = null; + } + + if ((resultCode & STATE_DISABLED) != 0) { + resetSession(resultCode); + } else { + mState = resultCode; + mDisabled.set(false); + // Flush any pending data immediately as buffering forced until now. + flushIfNeeded(FLUSH_REASON_SESSION_CONNECTED); + } + if (sVerbose) { + Log.v(TAG, "handleSessionStarted() result: id=" + mId + " resultCode=" + resultCode + + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get() + + ", binder=" + binder + ", events=" + (mEvents == null ? 0 : mEvents.size())); + } + } + + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public void sendEvent(@NonNull ContentCaptureEvent event) { + sendEvent(event, /* forceFlush= */ false); + } + + private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) { + checkOnContentCaptureThread(); + final int eventType = event.getType(); + if (sVerbose) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event); + if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED + && eventType != ContentCaptureEvent.TYPE_CONTEXT_UPDATED) { + // TODO(b/120494182): comment when this could happen (dialogs?) + if (sVerbose) { + Log.v(TAG, "handleSendEvent(" + getDebugState() + ", " + + ContentCaptureEvent.getTypeAsString(eventType) + + "): dropping because session not started yet"); + } + return; + } + if (mDisabled.get()) { + // This happens when the event was queued in the handler before the sesison was ready, + // then handleSessionStarted() returned and set it as disabled - we need to drop it, + // otherwise it will keep triggering handleScheduleFlush() + if (sVerbose) Log.v(TAG, "handleSendEvent(): ignoring when disabled"); + return; + } + + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + if (eventType == TYPE_VIEW_TREE_APPEARING) { + Trace.asyncTraceBegin( + Trace.TRACE_TAG_VIEW, /* methodName= */ "sendEventAsync", /* cookie= */ 0); + } + } + + if (isContentProtectionReceiverEnabled()) { + sendContentProtectionEvent(event); + } + if (isContentCaptureReceiverEnabled()) { + sendContentCaptureEvent(event, forceFlush); + } + + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + if (eventType == TYPE_VIEW_TREE_APPEARED) { + Trace.asyncTraceEnd( + Trace.TRACE_TAG_VIEW, /* methodName= */ "sendEventAsync", /* cookie= */ 0); + } + } + } + + private void sendContentProtectionEvent(@NonNull ContentCaptureEvent event) { + checkOnContentCaptureThread(); + if (mContentProtectionEventProcessor != null) { + mContentProtectionEventProcessor.processEvent(event); + } + } + + private void sendContentCaptureEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) { + checkOnContentCaptureThread(); + final int eventType = event.getType(); + final int maxBufferSize = mManager.mOptions.maxBufferSize; + if (mEvents == null) { + if (sVerbose) { + Log.v(TAG, "handleSendEvent(): creating buffer for " + maxBufferSize + " events"); + } + mEvents = new ArrayList<>(maxBufferSize); + } + + // Some type of events can be merged together + boolean addEvent = true; + + if (eventType == TYPE_VIEW_TEXT_CHANGED) { + // We determine whether to add or merge the current event by following criteria: + // 1. Don't have composing span: always add. + // 2. Have composing span: + // 2.1 either last or current text is empty: add. + // 2.2 last event doesn't have composing span: add. + // Otherwise, merge. + final CharSequence text = event.getText(); + final boolean hasComposingSpan = event.hasComposingSpan(); + if (hasComposingSpan) { + ContentCaptureEvent lastEvent = null; + for (int index = mEvents.size() - 1; index >= 0; index--) { + final ContentCaptureEvent tmpEvent = mEvents.get(index); + if (event.getId().equals(tmpEvent.getId())) { + lastEvent = tmpEvent; + break; + } + } + if (lastEvent != null && lastEvent.hasComposingSpan()) { + final CharSequence lastText = lastEvent.getText(); + final boolean bothNonEmpty = !TextUtils.isEmpty(lastText) + && !TextUtils.isEmpty(text); + boolean equalContent = + TextUtils.equals(lastText, text) + && lastEvent.hasSameComposingSpan(event) + && lastEvent.hasSameSelectionSpan(event); + if (equalContent) { + addEvent = false; + } else if (bothNonEmpty) { + lastEvent.mergeEvent(event); + addEvent = false; + } + if (!addEvent && sVerbose) { + Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text=" + + getSanitizedString(text)); + } + } + } + } + + if (!mEvents.isEmpty() && eventType == TYPE_VIEW_DISAPPEARED) { + final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1); + if (lastEvent.getType() == TYPE_VIEW_DISAPPEARED + && event.getSessionId() == lastEvent.getSessionId()) { + if (sVerbose) { + Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session " + + lastEvent.getSessionId()); + } + lastEvent.mergeEvent(event); + addEvent = false; + } + } + + if (addEvent) { + mEvents.add(event); + } + + // TODO: we need to change when the flush happens so that we don't flush while the + // composing span hasn't changed. But we might need to keep flushing the events for the + // non-editable views and views that don't have the composing state; otherwise some other + // Content Capture features may be delayed. + + final int numberEvents = mEvents.size(); + + final boolean bufferEvent = numberEvents < maxBufferSize; + + if (bufferEvent && !forceFlush) { + final int flushReason; + if (eventType == TYPE_VIEW_TEXT_CHANGED) { + mNextFlushForTextChanged = true; + flushReason = FLUSH_REASON_TEXT_CHANGE_TIMEOUT; + } else { + if (mNextFlushForTextChanged) { + if (sVerbose) { + Log.i(TAG, "Not scheduling flush because next flush is for text changed"); + } + return; + } + + flushReason = FLUSH_REASON_IDLE_TIMEOUT; + } + scheduleFlush(flushReason, /* checkExisting= */ true); + return; + } + + if (mState != STATE_ACTIVE && numberEvents >= maxBufferSize) { + // Callback from startSession hasn't been called yet - typically happens on system + // apps that are started before the system service + // TODO(b/122959591): try to ignore session while system is not ready / boot + // not complete instead. Similarly, the manager service should return right away + // when the user does not have a service set + if (sDebug) { + Log.d(TAG, "Closing session for " + getDebugState() + + " after " + numberEvents + " delayed events"); + } + resetSession(STATE_DISABLED | STATE_NO_RESPONSE); + // TODO(b/111276913): denylist activity / use special flag to indicate that + // when it's launched again + return; + } + final int flushReason; + switch (eventType) { + case ContentCaptureEvent.TYPE_SESSION_STARTED: + flushReason = FLUSH_REASON_SESSION_STARTED; + break; + case ContentCaptureEvent.TYPE_SESSION_FINISHED: + flushReason = FLUSH_REASON_SESSION_FINISHED; + break; + case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING: + flushReason = FLUSH_REASON_VIEW_TREE_APPEARING; + break; + case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED: + flushReason = FLUSH_REASON_VIEW_TREE_APPEARED; + break; + default: + flushReason = forceFlush ? FLUSH_REASON_FORCE_FLUSH : FLUSH_REASON_FULL; + } + + flush(flushReason); + } + + private boolean hasStarted() { + checkOnContentCaptureThread(); + return mState != UNKNOWN_STATE; + } + + private void scheduleFlush(@FlushReason int reason, boolean checkExisting) { + checkOnContentCaptureThread(); + if (sVerbose) { + Log.v(TAG, "handleScheduleFlush(" + getDebugState(reason) + + ", checkExisting=" + checkExisting); + } + if (!hasStarted()) { + if (sVerbose) Log.v(TAG, "handleScheduleFlush(): session not started yet"); + return; + } + + if (mDisabled.get()) { + // Should not be called on this state, as handleSendEvent checks. + // But we rather add one if check and log than re-schedule and keep the session alive... + Log.e(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): should not be called " + + "when disabled. events=" + (mEvents == null ? null : mEvents.size())); + return; + } + if (checkExisting && mContentCaptureHandler.hasMessages(MSG_FLUSH)) { + // "Renew" the flush message by removing the previous one + mContentCaptureHandler.removeMessages(MSG_FLUSH); + } + + final int flushFrequencyMs; + if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) { + flushFrequencyMs = mManager.mOptions.textChangeFlushingFrequencyMs; + } else { + if (reason != FLUSH_REASON_IDLE_TIMEOUT) { + if (sDebug) { + Log.d(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): not a timeout " + + "reason because mDirectServiceInterface is not ready yet"); + } + } + flushFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs; + } + + mNextFlush = System.currentTimeMillis() + flushFrequencyMs; + if (sVerbose) { + Log.v(TAG, "handleScheduleFlush(): scheduled to flush in " + + flushFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush)); + } + // Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage() + mContentCaptureHandler.postDelayed(() -> + flushIfNeeded(reason), MSG_FLUSH, flushFrequencyMs); + } + + private void flushIfNeeded(@FlushReason int reason) { + checkOnContentCaptureThread(); + if (mEvents == null || mEvents.isEmpty()) { + if (sVerbose) Log.v(TAG, "Nothing to flush"); + return; + } + flush(reason); + } + + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + @Override + public void flush(@FlushReason int reason) { + runOnContentCaptureThread(() -> flushImpl(reason)); + } + + private void flushImpl(@FlushReason int reason) { + checkOnContentCaptureThread(); + if (mEvents == null || mEvents.size() == 0) { + if (sVerbose) { + Log.v(TAG, "Don't flush for empty event buffer."); + } + return; + } + + if (mDisabled.get()) { + Log.e(TAG, "handleForceFlush(" + getDebugState(reason) + "): should not be when " + + "disabled"); + return; + } + + if (!isContentCaptureReceiverEnabled()) { + return; + } + + if (mDirectServiceInterface == null) { + if (sVerbose) { + Log.v(TAG, "handleForceFlush(" + getDebugState(reason) + "): hold your horses, " + + "client not ready: " + mEvents); + } + if (!mContentCaptureHandler.hasMessages(MSG_FLUSH)) { + scheduleFlush(reason, /* checkExisting= */ false); + } + return; + } + + mNextFlushForTextChanged = false; + + final int numberEvents = mEvents.size(); + final String reasonString = getFlushReasonAsString(reason); + + if (sVerbose) { + ContentCaptureEvent event = mEvents.get(numberEvents - 1); + String forceString = (reason == FLUSH_REASON_FORCE_FLUSH) ? ". The force flush event " + + ContentCaptureEvent.getTypeAsString(event.getType()) : ""; + Log.v(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState(reason) + + forceString); + } + if (mFlushHistory != null) { + // Logs reason, size, max size, idle timeout + final String logRecord = "r=" + reasonString + " s=" + numberEvents + + " m=" + mManager.mOptions.maxBufferSize + + " i=" + mManager.mOptions.idleFlushingFrequencyMs; + mFlushHistory.log(logRecord); + } + try { + mContentCaptureHandler.removeMessages(MSG_FLUSH); + + final ParceledListSlice<ContentCaptureEvent> events = clearEvents(); + mDirectServiceInterface.sendEvents(events, reason, mManager.mOptions); + } catch (RemoteException e) { + Log.w(TAG, "Error sending " + numberEvents + " for " + getDebugState() + + ": " + e); + } + } + + @Override + public void updateContentCaptureContext(@Nullable ContentCaptureContext context) { + internalNotifyContextUpdated(mId, context); + } + + /** + * Resets the buffer and return a {@link ParceledListSlice} with the previous events. + */ + @NonNull + private ParceledListSlice<ContentCaptureEvent> clearEvents() { + checkOnContentCaptureThread(); + // NOTE: we must save a reference to the current mEvents and then set it to to null, + // otherwise clearing it would clear it in the receiving side if the service is also local. + if (mEvents == null) { + return new ParceledListSlice<>(Collections.EMPTY_LIST); + } + + final List<ContentCaptureEvent> events = new ArrayList<>(mEvents); + mEvents.clear(); + return new ParceledListSlice<>(events); + } + + /** hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public void destroySession() { + checkOnContentCaptureThread(); + if (sDebug) { + Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with " + + (mEvents == null ? 0 : mEvents.size()) + " event(s) for " + + getDebugState()); + } + + reportWrongThreadMetric(); + try { + mSystemServerInterface.finishSession(mId); + } catch (RemoteException e) { + Log.e(TAG, "Error destroying system-service session " + mId + " for " + + getDebugState() + ": " + e); + } + + if (mDirectServiceInterface != null) { + mDirectServiceInterface.asBinder().unlinkToDeath(mDirectServiceVulture, 0); + } + mDirectServiceInterface = null; + mContentProtectionEventProcessor = null; + mEventProcessQueue.clear(); + } + + // TODO(b/122454205): once we support multiple sessions, we might need to move some of these + // clearings out. + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public void resetSession(int newState) { + checkOnContentCaptureThread(); + if (sVerbose) { + Log.v(TAG, "handleResetSession(" + getActivityName() + "): from " + + getStateAsString(mState) + " to " + getStateAsString(newState)); + } + mState = newState; + mDisabled.set((newState & STATE_DISABLED) != 0); + // TODO(b/122454205): must reset children (which currently is owned by superclass) + mApplicationToken = null; + mShareableActivityToken = null; + mComponentName = null; + mEvents = null; + if (mDirectServiceInterface != null) { + try { + mDirectServiceInterface.asBinder().unlinkToDeath(mDirectServiceVulture, 0); + } catch (NoSuchElementException e) { + Log.w(TAG, "IContentCaptureDirectManager does not exist"); + } + } + mDirectServiceInterface = null; + mContentProtectionEventProcessor = null; + mContentCaptureHandler.removeMessages(MSG_FLUSH); + } + + @Override + void internalNotifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) { + final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED) + .setViewNode(node.mNode); + enqueueEvent(event); + } + + @Override + void internalNotifyViewDisappeared(int sessionId, @NonNull AutofillId id) { + final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED) + .setAutofillId(id); + enqueueEvent(event); + } + + @Override + void internalNotifyViewTextChanged( + int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) { + // Since the same CharSequence instance may be reused in the TextView, we need to make + // a copy of its content so that its value will not be changed by subsequent updates + // in the TextView. + CharSequence trimmed = TextUtils.trimToParcelableSize(text); + final CharSequence eventText = trimmed != null && trimmed == text + ? trimmed.toString() + : trimmed; + + final int composingStart; + final int composingEnd; + if (text instanceof Spannable) { + composingStart = BaseInputConnection.getComposingSpanStart((Spannable) text); + composingEnd = BaseInputConnection.getComposingSpanEnd((Spannable) text); + } else { + composingStart = ContentCaptureEvent.MAX_INVALID_VALUE; + composingEnd = ContentCaptureEvent.MAX_INVALID_VALUE; + } + + final int startIndex = Selection.getSelectionStart(text); + final int endIndex = Selection.getSelectionEnd(text); + + final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED) + .setAutofillId(id).setText(eventText) + .setComposingIndex(composingStart, composingEnd) + .setSelectionIndex(startIndex, endIndex); + enqueueEvent(event); + } + + @Override + void internalNotifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) { + final ContentCaptureEvent event = + new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED) + .setInsets(viewInsets); + enqueueEvent(event); + } + + @Override + public void internalNotifyViewTreeEvent(int sessionId, boolean started) { + final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED; + final boolean disableFlush = mManager.getFlushViewTreeAppearingEventDisabled(); + final boolean forceFlush = disableFlush ? !started : FORCE_FLUSH; + + final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type); + enqueueEvent(event, forceFlush); + } + + @Override + public void internalNotifySessionResumed() { + final ContentCaptureEvent event = new ContentCaptureEvent(mId, TYPE_SESSION_RESUMED); + enqueueEvent(event, FORCE_FLUSH); + } + + @Override + public void internalNotifySessionPaused() { + final ContentCaptureEvent event = new ContentCaptureEvent(mId, TYPE_SESSION_PAUSED); + enqueueEvent(event, FORCE_FLUSH); + } + + @Override + boolean isContentCaptureEnabled() { + return super.isContentCaptureEnabled() && mManager.isContentCaptureEnabled(); + } + + // Called by ContentCaptureManager.isContentCaptureEnabled + boolean isDisabled() { + return mDisabled.get(); + } + + /** + * Sets the disabled state of content capture. + * + * @return whether disabled state was changed. + */ + boolean setDisabled(boolean disabled) { + return mDisabled.compareAndSet(!disabled, disabled); + } + + @Override + void internalNotifyChildSessionStarted(int parentSessionId, int childSessionId, + @NonNull ContentCaptureContext clientContext) { + final ContentCaptureEvent event = + new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED) + .setParentSessionId(parentSessionId) + .setClientContext(clientContext); + enqueueEvent(event, FORCE_FLUSH); + } + + @Override + void internalNotifyChildSessionFinished(int parentSessionId, int childSessionId) { + final ContentCaptureEvent event = + new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED) + .setParentSessionId(parentSessionId); + enqueueEvent(event, FORCE_FLUSH); + } + + @Override + void internalNotifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) { + final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED) + .setClientContext(context); + enqueueEvent(event, FORCE_FLUSH); + } + + @Override + public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) { + final ContentCaptureEvent event = + new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED) + .setBounds(bounds); + enqueueEvent(event); + } + + private List<ContentCaptureEvent> clearBufferEvents() { + final ArrayList<ContentCaptureEvent> bufferEvents = new ArrayList<>(); + ContentCaptureEvent event; + while ((event = mEventProcessQueue.poll()) != null) { + bufferEvents.add(event); + } + return bufferEvents; + } + + private void enqueueEvent(@NonNull final ContentCaptureEvent event) { + enqueueEvent(event, /* forceFlush */ false); + } + + /** + * Enqueue the event into {@code mEventProcessBuffer} if it is not an urgent request. Otherwise, + * clear the buffer events then starting sending out current event. + */ + private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) { + if (forceFlush) { + // The buffer events are cleared in the same thread first to prevent new events + // being added during the time of context switch. This would disrupt the sequence + // of events. + final List<ContentCaptureEvent> batchEvents = clearBufferEvents(); + runOnContentCaptureThread(() -> { + for (int i = 0; i < batchEvents.size(); i++) { + sendEvent(batchEvents.get(i)); + } + sendEvent(event, /* forceFlush= */ true); + }); + } else { + mEventProcessQueue.offer(event); + } + } + + @Override + public void notifyContentCaptureEvents( + @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) { + runOnUiThread(() -> { + prepareViewStructures(contentCaptureEvents); + runOnContentCaptureThread(() -> + notifyContentCaptureEventsImpl(contentCaptureEvents)); + }); + } + + /** + * Traverse events and pre-process {@link View} events to {@link ViewStructureSession} events. + * If a {@link View} event is invalid, an empty {@link ViewStructureSession} will still be + * provided. + */ + private void prepareViewStructures( + @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) { + for (int i = 0; i < contentCaptureEvents.size(); i++) { + int sessionId = contentCaptureEvents.keyAt(i); + ArrayList<Object> events = contentCaptureEvents.valueAt(i); + for_each_event: for (int j = 0; j < events.size(); j++) { + Object event = events.get(j); + if (event instanceof View) { + View view = (View) event; + ContentCaptureSession session = view.getContentCaptureSession(); + ViewStructureSession structureSession = new ViewStructureSession(); + + // Replace the View event with ViewStructureSession no matter the data is + // available or not. This is to ensure the sequence of the events are still + // the same. Calls to notifyViewAppeared will check the availability later. + events.set(j, structureSession); + if (session == null) { + Log.w(TAG, "no content capture session on view: " + view); + continue for_each_event; + } + int actualId = session.getId(); + if (actualId != sessionId) { + Log.w(TAG, "content capture session mismatch for view (" + view + + "): was " + sessionId + " before, it's " + actualId + " now"); + continue for_each_event; + } + ViewStructure structure = session.newViewStructure(view); + view.onProvideContentCaptureStructure(structure, /* flags= */ 0); + + structureSession.setSession(session); + structureSession.setStructure(structure); + } + } + } + } + + private void notifyContentCaptureEventsImpl( + @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) { + checkOnContentCaptureThread(); + try { + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents"); + } + for (int i = 0; i < contentCaptureEvents.size(); i++) { + int sessionId = contentCaptureEvents.keyAt(i); + internalNotifyViewTreeEvent(sessionId, /* started= */ true); + ArrayList<Object> events = contentCaptureEvents.valueAt(i); + for_each_event: for (int j = 0; j < events.size(); j++) { + Object event = events.get(j); + if (event instanceof AutofillId) { + internalNotifyViewDisappeared(sessionId, (AutofillId) event); + } else if (event instanceof ViewStructureSession viewStructureSession) { + viewStructureSession.notifyViewAppeared(); + } else if (event instanceof Insets) { + internalNotifyViewInsetsChanged(sessionId, (Insets) event); + } else { + Log.w(TAG, "invalid content capture event: " + event); + } + } + internalNotifyViewTreeEvent(sessionId, /* started= */ false); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + } + + @Override + void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + super.dump(prefix, pw); + + pw.print(prefix); pw.print("mContext: "); pw.println(mContext); + pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId()); + if (mDirectServiceInterface != null) { + pw.print(prefix); pw.print("mDirectServiceInterface: "); + pw.println(mDirectServiceInterface); + } + pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get()); + pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled()); + pw.print(prefix); pw.print("state: "); pw.println(getStateAsString(mState)); + if (mApplicationToken != null) { + pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken); + } + if (mShareableActivityToken != null) { + pw.print(prefix); pw.print("sharable activity token: "); + pw.println(mShareableActivityToken); + } + if (mComponentName != null) { + pw.print(prefix); pw.print("component name: "); + pw.println(mComponentName.flattenToShortString()); + } + if (mEvents != null && !mEvents.isEmpty()) { + final int numberEvents = mEvents.size(); + pw.print(prefix); pw.print("buffered events: "); pw.print(numberEvents); + pw.print('/'); pw.println(mManager.mOptions.maxBufferSize); + if (sVerbose && numberEvents > 0) { + final String prefix3 = prefix + " "; + for (int i = 0; i < numberEvents; i++) { + final ContentCaptureEvent event = mEvents.get(i); + pw.print(prefix3); pw.print(i); pw.print(": "); event.dump(pw); + pw.println(); + } + } + pw.print(prefix); pw.print("mNextFlushForTextChanged: "); + pw.println(mNextFlushForTextChanged); + pw.print(prefix); pw.print("flush frequency: "); + if (mNextFlushForTextChanged) { + pw.println(mManager.mOptions.textChangeFlushingFrequencyMs); + } else { + pw.println(mManager.mOptions.idleFlushingFrequencyMs); + } + pw.print(prefix); pw.print("next flush: "); + TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw); + pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")"); + } + if (mFlushHistory != null) { + pw.print(prefix); pw.println("flush history:"); + mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println(); + } else { + pw.print(prefix); pw.println("not logging flush history"); + } + + super.dump(prefix, pw); + } + + /** + * Gets a string that can be used to identify the activity on logging statements. + */ + private String getActivityName() { + return mComponentName == null + ? "pkg:" + mContext.getPackageName() + : "act:" + mComponentName.flattenToShortString(); + } + + @NonNull + private String getDebugState() { + return getActivityName() + " [state=" + getStateAsString(mState) + ", disabled=" + + mDisabled.get() + "]"; + } + + @NonNull + private String getDebugState(@FlushReason int reason) { + return getDebugState() + ", reason=" + getFlushReasonAsString(reason); + } + + private boolean isContentProtectionReceiverEnabled() { + return mManager.mOptions.contentProtectionOptions.enableReceiver; + } + + private boolean isContentCaptureReceiverEnabled() { + return mManager.mOptions.enableReceiver; + } + + private boolean isContentProtectionEnabled() { + // Should not be possible for mComponentName to be null here but check anyway + // Should not be possible for groups to be empty if receiver is enabled but check anyway + return mManager.mOptions.contentProtectionOptions.enableReceiver + && mManager.getContentProtectionEventBuffer() != null + && mComponentName != null + && (!mManager.mOptions.contentProtectionOptions.requiredGroups.isEmpty() + || !mManager.mOptions.contentProtectionOptions.optionalGroups.isEmpty()); + } + + /** + * Checks that the current work is running on the assigned thread from {@code mHandler} and + * count the number of times running on the wrong thread. + * + * <p>It is not guaranteed that the callers always invoke function from a single thread. + * Therefore, accessing internal properties in {@link MainContentCaptureSession} should + * always delegate to the assigned thread from {@code mHandler} for synchronization.</p> + */ + private void checkOnContentCaptureThread() { + final boolean onContentCaptureThread = mContentCaptureHandler.getLooper().isCurrentThread(); + if (!onContentCaptureThread) { + mWrongThreadCount.incrementAndGet(); + Log.e(TAG, "MainContentCaptureSession running on " + Thread.currentThread()); + } + } + + /** Reports number of times running on the wrong thread. */ + private void reportWrongThreadMetric() { + Counter.logIncrement( + CONTENT_CAPTURE_WRONG_THREAD_METRIC_ID, mWrongThreadCount.getAndSet(0)); + } + + /** + * Ensures that {@code r} will be running on the assigned thread. + * + * <p>This is to prevent unnecessary delegation to Handler that results in fragmented runnable. + * </p> + */ + private void runOnContentCaptureThread(@NonNull Runnable r) { + if (!mContentCaptureHandler.getLooper().isCurrentThread()) { + mContentCaptureHandler.post(r); + } else { + r.run(); + } + } + + private void clearAndRunOnContentCaptureThread(@NonNull Runnable r, int what) { + if (!mContentCaptureHandler.getLooper().isCurrentThread()) { + mContentCaptureHandler.removeMessages(what); + mContentCaptureHandler.post(r); + } else { + r.run(); + } + } + + private void runOnUiThread(@NonNull Runnable r) { + if (mUiHandler.getLooper().isCurrentThread()) { + r.run(); + } else { + mUiHandler.post(r); + } + } + + /** + * Holds {@link ContentCaptureSession} and related {@link ViewStructure} for processing. + */ + private static final class ViewStructureSession { + @Nullable private ContentCaptureSession mSession; + @Nullable private ViewStructure mStructure; + + ViewStructureSession() {} + + void setSession(@Nullable ContentCaptureSession session) { + this.mSession = session; + } + + void setStructure(@Nullable ViewStructure struct) { + this.mStructure = struct; + } + + /** + * Calls {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)} if the session and + * the view structure are available. + */ + void notifyViewAppeared() { + if (mSession != null && mStructure != null) { + mSession.notifyViewAppeared(mStructure); + } + } + } +} diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig new file mode 100644 index 000000000000..a74b06a491e8 --- /dev/null +++ b/core/java/android/view/flags/view_flags.aconfig @@ -0,0 +1,10 @@ +package: "android.view.flags" + +flag { + name: "enable_use_measure_cache_during_force_layout" + namespace: "toolkit" + description: "Enables using the measure cache during a view force layout from the second " + "onMeasure call onwards during the same traversal." + bug: "316170253" + is_fixed_read_only: true +} diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig index dc6aa6cdc048..bb7677d6a571 100644 --- a/core/java/android/view/inputmethod/flags.aconfig +++ b/core/java/android/view/inputmethod/flags.aconfig @@ -38,3 +38,12 @@ flag { description: "Feature flag for supporting stylus handwriting delegation from RemoteViews on the home screen" bug: "279959705" } + +flag { + name: "use_handwriting_listener_for_tooltype" + namespace: "input_method" + description: "Feature flag for using handwriting spy for determining pointer toolType." + bug: "309554999" + is_fixed_read_only: true +} + diff --git a/core/java/android/window/ActivityWindowInfo.aidl b/core/java/android/window/ActivityWindowInfo.aidl new file mode 100644 index 000000000000..d0526bc68fd4 --- /dev/null +++ b/core/java/android/window/ActivityWindowInfo.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.window; + +/** + * Stores information about a particular Activity Window. + * @hide + */ +parcelable ActivityWindowInfo; diff --git a/core/java/android/window/ActivityWindowInfo.java b/core/java/android/window/ActivityWindowInfo.java new file mode 100644 index 000000000000..946bb823398c --- /dev/null +++ b/core/java/android/window/ActivityWindowInfo.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.window; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.Rect; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Stores the window information about a particular Activity. + * It contains the info that is not part of {@link android.content.res.Configuration}. + * @hide + */ +public final class ActivityWindowInfo implements Parcelable { + + private boolean mIsEmbedded; + + @NonNull + private final Rect mTaskBounds = new Rect(); + + @NonNull + private final Rect mTaskFragmentBounds = new Rect(); + + public ActivityWindowInfo() {} + + public ActivityWindowInfo(@NonNull ActivityWindowInfo info) { + set(info); + } + + /** Copies fields from {@code info}. */ + public void set(@NonNull ActivityWindowInfo info) { + set(info.mIsEmbedded, info.mTaskBounds, info.mTaskFragmentBounds); + } + + /** Sets to the given values. */ + public void set(boolean isEmbedded, @NonNull Rect taskBounds, + @NonNull Rect taskFragmentBounds) { + mIsEmbedded = isEmbedded; + mTaskBounds.set(taskBounds); + mTaskFragmentBounds.set(taskFragmentBounds); + } + + /** + * Whether this activity is embedded, which means it is a TaskFragment that doesn't fill the + * leaf Task. + */ + public boolean isEmbedded() { + return mIsEmbedded; + } + + /** + * The bounds of the leaf Task window in display space. + */ + @NonNull + public Rect getTaskBounds() { + return mTaskBounds; + } + + /** + * The bounds of the leaf TaskFragment window in display space. + * This can be referring to the bounds of the same window as {@link #getTaskBounds()} when + * the activity is not embedded. + */ + @NonNull + public Rect getTaskFragmentBounds() { + return mTaskFragmentBounds; + } + + private ActivityWindowInfo(@NonNull Parcel in) { + mIsEmbedded = in.readBoolean(); + mTaskBounds.readFromParcel(in); + mTaskFragmentBounds.readFromParcel(in); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeBoolean(mIsEmbedded); + mTaskBounds.writeToParcel(dest, flags); + mTaskFragmentBounds.writeToParcel(dest, flags); + } + + @NonNull + public static final Creator<ActivityWindowInfo> CREATOR = + new Creator<>() { + @Override + public ActivityWindowInfo createFromParcel(@NonNull Parcel in) { + return new ActivityWindowInfo(in); + } + + @Override + public ActivityWindowInfo[] newArray(int size) { + return new ActivityWindowInfo[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ActivityWindowInfo other = (ActivityWindowInfo) o; + return mIsEmbedded == other.mIsEmbedded + && mTaskBounds.equals(other.mTaskBounds) + && mTaskFragmentBounds.equals(other.mTaskFragmentBounds); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + (mIsEmbedded ? 1 : 0); + result = 31 * result + mTaskBounds.hashCode(); + result = 31 * result + mTaskFragmentBounds.hashCode(); + return result; + } + + @Override + public String toString() { + return "ActivityWindowInfo{isEmbedded=" + mIsEmbedded + + ", taskBounds=" + mTaskBounds + + ", taskFragmentBounds=" + mTaskFragmentBounds + + "}"; + } +} diff --git a/core/java/android/window/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java index 0ec9ffe6390b..acc6a749e9b7 100644 --- a/core/java/android/window/TaskFragmentOperation.java +++ b/core/java/android/window/TaskFragmentOperation.java @@ -120,6 +120,11 @@ public final class TaskFragmentOperation implements Parcelable { */ public static final int OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE = 15; + /** + * Applies dimming on the parent Task which could cross two TaskFragments. + */ + public static final int OP_TYPE_SET_DIM_ON_TASK = 16; + @IntDef(prefix = { "OP_TYPE_" }, value = { OP_TYPE_UNKNOWN, OP_TYPE_CREATE_TASK_FRAGMENT, @@ -138,6 +143,7 @@ public final class TaskFragmentOperation implements Parcelable { OP_TYPE_REORDER_TO_TOP_OF_TASK, OP_TYPE_CREATE_TASK_FRAGMENT_DECOR_SURFACE, OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE, + OP_TYPE_SET_DIM_ON_TASK, }) @Retention(RetentionPolicy.SOURCE) public @interface OperationType {} @@ -165,12 +171,14 @@ public final class TaskFragmentOperation implements Parcelable { private final boolean mIsolatedNav; + private final boolean mDimOnTask; + private TaskFragmentOperation(@OperationType int opType, @Nullable TaskFragmentCreationParams taskFragmentCreationParams, @Nullable IBinder activityToken, @Nullable Intent activityIntent, @Nullable Bundle bundle, @Nullable IBinder secondaryFragmentToken, @Nullable TaskFragmentAnimationParams animationParams, - boolean isolatedNav) { + boolean isolatedNav, boolean dimOnTask) { mOpType = opType; mTaskFragmentCreationParams = taskFragmentCreationParams; mActivityToken = activityToken; @@ -179,6 +187,7 @@ public final class TaskFragmentOperation implements Parcelable { mSecondaryFragmentToken = secondaryFragmentToken; mAnimationParams = animationParams; mIsolatedNav = isolatedNav; + mDimOnTask = dimOnTask; } private TaskFragmentOperation(Parcel in) { @@ -190,6 +199,7 @@ public final class TaskFragmentOperation implements Parcelable { mSecondaryFragmentToken = in.readStrongBinder(); mAnimationParams = in.readTypedObject(TaskFragmentAnimationParams.CREATOR); mIsolatedNav = in.readBoolean(); + mDimOnTask = in.readBoolean(); } @Override @@ -202,6 +212,7 @@ public final class TaskFragmentOperation implements Parcelable { dest.writeStrongBinder(mSecondaryFragmentToken); dest.writeTypedObject(mAnimationParams, flags); dest.writeBoolean(mIsolatedNav); + dest.writeBoolean(mDimOnTask); } @NonNull @@ -282,6 +293,13 @@ public final class TaskFragmentOperation implements Parcelable { return mIsolatedNav; } + /** + * Returns whether the dim layer should apply on the parent Task. + */ + public boolean isDimOnTask() { + return mDimOnTask; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder(); @@ -305,6 +323,7 @@ public final class TaskFragmentOperation implements Parcelable { sb.append(", animationParams=").append(mAnimationParams); } sb.append(", isolatedNav=").append(mIsolatedNav); + sb.append(", dimOnTask=").append(mDimOnTask); sb.append('}'); return sb.toString(); @@ -313,7 +332,7 @@ public final class TaskFragmentOperation implements Parcelable { @Override public int hashCode() { return Objects.hash(mOpType, mTaskFragmentCreationParams, mActivityToken, mActivityIntent, - mBundle, mSecondaryFragmentToken, mAnimationParams, mIsolatedNav); + mBundle, mSecondaryFragmentToken, mAnimationParams, mIsolatedNav, mDimOnTask); } @Override @@ -329,7 +348,8 @@ public final class TaskFragmentOperation implements Parcelable { && Objects.equals(mBundle, other.mBundle) && Objects.equals(mSecondaryFragmentToken, other.mSecondaryFragmentToken) && Objects.equals(mAnimationParams, other.mAnimationParams) - && mIsolatedNav == other.mIsolatedNav; + && mIsolatedNav == other.mIsolatedNav + && mDimOnTask == other.mDimOnTask; } @Override @@ -363,6 +383,8 @@ public final class TaskFragmentOperation implements Parcelable { private boolean mIsolatedNav; + private boolean mDimOnTask; + /** * @param opType the {@link OperationType} of this {@link TaskFragmentOperation}. */ @@ -435,13 +457,22 @@ public final class TaskFragmentOperation implements Parcelable { } /** + * Sets the dimming to apply on the parent Task if any. + */ + @NonNull + public Builder setDimOnTask(boolean dimOnTask) { + mDimOnTask = dimOnTask; + return this; + } + + /** * Constructs the {@link TaskFragmentOperation}. */ @NonNull public TaskFragmentOperation build() { return new TaskFragmentOperation(mOpType, mTaskFragmentCreationParams, mActivityToken, mActivityIntent, mBundle, mSecondaryFragmentToken, mAnimationParams, - mIsolatedNav); + mIsolatedNav, mDimOnTask); } } } diff --git a/core/java/android/window/flags/wallpaper_manager.aconfig b/core/java/android/window/flags/wallpaper_manager.aconfig index f03c993a9c66..ea9da96496c7 100644 --- a/core/java/android/window/flags/wallpaper_manager.aconfig +++ b/core/java/android/window/flags/wallpaper_manager.aconfig @@ -13,3 +13,10 @@ flag { description: "Support storing different wallpaper crops for different display dimensions. Only effective after rebooting." bug: "281648899" } + +flag { + name: "no_consecutive_visibility_events" + namespace: "systemui" + description: "Prevent the system from sending consecutive onVisibilityChanged(false) events." + bug: "285631818" +}
\ No newline at end of file diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index 59d7b0e55e85..f743ab74d1f5 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -38,4 +38,12 @@ flag { name: "activity_embedding_interactive_divider_flag" description: "Whether the interactive divider feature is enabled" bug: "293654166" +} + +flag { + namespace: "windowing_sdk" + name: "activity_window_info_flag" + description: "To dispatch ActivityWindowInfo through ClientTransaction" + bug: "287582673" + is_fixed_read_only: true }
\ No newline at end of file diff --git a/core/java/com/android/internal/foldables/FoldGracePeriodProvider.java b/core/java/com/android/internal/foldables/FoldGracePeriodProvider.java new file mode 100644 index 000000000000..53164f3e1ec9 --- /dev/null +++ b/core/java/com/android/internal/foldables/FoldGracePeriodProvider.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.internal.foldables; + +import android.os.Build; +import android.sysprop.FoldLockBehaviorProperties; +import android.util.Slog; + +import com.android.internal.foldables.flags.Flags; + +import java.util.function.Supplier; + +/** + * Wrapper class to access {@link FoldLockBehaviorProperties}. + */ +public class FoldGracePeriodProvider { + + private static final String TAG = "FoldGracePeriodProvider"; + private final Supplier<Boolean> mFoldGracePeriodEnabled = Flags::foldGracePeriodEnabled; + + /** + * Whether the fold grace period feature is enabled. + */ + public boolean isEnabled() { + if ((Build.IS_ENG || Build.IS_USERDEBUG) + && FoldLockBehaviorProperties.fold_grace_period_enabled().orElse(false)) { + return true; + } + try { + return mFoldGracePeriodEnabled.get(); + } catch (Throwable ex) { + Slog.i(TAG, + "Flags not ready yet. Return false for " + + Flags.FLAG_FOLD_GRACE_PERIOD_ENABLED, + ex); + return false; + } + } +} diff --git a/core/java/com/android/internal/foldables/fold_lock_setting_flags.aconfig b/core/java/com/android/internal/foldables/fold_lock_setting_flags.aconfig index 44f436eaaa19..d73e62373732 100644 --- a/core/java/com/android/internal/foldables/fold_lock_setting_flags.aconfig +++ b/core/java/com/android/internal/foldables/fold_lock_setting_flags.aconfig @@ -7,3 +7,11 @@ flag { bug: "274447767" is_fixed_read_only: true } + +flag { + name: "fold_grace_period_enabled" + namespace: "display_manager" + description: "Feature flag for Folding Grace Period" + bug: "308417021" + is_fixed_read_only: true +} diff --git a/core/java/com/android/internal/pm/parsing/PackageInfoCommonUtils.java b/core/java/com/android/internal/pm/parsing/PackageInfoCommonUtils.java index f05d9cbe1c8d..983658a01dc8 100644 --- a/core/java/com/android/internal/pm/parsing/PackageInfoCommonUtils.java +++ b/core/java/com/android/internal/pm/parsing/PackageInfoCommonUtils.java @@ -96,8 +96,10 @@ public class PackageInfoCommonUtils { info.baseRevisionCode = pkg.getBaseRevisionCode(); info.splitRevisionCodes = pkg.getSplitRevisionCodes(); info.versionName = pkg.getVersionName(); - info.sharedUserId = pkg.getSharedUserId(); - info.sharedUserLabel = pkg.getSharedUserLabelResourceId(); + if (!pkg.isLeavingSharedUser()) { + info.sharedUserId = pkg.getSharedUserId(); + info.sharedUserLabel = pkg.getSharedUserLabelResourceId(); + } info.applicationInfo = applicationInfo; info.installLocation = pkg.getInstallLocation(); if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java index bdc8a668a7f7..1d6d69cee967 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java @@ -1009,7 +1009,7 @@ public interface PooledLambda { K arg11, L arg12) { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, - function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, + function, 12, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); return Message.obtain().setCallback(callback.recycleOnUse()); } diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index 4474d4cabacb..70505a45fa1b 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -139,10 +139,13 @@ static bool nativeSyncNextTransaction(JNIEnv* env, jclass clazz, jlong ptr, jobj return queue->syncNextTransaction( [globalCallbackRef](SurfaceComposerClient::Transaction* t) { JNIEnv* env = getenv(globalCallbackRef->vm()); + ScopedLocalRef<jobject> + transactionObject(env, + env->NewObject(gTransactionClassInfo.clazz, + gTransactionClassInfo.ctor, + reinterpret_cast<jlong>(t))); env->CallVoidMethod(globalCallbackRef->object(), gTransactionConsumer.accept, - env->NewObject(gTransactionClassInfo.clazz, - gTransactionClassInfo.ctor, - reinterpret_cast<jlong>(t))); + transactionObject.get()); }, acquireSingleBuffer); } diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp index 781895eeeaba..477bd096b11a 100644 --- a/core/jni/android_os_HwBinder.cpp +++ b/core/jni/android_os_HwBinder.cpp @@ -258,14 +258,59 @@ static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) { JHwBinder::SetNativeContext(env, thiz, context); } -static void JHwBinder_native_transact( - JNIEnv * /* env */, - jobject /* thiz */, - jint /* code */, - jobject /* requestObj */, - jobject /* replyObj */, - jint /* flags */) { - CHECK(!"Should not be here"); +static void JHwBinder_native_transact(JNIEnv *env, jobject thiz, jint code, jobject requestObj, + jobject replyObj, jint flags) { + if (requestObj == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } + sp<hardware::IBinder> binder = JHwBinder::GetNativeBinder(env, thiz); + sp<android::hidl::base::V1_0::IBase> base = new android::hidl::base::V1_0::BpHwBase(binder); + hidl_string desc; + auto ret = base->interfaceDescriptor( + [&desc](const hidl_string &descriptor) { desc = descriptor; }); + ret.assertOk(); + // Only the fake hwservicemanager is allowed to be used locally like this. + if (desc != "android.hidl.manager@1.2::IServiceManager" && + desc != "android.hidl.manager@1.1::IServiceManager" && + desc != "android.hidl.manager@1.0::IServiceManager") { + LOG(FATAL) << "Local binders are not supported!"; + } + if (replyObj == nullptr) { + LOG(FATAL) << "Unexpected null replyObj. code: " << code; + return; + } + const hardware::Parcel *request = JHwParcel::GetNativeContext(env, requestObj)->getParcel(); + sp<JHwParcel> replyContext = JHwParcel::GetNativeContext(env, replyObj); + hardware::Parcel *reply = replyContext->getParcel(); + + request->setDataPosition(0); + + bool isOneway = (flags & IBinder::FLAG_ONEWAY) != 0; + if (!isOneway) { + replyContext->setTransactCallback([](auto &replyParcel) {}); + } + + env->CallVoidMethod(thiz, gFields.onTransactID, code, requestObj, replyObj, flags); + + if (env->ExceptionCheck()) { + jthrowable excep = env->ExceptionOccurred(); + env->ExceptionDescribe(); + env->ExceptionClear(); + + binder_report_exception(env, excep, "Uncaught error or exception in hwbinder!"); + + env->DeleteLocalRef(excep); + } + + if (!isOneway) { + if (!replyContext->wasSent()) { + // The implementation never finished the transaction. + LOG(ERROR) << "The reply failed to send!"; + } + } + + reply->setDataPosition(0); } static void JHwBinder_native_registerService( diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 5b68e8ed1ad8..f7d815283885 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -82,6 +82,7 @@ public: status_t initialize(); void dispose(); status_t finishInputEvent(uint32_t seq, bool handled); + bool probablyHasInput(); status_t reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime); status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch); @@ -165,6 +166,10 @@ status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) return processOutboundEvents(); } +bool NativeInputEventReceiver::probablyHasInput() { + return mInputConsumer.probablyHasInput(); +} + status_t NativeInputEventReceiver::reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime) { if (kDebugDispatchCycle) { @@ -547,6 +552,12 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr, } } +static bool nativeProbablyHasInput(JNIEnv* env, jclass clazz, jlong receiverPtr) { + sp<NativeInputEventReceiver> receiver = + reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); + return receiver->probablyHasInput(); +} + static void nativeReportTimeline(JNIEnv* env, jclass clazz, jlong receiverPtr, jint inputEventId, jlong gpuCompletedTime, jlong presentTime) { if (IdGenerator::getSource(inputEventId) != IdGenerator::Source::INPUT_READER) { @@ -597,6 +608,7 @@ static const JNINativeMethod gMethods[] = { (void*)nativeInit}, {"nativeDispose", "(J)V", (void*)nativeDispose}, {"nativeFinishInputEvent", "(JIZ)V", (void*)nativeFinishInputEvent}, + {"nativeProbablyHasInput", "(J)Z", (void*)nativeProbablyHasInput}, {"nativeReportTimeline", "(JIJJ)V", (void*)nativeReportTimeline}, {"nativeConsumeBatchedInputEvents", "(JJ)Z", (void*)nativeConsumeBatchedInputEvents}, {"nativeDump", "(JLjava/lang/String;)Ljava/lang/String;", (void*)nativeDump}, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 7c5885adb220..7e325a5c1338 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -2187,6 +2187,7 @@ static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gi } if (multiuser_get_app_id(uid) == AID_NETWORK_STACK) { + capabilities |= (1LL << CAP_WAKE_ALARM); capabilities |= (1LL << CAP_NET_ADMIN); capabilities |= (1LL << CAP_NET_BROADCAST); capabilities |= (1LL << CAP_NET_BIND_SERVICE); diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index e5b85517e904..52e0124cc681 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -406,7 +406,7 @@ message WindowTokenProto { optional WindowContainerProto window_container = 1; optional int32 hash_code = 2; repeated WindowStateProto windows = 3 [deprecated=true]; - optional bool waiting_to_show = 5; + optional bool waiting_to_show = 5 [deprecated=true]; optional bool paused = 6; } diff --git a/core/proto/android/view/displaycutout.proto b/core/proto/android/view/displaycutout.proto index 72d5303a6f2c..53155d2d46c6 100644 --- a/core/proto/android/view/displaycutout.proto +++ b/core/proto/android/view/displaycutout.proto @@ -32,4 +32,5 @@ message DisplayCutoutProto { optional .android.graphics.RectProto bound_right = 5; optional .android.graphics.RectProto bound_bottom = 6; optional .android.graphics.RectProto waterfall_insets = 7; + repeated int32 side_overrides = 8; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c6209dd25c47..e65bfab06052 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -578,6 +578,7 @@ <protected-broadcast android:name="com.android.settings.network.SWITCH_TO_SUBSCRIPTION" /> <protected-broadcast android:name="com.android.settings.wifi.action.NETWORK_REQUEST" /> + <protected-broadcast android:name="android.app.action.KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED" /> <protected-broadcast android:name="NotificationManagerService.TIMEOUT" /> <protected-broadcast android:name="NotificationHistoryDatabase.CLEANUP" /> <protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" /> @@ -7691,6 +7692,13 @@ <permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" android:protectionLevel="signature" /> + <!-- Allows low-level access to monitor sticky modifier state changes when A11Y Sticky keys + feature is enabled. + <p>Not for use by third-party applications. + @hide --> + <permission android:name="android.permission.MONITOR_STICKY_MODIFIER_STATE" + android:protectionLevel="signature" /> + <uses-permission android:name="android.permission.HANDLE_QUERY_PACKAGE_RESTART" /> <!-- Allows financed device kiosk apps to perform actions on the Device Lock service diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 8e89075d9f7a..82814626b88a 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Naweek"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Geleentheid"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Slaap"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Bestuur deur <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Aan"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Af"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> demp sekere klanke"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Werk 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Toets"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Gemeenskaplik"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index b38257c07419..ff7dee8c4e2f 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"የሳምንት እረፍት ቀናት"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ክስተት"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"መተኛት"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> የሚተዳደር"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"በርቷል"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ጠፍቷል"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> አንዳንድ ድምጾችን እየዘጋ ነው"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ሥራ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ሙከራ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"የጋራ"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index a77fc65df473..70f0c932b88e 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1910,8 +1910,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"نهاية الأسبوع"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"حدث"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"النوم"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"تحت إدارة \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"مفعَّل"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"غير مفعَّل"</string> <string name="muted_by" msgid="91464083490094950">"يعمل <xliff:g id="THIRD_PARTY">%1$s</xliff:g> على كتم بعض الأصوات."</string> @@ -2344,9 +2343,9 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"يسمح هذا الإذن للتطبيق المصاحب ببدء الخدمات التي تعمل في المقدّمة من الخلفية."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"الميكروفون متاح."</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"تم حظر الميكروفون."</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"يتعذّر إجراء نسخ مطابق لمحتوى جهازك إلى الشاشة"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"يتعذّر البثّ على الشاشة"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"يُرجى استخدام كابل آخر وإعادة المحاولة."</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"جهازك ساخن للغاية ولا يمكنه إجراء نسخ مطابق للمحتوى إلى الشاشة إلى أن تنخفض حرارته."</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"جهازك ساخن للغاية ولا يمكنه البث على الشاشة إلى أن تنخفض حرارته."</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"ميزة Dual Screen مفعّلة"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"يستخدم \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" كلتا الشاشتين لعرض المحتوى."</string> @@ -2370,4 +2369,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ملف العمل 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ملف شخصي تجريبي"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ملف شخصي مشترك"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index f85f61c7e9a2..ddc236773205 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -1177,7 +1177,7 @@ <string name="yes" msgid="9069828999585032361">"ঠিক আছে"</string> <string name="no" msgid="5122037903299899715">"বাতিল কৰক"</string> <string name="dialog_alert_title" msgid="651856561974090712">"মনোযোগ দিব"</string> - <string name="loading" msgid="3138021523725055037">"ল\'ড কৰি থকা হৈছে…"</string> + <string name="loading" msgid="3138021523725055037">"ল’ড হৈ আছে…"</string> <string name="capital_on" msgid="2770685323900821829">"অন কৰক"</string> <string name="capital_off" msgid="7443704171014626777">"অফ কৰক"</string> <string name="checked" msgid="9179896827054513119">"টিক চিহ্ন দিয়া হৈছে"</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"সপ্তাহ অন্ত"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"কার্যক্ৰম"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"নিদ্ৰাৰত"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ পৰিচালনা কৰা"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"অন আছে"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"অফ আছে"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>এ কিছুমান ধ্বনি মিউট কৰি আছে"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"কৰ্মস্থান ৩"</string> <string name="profile_label_test" msgid="9168641926186071947">"পৰীক্ষা"</string> <string name="profile_label_communal" msgid="8743921499944800427">"শ্বেয়াৰ কৰা"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index ed1e34035525..794e26a23c57 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Həftə sonu"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Tədbir"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Yuxu vaxtı"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> idarə edir"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Aktiv"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Deaktiv"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> bəzi səsləri səssiz rejimə salır"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"İş 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Kommunal"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index ea15ceefd262..8df8b8723759 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Vikend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Događaj"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Spavanje"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Upravlja: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Uključeno"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Isključeno"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> isključuje neke zvuke"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Posao 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 8da0d1a9dea1..13801d0f3ed5 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1908,8 +1908,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Выхадныя"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Падзея"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Рэжым сну"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Пад кіраваннем праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Уключана"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Выключана"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> выключае некаторыя гукі"</string> @@ -2368,4 +2367,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Працоўны 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тэставы"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Супольны"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index e97d9dc6bb74..e0e9b09e040f 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Събота и неделя"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Събитие"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Време за сън"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Управлява се от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Вкл."</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Изкл."</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> заглушава някои звуци"</string> @@ -2340,9 +2339,9 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Разрешава на дадено придружаващо приложение да стартира услуги на преден план, докато се изпълнява на заден план."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофонът е налице"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофонът е блокиран"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Не може да се копира огледално на дисплея"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Не може да се дублира на дисплея"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Използвайте друг кабел и опитайте отново"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Устройството ви е твърде топло и няма да може да дублира на екрана, преди да се охлади"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Устройството ви е твърде топло. Дублирането ще е възможно, след като се охлади"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Функцията Dual Screen е включена"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> използва и двата екрана, за да показва съдържание"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Служебни 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тестване"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Общи"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index fa2c2836c1be..cf8c64d251f7 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"সপ্তাহান্ত"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ইভেন্ট"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"ঘুমানোর সময়"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> ম্যানেজ করে"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"চালু আছে"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"বন্ধ আছে"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> কিছু সাউন্ডকে মিউট করে দিচ্ছে"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"৩য় অফিস"</string> <string name="profile_label_test" msgid="9168641926186071947">"পরীক্ষা"</string> <string name="profile_label_communal" msgid="8743921499944800427">"কমিউনাল"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index cd941cef32be..ef941e19ff37 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1902,13 +1902,12 @@ <string name="zen_mode_rule_name_combination" msgid="7174598364351313725">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string> <string name="toolbar_collapse_description" msgid="8009920446193610996">"Suzi"</string> <string name="zen_mode_feature_name" msgid="3785547207263754500">"Ne ometaj"</string> - <string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"Neaktivnost"</string> + <string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"Vrijeme mirovanja"</string> <string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Radni dan uvečer"</string> <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Vikend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Događaj"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Spavanje"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Upravlja <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Uključeno"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Isključeno"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> isključuje neke zvukove"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"3. poslovno"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testno"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Opće"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index fbdcf56c2db9..a4b01e8c822f 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Cap de setmana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Esdeveniment"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Mentre dormo"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gestionat per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activat"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desactivat"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> està silenciant alguns sons"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Treball 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Prova"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Compartit"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 156f18d4f1f2..e518de47834f 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1908,8 +1908,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Víkend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Událost"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Spánek"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Spravováno aplikací <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Zapnuto"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Vypnuto"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> vypíná určité zvuky"</string> @@ -2368,4 +2367,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Práce 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Komunální"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 9f89293fe42c..7119131048a4 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -367,11 +367,11 @@ <string name="permlab_receiveMms" msgid="4000650116674380275">"modtage tekstbeskeder (mms)"</string> <string name="permdesc_receiveMms" msgid="958102423732219710">"Tillader, at appen kan modtage og behandle mms-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string> <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"Videresend Cell Broadcast-meddelelser"</string> - <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tillader, at appen bindes til Cell Broadcast-modulet, så Cell Broadcast-meddelelser kan videresendes, når de modtages. I nogle områder sendes der Cell Broadcast-underretninger for at advare dig om nødsituationer. Ondsindede apps kan forstyrre effektiviteten eller driften af din enhed, når den modtager en Cell Broadcast-meddelelse om en nødsituation."</string> + <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tillader, at appen bindes til Cell Broadcast-modulet, så Cell Broadcast-meddelelser kan videresendes, når de modtages. I regioner sendes der Cell Broadcast-underretninger for at advare dig om nødsituationer. Ondsindede apps kan forstyrre effektiviteten eller driften af din enhed, når den modtager en Cell Broadcast-meddelelse om en nødsituation."</string> <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Administrere igangværende opkald"</string> <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Giver appen tilladelse til at se oplysninger om igangværende opkald på din enhed og styre disse opkald."</string> <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"læse Cell Broadcast-meddelelser"</string> - <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Tillader, at appen læser Cell Broadcast-underretninger, der modtages af din enhed. I nogle områder sendes der Cell Broadcast-underretninger for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af din enhed, når der modtages en Cell Broadcast-meddelelse om en nødsituation."</string> + <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Tillader, at appen læser Cell Broadcast-underretninger, der modtages af din enhed. I regioner sendes der Cell Broadcast-underretninger for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af din enhed, når der modtages en Cell Broadcast-meddelelse om en nødsituation."</string> <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"læse feeds, jeg abonnerer på"</string> <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Tillader, at appen kan hente oplysninger om de feeds, der synkroniseres."</string> <string name="permlab_sendSms" msgid="7757368721742014252">"Send og se sms-beskeder"</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Begivenhed"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sover"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Administreres af <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Til"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Fra"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> slår nogle lyde fra"</string> @@ -1951,14 +1950,14 @@ <string name="user_creation_adding" msgid="7305185499667958364">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en nye bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="supervised_user_creation_label" msgid="6884904353827427515">"Tilføj en administreret bruger"</string> <string name="language_selection_title" msgid="52674936078683285">"Tilføj et sprog"</string> - <string name="country_selection_title" msgid="5221495687299014379">"Områdeindstilling"</string> + <string name="country_selection_title" msgid="5221495687299014379">"Regionpræferencer"</string> <string name="search_language_hint" msgid="7004225294308793583">"Angiv sprog"</string> <string name="language_picker_section_suggested" msgid="6556199184638990447">"Foreslået"</string> <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Forslag"</string> <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Foreslåede sprog"</string> - <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Foreslåede områder"</string> + <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Foreslåede regioner"</string> <string name="language_picker_section_all" msgid="1985809075777564284">"Alle sprog"</string> - <string name="region_picker_section_all" msgid="756441309928774155">"Alle områder"</string> + <string name="region_picker_section_all" msgid="756441309928774155">"Alle regioner"</string> <string name="locale_search_menu" msgid="6258090710176422934">"Søg"</string> <string name="app_suspended_title" msgid="888873445010322650">"Appen er ikke tilgængelig"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgængelig lige nu. Dette administreres af <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> @@ -1998,7 +1997,7 @@ <string name="profile_encrypted_title" msgid="9001208667521266472">"Nogle funktioner er begrænsede"</string> <string name="profile_encrypted_detail" msgid="5279730442756849055">"Arbejdsprofilen er låst"</string> <string name="profile_encrypted_message" msgid="1128512616293157802">"Tryk for at låse profilen op"</string> - <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Tilsluttet <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Forbundet <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Tryk for at se filer"</string> <string name="pin_target" msgid="8036028973110156895">"Fastgør"</string> <string name="pin_specific_target" msgid="7824671240625957415">"Fastgør <xliff:g id="LABEL">%1$s</xliff:g>"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Arbejde 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Fælles"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 182b97409750..c0e12c3d0a03 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Wochenende"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Termin"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Schlafen"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Verwaltet von <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"An"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Aus"</string> <string name="muted_by" msgid="91464083490094950">"Einige Töne werden von <xliff:g id="THIRD_PARTY">%1$s</xliff:g> stummgeschaltet"</string> @@ -2340,8 +2339,8 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Ermöglicht einer Companion-App, Dienste im Vordergrund aus dem Hintergrund zu starten."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"Mikrofon ist verfügbar"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofon ist blockiert"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Kann nicht auf das Display gespiegelt werden"</string> - <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Verwende ein anderes Kabel und versuch es noch einmal"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Bildschirm kann nicht gespiegelt werden"</string> + <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Versuch es mit einem anderen Kabel"</string> <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Dein Gerät ist zu heiß und kann den Bildschirm erst spiegeln, wenn es abgekühlt ist"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen ist aktiviert"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Geschäftlich 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Gemeinsam genutzt"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index d33a2f394862..a392c0fb6969 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Σαββατοκύριακο"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Συμβάν"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Ύπνος"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Διαχείριση από <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Ενεργός"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Ανενεργός"</string> <string name="muted_by" msgid="91464083490094950">"Το τρίτο μέρος <xliff:g id="THIRD_PARTY">%1$s</xliff:g> θέτει ορισμένους ήχους σε σίγαση"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Εργασία 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Δοκιμή"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Κοινόχρηστο"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index a8d807e95ac9..7498488c65be 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Event"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sleeping"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Managed by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"On"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Off"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 2885e4d3f720..fd76ce577b94 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Event"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sleeping"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Managed by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"On"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Off"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index ed4e953e73e0..1f2ccce64c86 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Event"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sleeping"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Managed by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"On"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Off"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index c7e425274b49..d4fd01e3d17b 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Event"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sleeping"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Managed by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"On"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Off"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 8efab743bc4c..8a89ebdfdaa7 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Event"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sleeping"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Managed by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"On"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Off"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> is muting some sounds"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 9cea763d725b..f6117cdaf253 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fin de semana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Dormir"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Administradas por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activado"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desactivado"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> silencia algunos sonidos"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabajo 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Probar"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Compartido"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 3acb71fd937c..406f8795e2a2 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fin de semana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Durmiendo"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gestionado por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activado"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desactivado"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> silencia algunos sonidos"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabajo 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Prueba"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Común"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 5a18823be96c..afcc618bafd3 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Nädalavahetus"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Sündmus"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Magamine"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Haldab <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Sees"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Väljas"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> vaigistab teatud helid"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Töö 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Jagatud"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 625bb00562b2..cf18eb907e1c 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -558,7 +558,7 @@ <string name="permlab_changeTetherState" msgid="9079611809931863861">"aldatu telefono bidezko konektagarritasuna"</string> <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Partekatutako Interneterako konexioaren egoera aldatzeko baimena ematen die aplikazioei."</string> <string name="permlab_accessWifiState" msgid="5552488500317911052">"ikusi wifi-konexioak"</string> - <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Wi-Fi sareei buruzko informazioa ikusteko baimena ematen die aplikazioei, adibidez, Wi-Fi konexioa aktibatuta dagoen eta konektatutako Wi-Fi gailuen izenak zein diren."</string> + <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Wi-Fi sareei buruzko informazioa ikusteko baimena ematen die aplikazioei, adibidez, wifi-konexioa aktibatuta dagoen eta konektatutako Wi-Fi gailuen izenak zein diren."</string> <string name="permlab_changeWifiState" msgid="7947824109713181554">"konektatu wifira edo deskonektatu bertatik"</string> <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Wi-Fi sarbide-puntuetara konektatzeko edo haietatik deskonektatzeko baimena ematen die aplikazioei, baita Wi-Fi sareen gailu-konfigurazioari aldaketak egitekoa ere."</string> <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"onartu Wi-Fi Multicast harrera"</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Asteburua"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Gertaera"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Lo egiteko"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Kudeatzailea: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Aktibatuta"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desaktibatuta"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> soinu batzuk isilarazten ari da"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Lanekoa 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Probakoa"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Partekatua"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index be9c11456296..eb71a7dc3b9e 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -338,7 +338,7 @@ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"نوشتاری را که تایپ میکنید مشاهده کند"</string> <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"اطلاعات شخصی مانند شماره کارت اعتباری و گذرواژهها را لحاظ میکند."</string> <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"کنترل درشتنمایی نمایشگر"</string> - <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"سطح و موقعیت بزرگنمایی نمایشگر را کنترل کنید."</string> + <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"موقعیت و سطح بزرگنمایی نمایشگر را کنترل کنید."</string> <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"اجرای اشارهها"</string> <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"میتوانید ضربه بزنید، انگشتتان را تند بکشید، انگشتانتان را به هم نزدیک یا از هم دور کنید و اشارههای دیگری اجرا کنید."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"اشارههای اثر انگشت"</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"آخر هفته"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"رویداد"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"خوابیدن"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"تحتمدیریت <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"روشن"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"خاموش"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> درحال قطع کردن بعضی از صداهاست"</string> @@ -2340,9 +2339,9 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"به برنامه همراه اجازه میدهد سرویسهای پیشنما را از پسزمینه راهاندازی کند."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"میکروفون دردسترس است"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"میکروفون مسدود شد"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"بازتاب دادن به نمایشگر ممکن نبود"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"قرینهسازی روی نمایشگر ممکن نبود"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"از کابل دیگری استفاده کنید و دوباره امتحان کنید"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"دستگاه بسیار گرم است و تا زمانیکه خنک نشود نمیتواند محتوا را در نمایشگر بازتاب دهد."</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"دستگاه بسیار گرم است و تا زمانیکه خنک نشود نمیتواند محتوا را روی نمایشگر قرینهسازی کند."</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen روشن است"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> از هر دو نمایشگر برای نمایش محتوا استفاده میکند"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"کار ۳"</string> <string name="profile_label_test" msgid="9168641926186071947">"آزمایش"</string> <string name="profile_label_communal" msgid="8743921499944800427">"عمومی"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index d34817e84c08..8359bf6aecff 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Viikonloppuna"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Tapahtuma"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Nukkuminen"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Ylläpitäjä: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Päällä"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Pois päältä"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> mykistää joitakin ääniä"</string> @@ -2342,7 +2341,7 @@ <string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofoni on estetty"</string> <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Näytön peilaaminen ei onnistu"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Käytä eri johtoa ja yritä uudelleen"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Laite on liian kuuma eikä voi peilata näyttöön, kunnes se viilenee"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Laite on liian kuuma eikä voi peilata näyttöön, ennen kuin se viilenee"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Kaksoisnäyttö"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Kaksoisnäyttö on päällä"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> käyttää molempia näyttöjä sisällön näyttämiseen"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Työ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testi"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Jaettu"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index ba7fd5223b3e..8842ae8ce8f3 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fin de semaine"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Événement"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sommeil"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Géré par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activé"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Désactivé"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> désactive certains sons"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Professionnel 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 06b9ec8fae0f..d435c62b9b49 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Week-end"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Événement"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sommeil"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Géré par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activé"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Désactivé"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> coupe certains sons"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Professionnel 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index f599631127fb..703ed7ccad2f 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fin de semana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Durmindo"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Xestionada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activada"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desactivada"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está silenciando algúns sons"</string> @@ -2342,7 +2341,7 @@ <string name="mic_access_off_toast" msgid="8111040892954242437">"O micrófono está bloqueado"</string> <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Non se pode proxectar contido na pantalla"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Cambia de cable e téntao de novo"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"O teu dispositivo está demasiado quente; mentres non arrefríe, non se poderá proxectar contido na pantalla"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"O dispositivo está moi quente; mentres non arrefríe, non se poderá proxectar contido na pantalla"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen está activada"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> está usando ambas as pantallas para mostrar contido"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Traballo 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Proba"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Compartido"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 5e12c7db3cfa..2e1f0e6cfe23 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"સપ્તાહાંત"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ઇવેન્ટ"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"નિષ્ક્રિય"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ચાલુ છે"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"બંધ છે"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> અમુક અવાજોને મ્યૂટ કરે છે"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ઑફિસ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"પરીક્ષણ કરો"</string> <string name="profile_label_communal" msgid="8743921499944800427">"કૉમ્યુનલ"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index a6d70dd6b96b..336d998ccd18 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1226,7 +1226,7 @@ <string name="aerr_report" msgid="3095644466849299308">"फ़ीडबैक भेजें"</string> <string name="aerr_close" msgid="3398336821267021852">"बंद करें"</string> <string name="aerr_mute" msgid="2304972923480211376">"डिवाइस फिर से प्रारंभ होने तक म्यूट करें"</string> - <string name="aerr_wait" msgid="3198677780474548217">"प्रतीक्षा करें"</string> + <string name="aerr_wait" msgid="3198677780474548217">"इंतज़ार करें"</string> <string name="aerr_close_app" msgid="8318883106083050970">"ऐप बंद करें"</string> <string name="anr_title" msgid="7290329487067300120"></string> <string name="anr_activity_application" msgid="8121716632960340680">"<xliff:g id="APPLICATION">%2$s</xliff:g> प्रतिसाद नहीं दे रहा है"</string> @@ -1235,7 +1235,7 @@ <string name="anr_process" msgid="1664277165911816067">"<xliff:g id="PROCESS">%1$s</xliff:g> प्रक्रिया प्रतिसाद नहीं दे रही है"</string> <string name="force_close" msgid="9035203496368973803">"ठीक है"</string> <string name="report" msgid="2149194372340349521">"रिपोर्ट करें"</string> - <string name="wait" msgid="7765985809494033348">"प्रतीक्षा करें"</string> + <string name="wait" msgid="7765985809494033348">"इंतज़ार करें"</string> <string name="webpage_unresponsive" msgid="7850879412195273433">"पेज प्रतिसाद नहीं दे रहा है.\n\nक्या आप इसे बंद करना चाहते हैं?"</string> <string name="launch_warning_title" msgid="6725456009564953595">"ऐप को दूसरे वेबलिंक पर लॉन्च किया गया"</string> <string name="launch_warning_replace" msgid="3073392976283203402">"<xliff:g id="APP_NAME">%1$s</xliff:g> अभी चल रहा है."</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"सप्ताहांत"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"इवेंट"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"सोते समय"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"मैनेज करने वाला ऐप्लिकेशन: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"चालू है"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"बंद है"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> कुछ आवाज़ें म्यूट कर रहा है"</string> @@ -2340,9 +2339,9 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"इससे साथी ऐप्लिकेशन को बैकग्राउंड में फ़ोरग्राउंड सेवाएं चलाने की अनुमति मिलती है."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"माइक्रोफ़ोन इस्तेमाल किया जा सकता है"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"माइक्रोफ़ोन को ब्लॉक किया गया है"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"डिसप्ले का कॉन्टेंट नहीं दिखाया जा सकता"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"कॉन्टेंट डिसप्ले नहीं किया जा सकता"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"कोई दूसरा केबल इस्तेमाल करके फिर से कोशिश करें"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"आपका डिवाइस बहुत गर्म है. इसलिए, इसके ठंडा होने तक दूसरे डिसप्ले पर इसकी स्क्रीन शेयर नहीं की जा सकती"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"आपका डिवाइस बहुत गर्म हो गया है. जब तक यह ठंडा नहीं हो जाता, तब तक दूसरे डिवाइस पर इसकी स्क्रीन डिसप्ले नहीं की जा सकती"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual screen की सुविधा चालू है"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>, कॉन्टेंट दिखाने के लिए दोनों स्क्रीन का इस्तेमाल कर रहा है"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ऑफ़िस 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"टेस्ट"</string> <string name="profile_label_communal" msgid="8743921499944800427">"कम्यूनिटी"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index e574b9aca42d..ec5a77e0c10d 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Vikend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Događaj"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Spavanje"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Upravlja <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Uključeno"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Isključeno"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> isključuje neke zvukove"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Posao 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index a7e67f60dec0..3bcd44be0ffc 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Hétvége"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Esemény"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Alvás"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Kezelő: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Bekapcsolva"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Kikapcsolva"</string> <string name="muted_by" msgid="91464083490094950">"A(z) <xliff:g id="THIRD_PARTY">%1$s</xliff:g> lenémít néhány hangot"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"3. munkahelyi"</string> <string name="profile_label_test" msgid="9168641926186071947">"Teszt"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Közös"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 6e517fb51526..603d7c6332ee 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Շաբաթ-կիրակի"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Միջոցառում"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Քնի ժամանակ"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Կառավարվում է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի կողմից"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Միացված է"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Անջատված է"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>-ն անջատում է որոշ ձայներ"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Աշխատանքային 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Փորձնական"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Ընդհանուր"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index f263f474a061..788628074812 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Akhir pekan"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Acara"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Tidur"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Dikelola oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Aktif"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Nonaktif"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> mematikan beberapa suara"</string> @@ -2342,7 +2341,7 @@ <string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofon diblokir"</string> <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Tidak dapat mencerminkan ke layar"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Gunakan kabel lain dan coba lagi"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Perangkat terlalu panas dan tidak dapat mencerminkan ke layar sampai cukup dingin"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Perangkat terlalu panas dan tidak dapat mencerminkan ke layar sebelum suhunya cukup dingin"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual screen aktif"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> menggunakan kedua layar untuk menampilkan konten"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Kerja 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Pengujian"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 25608cfe65f1..ddf60c12e400 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Helgi"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Viðburður"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Svefn"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Stýrt af <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Kveikt"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Slökkt"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> þaggar í einhverjum hljóðum"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Vinna 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Prófun"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Sameiginlegt"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index a99fbe6954e8..3877ac48d00f 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fine settimana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Notte"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gestione: app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"On"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Off"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> sta disattivando alcuni suoni"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Lavoro 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Condiviso"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 66250b0a3664..eb2f3b2dc6eb 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"סוף השבוע"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"אירוע"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"שינה"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"בניהול של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"מצב פעיל"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"מצב מושבת"</string> <string name="muted_by" msgid="91464083490094950">"חלק מהצלילים מושתקים על ידי <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"פרופיל עבודה 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"בדיקה"</string> <string name="profile_label_communal" msgid="8743921499944800427">"שיתופי"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 8b87228e2576..a2d40afb5a38 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -322,7 +322,7 @@ <string name="permgrouplab_camera" msgid="9090413408963547706">"カメラ"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"写真と動画の撮影"</string> <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"付近のデバイス"</string> - <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"付近のデバイスの\\n検出と接続"</string> + <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"付近のデバイスの検出と接続"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"通話履歴"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"通話履歴の読み取りと書き込み"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"電話"</string> @@ -1872,7 +1872,7 @@ <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 番目の仕事用<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 番目の仕事用<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> のクローン"</string> - <string name="private_profile_label_badge" msgid="1712086003787839183">"個人用<xliff:g id="LABEL">%1$s</xliff:g>"</string> + <string name="private_profile_label_badge" msgid="1712086003787839183">"プライベートの<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"オフライン再生を解除する前にPINの入力を求める"</string> <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"画面固定を解除する前にロック解除パターンの入力を求める"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"オフライン再生を解除する前にパスワードの入力を求める"</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"週末"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"予定"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"睡眠中"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> によって管理されています"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ON"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"OFF"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> により一部の音はミュートに設定"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"仕事用 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"テスト"</string> <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 839a81799c80..dee1f1f33339 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"შაბათ-კვირა"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"მოვლენა"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"ძილისას"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"მართავს <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ჩართული"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"გამორთული"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ზოგიერთ ხმას ადუმებს"</string> @@ -2342,7 +2341,7 @@ <string name="mic_access_off_toast" msgid="8111040892954242437">"მიკროფონი დაბლოკილია"</string> <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"ეკრანზე არეკვლა შეუძლებელია"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"გამოიყენეთ სხვა კაბელი და ცადეთ ხელახლა"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"თქვენი მოწყობილობა ძალიან თბილია და ვერ ასახავს ეკრანზე სანამ არ გაგრილდება"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"თქვენი მოწყობილობა ძალიან თბილია და ეკრანზე არეკვლას ვერ მოახერხებს, სანამ არ გაგრილდება"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"ორმაგი ეკრანი"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"ორმაგი ეკრანი ჩართულია"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> იყენებს ორივე ეკრანს შინაარსის საჩვენებლად"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"სამსახური 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"სატესტო"</string> <string name="profile_label_communal" msgid="8743921499944800427">"საერთო"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 45abbef036c3..4cf61ac9b248 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Демалыс күндері"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Іс-шара"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Ұйқы режимі"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> басқарады."</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Қосулы"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Өшірулі"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> кейбір дыбыстарды өшіруде"</string> @@ -2340,8 +2339,8 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Серік қолданбаға экрандық режимдегі қызметтерді фоннан іске қосуға рұқсат беріледі."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофон қолжетімді."</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофон блокталған."</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Дисплейге көшірмені көрсету мүмкін емес"</string> - <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Басқа кабельмен әрекетті қайталап көріңіз."</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Экран көшірмесін көрсету мүмкін емес"</string> + <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Басқа кабельмен көріңіз."</string> <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Құрылғыңыз тым қызып кетті, сондықтан ол суымайынша, дисплейге экран көшірмесін көрсете алмайды."</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual Screen функциясы қосулы"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Жұмыс 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Сынақ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Жалпы"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 3aec1f640daa..7973f2a0b4fe 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"ចុងសប្ដាហ៍"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ព្រឹត្តិការណ៍"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"កំពុងដេក"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"គ្រប់គ្រងដោយ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"បើក"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"បិទ"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> កំពុងបិទសំឡេងមួយចំនួន"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ការងារទី 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ការធ្វើតេស្ត"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ទូទៅ"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 388fe2036872..7e5e5b5b9ec9 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"ವಾರಾಂತ್ಯ"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ಈವೆಂಟ್"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"ನಿದ್ರೆಯ ಸಮಯ"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ಆನ್ ಆಗಿದೆ"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ಆಫ್ ಆಗಿದೆ"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ಧ್ವನಿ ಮ್ಯೂಟ್ ಮಾಡುತ್ತಿದ್ದಾರೆ"</string> @@ -2340,7 +2339,7 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಹಿನ್ನೆಲೆಯಿಂದ ಪ್ರಾರಂಭಿಸಲು ಕಂಪ್ಯಾನಿಯನ್ ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"ಮೈಕ್ರೊಫೋನ್ ಲಭ್ಯವಿದೆ"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"ಬೇರೆ ಕೇಬಲ್ ಬಳಸಿ ಹಾಗೂ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string> <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"ನಿಮ್ಮ ಸಾಧನವು ತುಂಬಾ ಬಿಸಿಯಾಗಿದೆ ಮತ್ತು ಅದು ತಣ್ಣಗಾಗುವವರೆಗೆ ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ಕೆಲಸ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ಪರೀಕ್ಷೆ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ಸಮುದಾಯ"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index f002fd526884..cfc7730d8c12 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"주말"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"캘린더 일정"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"수면 시간"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"관리자: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"사용"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"사용 중지"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>(이)가 일부 소리를 음소거함"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"직장 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"테스트"</string> <string name="profile_label_communal" msgid="8743921499944800427">"공동"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 73161e468f89..dcdfc8020929 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Дем алыш"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Иш-чара"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Уйку режими"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> башкарат"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Күйүк"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Өчүк"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> айрым үндөрдү өчүрүүдө"</string> @@ -2340,7 +2339,7 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Көмөкчү колдонмого активдүү кызматтарды фондо иштетүүгө уруксат берет."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофон жеткиликтүү"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофон бөгөттөлгөн"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Экранга күзгүдөй чагылдыруу мүмкүн эмес"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Башка экранга чыгаруу мүмкүн эмес"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Башка кабелди колдонуп, кайра аракет кылыңыз"</string> <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Түзмөгүңүз өтө ысып кетти жана ал муздамайынча башка экранга чыгара албайт"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Кош экран"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Жумуш 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Сыноо"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Жалпы"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index e687436fbe89..49266a4b9447 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"ທ້າຍອາທິດ"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ການນັດໝາຍ"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"ການນອນ"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"ຈັດການໂດຍ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ເປີດຢູ່"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ປິດຢູ່"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ປິດສຽງບາງຢ່າງໄວ້"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ວຽກ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ທົດສອບ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ສ່ວນກາງ"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index b3c9f37ce8b6..aefda2e88bed 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1908,8 +1908,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Savaitgalį"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Įvykis"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Miegas"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Tvarko „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Įjungti"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Išjungti"</string> <string name="muted_by" msgid="91464083490094950">"„<xliff:g id="THIRD_PARTY">%1$s</xliff:g>“ nutildo kai kuriuos garsus"</string> @@ -2368,4 +2367,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Darbas (3)"</string> <string name="profile_label_test" msgid="9168641926186071947">"Bandymas"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Bendruomenės"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index a14e7c587352..f17f02fde8d6 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Nedēļas nogalē"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Pasākums"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Gulēšana"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Pārvalda <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Ieslēgta"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Izslēgta"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> izslēdz noteiktas skaņas"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Darbam (3.)"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testēšanai"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Kopīgs"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index e4ba9fa692fe..dbcf11f1b3b0 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Викенд"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Настан"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Спиење"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Управувано од <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Вклучено"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Исклучено"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> исклучи некои звуци"</string> @@ -2340,7 +2339,7 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Дозволува придружна апликација да започне услуги во преден план од заднината."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофонот е достапен"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофонот е блокиран"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Не може да се отсликува за прикажување"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Не може да се отслика екранот"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Користете друг кабел и обидете се повторно"</string> <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Вашиот уред е премногу топол и не може да се отсликува на екранот додека не се излади"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Работен профил 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Профил за тестирање"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Профил на заедницата"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 8aa2c9a177f4..68c0749f32c8 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"വാരാന്ത്യം"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ഇവന്റ്"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"ഉറക്കം"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യുന്നത്"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ഓണാണ്"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ഓഫാണ്"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ചില ശബ്ദങ്ങൾ മ്യൂട്ട് ചെയ്യുന്നു"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ഔദ്യോഗികം 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ടെസ്റ്റ്"</string> <string name="profile_label_communal" msgid="8743921499944800427">"കമ്മ്യൂണൽ"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 27bcd80b601a..97858ef2048f 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Амралтын өдөр"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Үйл явдал"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Унтлагын цаг"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g>-с удирддаг"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Асаалттай"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Унтраалттай"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> зарим дууны дууг хааж байна"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Ажил 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Туршилт"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Нийтийн"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 48d4fdb92e74..cd553a484a08 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"आठवड्याच्या शेवटी"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"इव्हेंट"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"झोपताना"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> द्वारे व्यवस्थापित"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"सुरू आहे"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"बंद आहे"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> काही ध्वनी म्यूट करत आहे"</string> @@ -2342,7 +2341,7 @@ <string name="mic_access_off_toast" msgid="8111040892954242437">"मायक्रोफोन ब्लॉक केलेला आहे"</string> <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"डिस्प्लेवर मिरर करू शकत नाही"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"वेगळी केबल वापरून पुन्हा प्रयत्न करा"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"तुमचे डिव्हाइस खूप गरम आहे आणि ते थंड होईपर्यंत डिस्प्लेमध्ये मिरर करू शकत नाही"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"तुमचे डिव्हाइस खूप गरम आहे आणि ते थंड होईपर्यंत डिस्प्लेवर मिरर करू शकत नाही"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual screen सुरू आहे"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"आशय दाखवण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> दोन्ही डिस्प्ले वापरत आहे"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ऑफिस ३"</string> <string name="profile_label_test" msgid="9168641926186071947">"चाचणी"</string> <string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 5254490e0b95..90ffb215210e 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Hujung minggu"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Acara"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Tidur"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Diurus oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Hidup"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Mati"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> meredamkan sesetengah bunyi"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Kerja 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Ujian"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 9e8a4a9931e5..fa5efa6d2344 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"စနေ၊ တနင်္ဂနွေ"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"အစီအစဉ်"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"အိပ်နေချိန်"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စီမံသည်"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ဖွင့်"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ပိတ်"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> သည် အချို့အသံကို ပိတ်နေသည်"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"အလုပ် ၃"</string> <string name="profile_label_test" msgid="9168641926186071947">"စမ်းသပ်မှု"</string> <string name="profile_label_communal" msgid="8743921499944800427">"အများသုံး"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 196f98dbba21..f97e43732fe7 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Helg"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Aktivitet"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sover"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Administreres av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"På"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Av"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> slår av noen lyder"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Jobb 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Felles"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 141146353770..99dcae018fa5 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -978,7 +978,7 @@ <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फेरि प्रयास गर्नुहोस्"</string> <string name="lockscreen_password_wrong" msgid="8605355913868947490">"फेरि प्रयास गर्नुहोस्"</string> <string name="lockscreen_storage_locked" msgid="634993789186443380">"सबै सुविधाहरू र डेटाका लागि अनलक गर्नुहोस्"</string> - <string name="faceunlock_multiple_failures" msgid="681991538434031708">"फेस अनलक प्रयोग गरी अनलक गर्ने प्रयास अत्याधिक धेरै भयो"</string> + <string name="faceunlock_multiple_failures" msgid="681991538434031708">"फेस अनलक प्रयोग गरी अनलक गर्ने प्रयास अत्यधिक धेरै भयो"</string> <string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"SIM कार्ड हालिएको छैन"</string> <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"ट्याब्लेटमा SIM कार्ड हालिएको छैन।"</string> <string name="lockscreen_missing_sim_message" product="tv" msgid="3903140876952198273">"तपाईंको Android TV डिभाइसमा SIM कार्ड हालिएको छैन।"</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"शनिबार"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"कार्यक्रम"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"निदाएका बेला"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले व्यवस्थापन गरेको"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"अन छ"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"अफ छ"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ले केही ध्वनिहरू म्युट गर्दै छ"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"कार्य प्रोफाइल ३"</string> <string name="profile_label_test" msgid="9168641926186071947">"परीक्षण"</string> <string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index c41dae729cc1..f0d34a58e2f3 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Afspraken"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Slapen"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Beheerd door <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Aan"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Uit"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> zet sommige geluiden uit"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Werk 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Gemeenschappelijk"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 7a1b7f40d268..bfde6c960e53 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -277,7 +277,7 @@ <string name="notification_channel_account" msgid="6436294521740148173">"ଆକାଉଣ୍ଟର ସ୍ଥିତି"</string> <string name="notification_channel_developer" msgid="1691059964407549150">"ଡେଭଲପରଙ୍କ ମେସେଜ୍"</string> <string name="notification_channel_developer_important" msgid="7197281908918789589">"ଗୁରୁତ୍ଵପୂର୍ଣ୍ଣ ଡେଭେଲପର୍ ମେସେଜ୍ଗୁଡ଼ିକ"</string> - <string name="notification_channel_updates" msgid="7907863984825495278">"ଅପଡେଟ୍"</string> + <string name="notification_channel_updates" msgid="7907863984825495278">"ଅପଡେଟ କରନ୍ତୁ"</string> <string name="notification_channel_network_status" msgid="2127687368725272809">"ନେଟୱର୍କ ସ୍ଥିତି"</string> <string name="notification_channel_network_alerts" msgid="6312366315654526528">"ନେଟୱର୍କ ଅଲର୍ଟ"</string> <string name="notification_channel_network_available" msgid="6083697929214165169">"ନେଟ୍ୱର୍କ ଉପଲବ୍ଧ ଅଛି"</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"ସପ୍ତାହାନ୍ତ"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ଇଭେଣ୍ଟ"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"ଶୋଇବା"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳିତ"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ଚାଲୁ ଅଛି"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ବନ୍ଦ ଅଛି"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> କିଛି ସାଉଣ୍ଡକୁ ମ୍ୟୁଟ୍ କରୁଛି"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ୱାର୍କ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ଟେଷ୍ଟ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"କମ୍ୟୁନାଲ"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index cccb3ddde524..d3901f743701 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"ਹਫ਼ਤੇ ਦਾ ਅੰਤਲਾ ਦਿਨ"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ਇਵੈਂਟ"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"ਸੌਣ ਵੇਲੇ"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ਚਾਲੂ ਹੈ"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ਬੰਦ ਹੈ"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ਕੁਝ ਧੁਨੀਆਂ ਨੂੰ ਮਿਊਟ ਕਰ ਰਹੀ ਹੈ"</string> @@ -1921,7 +1920,7 @@ <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS ਬੇਨਤੀ ਨੂੰ ਵੀਡੀਓ ਕਾਲ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string> <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS ਬੇਨਤੀ ਨੂੰ USSD ਬੇਨਤੀ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string> <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ਨਵੀਂ SS ਬੇਨਤੀ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string> - <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ਫ਼ਿਸ਼ਿੰਗ ਸੰਬੰਧੀ ਸੁਚੇਤਨਾ"</string> + <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ਫ਼ਿਸ਼ਿੰਗ ਸੰਬੰਧੀ ਅਲਰਟ"</string> <string name="notification_work_profile_content_description" msgid="5296477955677725799">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string> <string name="notification_alerted_content_description" msgid="6139691253611265992">"ਸੁਚੇਤਨਾਵਾਂ"</string> <string name="notification_verified_content_description" msgid="6401483602782359391">"ਪੁਸ਼ਟੀਕਿਰਤ"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ਕੰਮ ਸੰਬੰਧੀ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ਜਾਂਚ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ਭਾਈਚਾਰਕ"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 5143e9e952ee..e03679bbc27e 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1908,8 +1908,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Wydarzenie"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Sen"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Zarządzana przez aplikację <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Włączono"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Wyłączono"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> wycisza niektóre dźwięki"</string> @@ -2344,7 +2343,7 @@ <string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofon jest zablokowany"</string> <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Nie można utworzyć odbicia lustrzanego na wyświetlaczu"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Użyj innego kabla i spróbuj ponownie"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Urządzenie ma zbyt wysoką temperaturę i nie może utworzyć odbicia lustrzanego zawartości ekranu, dopóki się nie ochłodzi."</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Urządzenie jest zbyt ciepłe i nie może utworzyć odbicia lustrzanego zawartości ekranu, dopóki się nie ochłodzi."</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Podwójny ekran"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Włączono podwójny ekran"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> korzysta z obu wyświetlaczy, aby pokazać treści"</string> @@ -2368,4 +2367,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Służbowy 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testowy"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Wspólny"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index f7b6b0bd1201..2888c5f7e027 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fim de semana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Dormir"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gerenciada pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Ativada"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desativada"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está silenciando alguns sons"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Público"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 5e6cc3ede497..7a3201fca3b3 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fim de semana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"A dormir"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gerido por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Ativada"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desativada"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está a desativar alguns sons."</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Comum"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index f7b6b0bd1201..2888c5f7e027 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fim de semana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Dormir"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gerenciada pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Ativada"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Desativada"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> está silenciando alguns sons"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Público"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index b5b411e2ae43..082fbb24c969 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Eveniment"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Somn"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gestionat de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activată"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Dezactivată"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> dezactivează anumite sunete"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Serviciu 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Comun"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 6948a1a9e3ff..8a03a6b18ae7 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1908,8 +1908,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Выходные"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Мероприятие"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Время сна"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Под управлением приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Включено"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Отключено"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> приглушает некоторые звуки."</string> @@ -2342,9 +2341,9 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Сопутствующее приложение сможет запускать активные службы из фонового режима."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофон доступен."</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофон заблокирован."</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Не удается дублировать на экран"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Не удается дублировать экран"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Используйте другой кабель или повторите попытку."</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Ваше устройство слишком сильно нагрелось. Когда оно остынет, вы снова сможете передавать изображение на другой экран."</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Устройство слишком нагрелось и не может дублировать экран. Подождите, пока оно остынет."</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Функция Dual Screen включена"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> использует оба экрана."</string> @@ -2368,4 +2367,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Рабочий 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тестовый"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Совместный"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 7ed085d5c4d1..89ee9f910257 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"සති අන්තය"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"සිදුවීම"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"නිදා ගනිමින්"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> විසින් කළමනාකරණය කරයි"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ක්රියාත්මකයි"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ක්රියාවිරහිතයි"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> සමහර ශබ්ද නිහඬ කරමින්"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"කාර්යාලය 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"පරීක්ෂණය"</string> <string name="profile_label_communal" msgid="8743921499944800427">"වාර්ගික"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index b6dd850db81a..bbfefd162c7f 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1908,8 +1908,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Víkend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Udalosť"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Spánok"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Spravované aplikáciou <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Zapnuté"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Vypnuté"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> vypína niektoré zvuky"</string> @@ -2368,4 +2367,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"3. pracovný"</string> <string name="profile_label_test" msgid="9168641926186071947">"Testovací"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Spoločný"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index df7e61409211..e4e9a37fdc36 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1908,8 +1908,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Konec tedna"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Dogodek"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Spanje"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Upravlja <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Vklopljeno"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Izklopljeno"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> izklaplja nekatere zvoke"</string> @@ -2342,7 +2341,7 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Spremljevalni aplikaciji dovoljuje, da storitve v ospredju zažene iz ozadja."</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"Mikrofon je na voljo"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"Mikrofon je blokiran"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Ni mogoče zrcaliti zaslona"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Ni mogoče zrcaliti v zaslon"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Uporabite drug kabel in poskusite znova"</string> <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Naprava je pretopla in ne more zrcaliti v zaslon, dokler se ne ohladi"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string> @@ -2368,4 +2367,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Delo 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Preizkus"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Skupno"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index f84966b3bfe8..288d8bf5acf9 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fundjava"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Ngjarje"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Në gjumë"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Menaxhohet nga <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Aktivizuar"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Çaktivizuar"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> po çaktivizon disa tinguj"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Puna 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"I përbashkët"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index f37fe054cc52..479a1db277ed 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1907,8 +1907,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Викенд"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Догађај"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Спавање"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Управља: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Укључено"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Искључено"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> искључује неке звуке"</string> @@ -2367,4 +2366,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Посао 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тест"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Заједничко"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index cbba6d445371..a30aa0a012a6 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1614,7 +1614,7 @@ <string name="fingerprints" msgid="148690767172613723">"Fingeravtryck:"</string> <string name="sha256_fingerprint" msgid="7103976380961964600">"SHA-256-fingeravtryck"</string> <string name="sha1_fingerprint" msgid="2339915142825390774">"SHA-1-fingeravtryck:"</string> - <string name="activity_chooser_view_see_all" msgid="3917045206812726099">"Visa alla"</string> + <string name="activity_chooser_view_see_all" msgid="3917045206812726099">"Se alla"</string> <string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"Välj aktivitet"</string> <string name="share_action_provider_share_with" msgid="1904096863622941880">"Dela med"</string> <string name="sending" msgid="206925243621664438">"Skickar ..."</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"I helgen"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Händelse"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"När jag sover"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Hanteras av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"På"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Av"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> stänger av vissa ljud"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Arbete 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Allmän"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index ae9c3f8dfee6..2ff302df7a21 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Wikendi"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Tukio"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Kulala"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Inadhibitiwa na <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Imewashwa"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Imezimwa"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> inazima baadhi ya sauti"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Wa 3 wa Kazini"</string> <string name="profile_label_test" msgid="9168641926186071947">"Jaribio"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Unaoshirikiwa"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index cfa5c72e2c2e..23402f7e38a5 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"வார இறுதி"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"நிகழ்வு"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"உறக்கத்தில்"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"நிர்வகிப்பது: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ஆன்"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ஆஃப்"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> சில ஒலிகளை முடக்குகிறது"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"பணி 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"பரிசோதனை"</string> <string name="profile_label_communal" msgid="8743921499944800427">"பொது"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 52d7539e333c..30697b34e357 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"వారాంతం"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ఈవెంట్"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"నిద్రావస్థ"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> ద్వారా మేనేజ్ చేయబడుతోంది"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"ఆన్లో ఉంది"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ఆఫ్లో ఉంది"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> కొన్ని ధ్వనులను మ్యూట్ చేస్తోంది"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"ఆఫీస్ 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"పరీక్ష"</string> <string name="profile_label_communal" msgid="8743921499944800427">"కమ్యూనల్"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 759b6e46df14..66ed0539cb5e 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"สุดสัปดาห์"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"กิจกรรม"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"นอนหลับ"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"จัดการโดย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"เปิด"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"ปิด"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> กำลังปิดเสียงบางรายการ"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"งาน 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"ทดสอบ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"ส่วนกลาง"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 650b3fe40dc1..c83daa31e372 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Weekend"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Event"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Pag-sleep"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Pinapamahalaan ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Naka-on"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Naka-off"</string> <string name="muted_by" msgid="91464083490094950">"Minu-mute ng <xliff:g id="THIRD_PARTY">%1$s</xliff:g> ang ilang tunog"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabaho 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 9e84fdd8eade..c2c8ec655610 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Hafta sonu"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Etkinlik"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Uyku"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> tarafından yönetiliyor"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Açık"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Kapalı"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> bazı sesleri kapatıyor"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"İş 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Paylaşılan"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 2772eb490f21..00139a635826 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1908,8 +1908,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"На вихідних"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Подія"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Під час сну"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Керує додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Увімкнено"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Вимкнено"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> вимикає деякі звуки"</string> @@ -2368,4 +2367,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Робочий профіль 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Тестовий профіль"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Спільний профіль"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 03246979d613..dc3ca4752c75 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"ویک اینڈ"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"ایونٹ"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"سونا"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے زیر انتظام ہے"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"آن ہے"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"آف ہے"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> کچھ آوازوں کو خاموش کر رہا ہے"</string> @@ -2340,9 +2339,9 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"ساتھی ایپ کو پس منظر سے پیش منظر کی سروسز شروع کرنے کی اجازت دیتی ہے۔"</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"مائیکروفون دستیاب ہے"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"مائیکروفون مسدود ہے"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"ڈسپلے پر دو طرفہ مطابقت پذیری ممکن نہیں ہے"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"ڈسپلے پر مرر نہیں ہو سکتا"</string> <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"مختلف کیبل استعمال کریں اور دوبارہ کوشش کریں"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"آپ کا آلہ بہت گرم ہے اور جب تک یہ ٹھنڈا نہیں ہو جاتا اس وقت تک ڈسپلے میں عکس دو طرفہ مطابقت پذیر نہیں ہو سکتا"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"آپ کا آلہ بہت گرم ہے اور جب تک یہ ٹھنڈا نہیں ہو جاتا اس وقت تک ڈسپلے پر مرر نہیں ہو سکتا"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"دوہری اسکرین"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"دوہری اسکرین آن ہے"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"مواد دکھانے کیلئے <xliff:g id="APP_NAME">%1$s</xliff:g> دونوں ڈسپلیز استعمال کر رہی ہے"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"تیسری دفتری پروفائل"</string> <string name="profile_label_test" msgid="9168641926186071947">"ٹیسٹ"</string> <string name="profile_label_communal" msgid="8743921499944800427">"کمیونل"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 1a8328849214..23ef54caaa9f 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Dam olish kunlari"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Tadbir"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Uyquda"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"<xliff:g id="APP_NAME">%1$s</xliff:g> tomonidan boshqariladi"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Yoniq"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Oʻchiq"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ayrim tovushlarni ovozsiz qilgan"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Ish 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Umumiy"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index a6c64eeccf55..22d9f068b343 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Cuối tuần"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Sự kiện"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Ngủ"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Do <xliff:g id="APP_NAME">%1$s</xliff:g> quản lý"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Bật"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Tắt"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> đang tắt một số âm thanh"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Công việc 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Kiểm thử"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Dùng chung"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 4b64daf29264..dec4705a255d 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1882,8 +1882,8 @@ <string name="confirm_battery_saver" msgid="5247976246208245754">"确定"</string> <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"在省电模式下,系统会启用深色主题,并限制或关闭后台活动、某些视觉效果、特定功能和部分网络连接。"</string> <string name="battery_saver_description" msgid="8518809702138617167">"在省电模式下,系统会启用深色主题,并限制或关闭后台活动、某些视觉效果、特定功能和部分网络连接。"</string> - <string name="data_saver_description" msgid="4995164271550590517">"为了减少流量消耗,流量节省程序会阻止某些应用在后台收发数据。您当前使用的应用可以收发数据,但频率可能会降低。举例而言,这可能意味着图片只有在您点按之后才会显示。"</string> - <string name="data_saver_enable_title" msgid="7080620065745260137">"要开启流量节省程序吗?"</string> + <string name="data_saver_description" msgid="4995164271550590517">"为了减少流量消耗,省流模式会阻止某些应用在后台收发数据。您当前使用的应用可以收发数据,但频率可能会降低。举例而言,这可能意味着图片只有在您点按之后才会显示。"</string> + <string name="data_saver_enable_title" msgid="7080620065745260137">"要开启省流模式吗?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"开启"</string> <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{1 分钟(直到 {formattedTime})}other{# 分钟(直到 {formattedTime})}}"</string> <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{1 分钟(直到 {formattedTime})}other{# 分钟(直到 {formattedTime})}}"</string> @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"周末"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"活动"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"睡眠"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"由<xliff:g id="APP_NAME">%1$s</xliff:g>管理"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"已启用"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"已停用"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>正在将某些音效设为静音"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"测试"</string> <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 9610a38e0aff..769c274c11e3 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"週末"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"活動"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"睡眠"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"由<xliff:g id="APP_NAME">%1$s</xliff:g>管理"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"已開啟"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"已關閉"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>正將某些音效設為靜音"</string> @@ -2340,9 +2339,9 @@ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"允許隨附應用程式從背景啟動前景服務。"</string> <string name="mic_access_on_toast" msgid="2666925317663845156">"可以使用麥克風"</string> <string name="mic_access_off_toast" msgid="8111040892954242437">"已封鎖麥克風"</string> - <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"無法將畫面鏡像投放至螢幕"</string> - <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"請改用其他連接線,然後再試一次"</string> - <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"裝置過熱,請等到降溫後再將畫面鏡像投射至螢幕"</string> + <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"無法鏡像投放"</string> + <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"請改用其他連接線再試"</string> + <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"裝置過熱,降溫後才可鏡像投放至螢幕"</string> <string name="concurrent_display_notification_name" msgid="1526911253558311131">"雙螢幕"</string> <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"已開啟雙螢幕功能"</string> <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在使用雙螢幕顯示內容"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"測試"</string> <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 6164be550368..2c8c0465a4bf 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"週末"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"活動"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"睡眠"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"由「<xliff:g id="APP_NAME">%1$s</xliff:g>」管理"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"已啟用"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"已停用"</string> <string name="muted_by" msgid="91464083490094950">"「<xliff:g id="THIRD_PARTY">%1$s</xliff:g>」正在關閉部分音效"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"測試"</string> <string name="profile_label_communal" msgid="8743921499944800427">"通用"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index f2a23bc4ecf5..42f0b3ffb8be 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1906,8 +1906,7 @@ <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Ngempelasonto"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Umcimbi"</string> <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Ulele"</string> - <!-- no translation found for zen_mode_implicit_trigger_description (5714956693073007111) --> - <skip /> + <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Iphethwe yi-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Kuvuliwe"</string> <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Kuvaliwe"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ithulisa eminye imisindo"</string> @@ -2366,4 +2365,5 @@ <string name="profile_label_work_3" msgid="4834572253956798917">"Umsebenzi 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Hlola"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Okomphakathi"</string> + <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 804e9ef8476b..806be9471ae5 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4017,6 +4017,18 @@ by shrinking the display such that it does not overlap the cutout area. --> <bool name="config_maskMainBuiltInDisplayCutout">false</bool> + <!-- This string array provide override side of each rotation of the given insets. + Array of "[rotation],[side]". + Undefined rotation will apply the default behavior. + When there are cutouts on multiple edges of the display, the override won't take any + effect. --> + <string-array name="config_mainBuiltInDisplayCutoutSideOverride" translatable="false"> + <!-- Example: + <item>90,top</item> + <item>270,bottom</item> + --> + </string-array> + <!-- Ultrasound support for Mic/speaker path --> <!-- Whether the default microphone audio source supports near-ultrasound frequencies (range of 18 - 21 kHz). --> @@ -6373,6 +6385,8 @@ </string> <bool name="config_fillSecondaryBuiltInDisplayCutout">false</bool> <bool name="config_maskSecondaryBuiltInDisplayCutout">false</bool> + <string-array name="config_secondaryBuiltInDisplayCutoutSideOverride" translatable="false"> + </string-array> <!-- An array contains unique ids of all built-in displays and the unique id of a display can be obtained from {@link Display#getUniqueId}. This array should be set for multi-display @@ -6418,6 +6432,11 @@ <item>@string/config_secondaryBuiltInDisplayCutoutRectApproximation</item> </string-array> + <array name="config_displayCutoutSideOverrideArray" translatable="false"> + <item>@array/config_mainBuiltInDisplayCutoutSideOverride</item> + <item>@array/config_secondaryBuiltInDisplayCutoutSideOverride</item> + </array> + <!-- The maskBuiltInDisplayCutout config for each display in a multi-display device. --> <array name="config_maskBuiltInDisplayCutoutArray" translatable="false"> <item>@bool/config_maskMainBuiltInDisplayCutout</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9589fb00fd5d..b0a4c16b0551 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4036,6 +4036,7 @@ <java-symbol type="string" name="global_action_logout" /> <java-symbol type="string" name="config_mainBuiltInDisplayCutout" /> <java-symbol type="string" name="config_mainBuiltInDisplayCutoutRectApproximation" /> + <java-symbol type="array" name="config_mainBuiltInDisplayCutoutSideOverride" /> <java-symbol type="drawable" name="messaging_user" /> <java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" /> <java-symbol type="drawable" name="ic_logout" /> @@ -5002,9 +5003,11 @@ <java-symbol type="string" name="config_secondaryBuiltInDisplayCutoutRectApproximation" /> <java-symbol type="bool" name="config_fillSecondaryBuiltInDisplayCutout" /> <java-symbol type="bool" name="config_maskSecondaryBuiltInDisplayCutout" /> + <java-symbol type="array" name="config_secondaryBuiltInDisplayCutoutSideOverride" /> <java-symbol type="array" name="config_displayUniqueIdArray" /> <java-symbol type="array" name="config_displayCutoutPathArray" /> <java-symbol type="array" name="config_displayCutoutApproximationRectArray" /> + <java-symbol type="array" name="config_displayCutoutSideOverrideArray" /> <java-symbol type="array" name="config_fillBuiltInDisplayCutoutArray" /> <java-symbol type="array" name="config_maskBuiltInDisplayCutoutArray" /> <java-symbol type="dimen" name="secondary_waterfall_display_left_edge_size" /> diff --git a/core/sysprop/FoldLockBehaviorProperties.sysprop b/core/sysprop/FoldLockBehaviorProperties.sysprop index d337954ff2a0..120e4bbc743a 100644 --- a/core/sysprop/FoldLockBehaviorProperties.sysprop +++ b/core/sysprop/FoldLockBehaviorProperties.sysprop @@ -22,3 +22,11 @@ prop { scope: Internal access: Readonly } + +prop { + api_name: "fold_grace_period_enabled" + type: Boolean + prop_name: "persist.fold_grace_period_enabled" + scope: Internal + access: Readonly +} diff --git a/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java deleted file mode 100644 index 785a8a1ced60..000000000000 --- a/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java +++ /dev/null @@ -1,73 +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 android.app.servertransaction; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.doReturn; - -import android.app.Activity; -import android.app.ClientTransactionHandler; -import android.content.Context; -import android.content.res.Configuration; -import android.os.IBinder; -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link ActivityConfigurationChangeItem}. - * - * Build/Install/Run: - * atest FrameworksCoreTests:ActivityConfigurationChangeItemTest - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -@Presubmit -public class ActivityConfigurationChangeItemTest { - - @Mock - private ClientTransactionHandler mHandler; - @Mock - private IBinder mToken; - @Mock - private Activity mActivity; - // Can't mock final class. - private final Configuration mConfiguration = new Configuration(); - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testGetContextToUpdate() { - doReturn(mActivity).when(mHandler).getActivity(mToken); - - final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem - .obtain(mToken, mConfiguration); - final Context context = item.getContextToUpdate(mHandler); - - assertEquals(mActivity, context); - } -} diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java new file mode 100644 index 000000000000..b5e8203c51ed --- /dev/null +++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java @@ -0,0 +1,239 @@ +/* + * 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.servertransaction; + +import static android.content.Context.DEVICE_ID_DEFAULT; +import static android.view.Display.DEFAULT_DISPLAY; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.app.Activity; +import android.app.ActivityThread; +import android.app.ClientTransactionHandler; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.os.IBinder; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.util.ArrayMap; +import android.util.MergedConfiguration; +import android.view.IWindow; +import android.view.InsetsState; +import android.window.ClientWindowFrames; +import android.window.WindowContext; +import android.window.WindowContextInfo; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for subtypes of {@link ClientTransactionItem}. + * + * Build/Install/Run: + * atest FrameworksCoreTests:ClientTransactionItemTest + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class ClientTransactionItemTest { + + @Mock + private ClientTransactionHandler mHandler; + @Mock + private IBinder mActivityToken; + @Mock + private Activity mActivity; + @Mock + private PendingTransactionActions mPendingActions; + @Mock + private IBinder mWindowClientToken; + @Mock + private WindowContext mWindowContext; + @Mock + private IWindow mWindow; + + // Can't mock final class. + private Configuration mGlobalConfig; + private Configuration mConfiguration; + private ActivityThread.ActivityClientRecord mActivityClientRecord; + private ArrayMap<IBinder, DestroyActivityItem> mActivitiesToBeDestroyed; + private InsetsState mInsetsState; + private ClientWindowFrames mFrames; + private MergedConfiguration mMergedConfiguration; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mGlobalConfig = new Configuration(); + mConfiguration = new Configuration(); + mActivitiesToBeDestroyed = new ArrayMap<>(); + mActivityClientRecord = new ActivityThread.ActivityClientRecord(); + mInsetsState = new InsetsState(); + mFrames = new ClientWindowFrames(); + mMergedConfiguration = new MergedConfiguration(mGlobalConfig, mConfiguration); + + doReturn(mActivity).when(mHandler).getActivity(mActivityToken); + doReturn(mActivitiesToBeDestroyed).when(mHandler).getActivitiesToBeDestroyed(); + } + + @Test + public void testActivityConfigurationChangeItem_getContextToUpdate() { + final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem + .obtain(mActivityToken, mConfiguration); + final Context context = item.getContextToUpdate(mHandler); + + assertEquals(mActivity, context); + } + + @Test + public void testActivityRelaunchItem_getContextToUpdate() { + final ActivityRelaunchItem item = ActivityRelaunchItem + .obtain(mActivityToken, null /* pendingResults */, null /* pendingNewIntents */, + 0 /* configChange */, mMergedConfiguration, false /* preserveWindow */); + final Context context = item.getContextToUpdate(mHandler); + + assertEquals(mActivity, context); + } + + @Test + public void testConfigurationChangeItem_getContextToUpdate() { + final ConfigurationChangeItem item = ConfigurationChangeItem + .obtain(mConfiguration, DEVICE_ID_DEFAULT); + final Context context = item.getContextToUpdate(mHandler); + + assertEquals(ActivityThread.currentApplication(), context); + } + + @Test + public void testDestroyActivityItem_preExecute() { + final DestroyActivityItem item = DestroyActivityItem + .obtain(mActivityToken, false /* finished */, 123 /* configChanges */); + item.preExecute(mHandler); + + assertEquals(1, mActivitiesToBeDestroyed.size()); + assertEquals(item, mActivitiesToBeDestroyed.get(mActivityToken)); + } + + @Test + public void testDestroyActivityItem_postExecute() { + final DestroyActivityItem item = DestroyActivityItem + .obtain(mActivityToken, false /* finished */, 123 /* configChanges */); + item.preExecute(mHandler); + item.postExecute(mHandler, mPendingActions); + + assertTrue(mActivitiesToBeDestroyed.isEmpty()); + } + + @Test + public void testDestroyActivityItem_execute() { + final DestroyActivityItem item = DestroyActivityItem + .obtain(mActivityToken, false /* finished */, 123 /* configChanges */); + item.execute(mHandler, mActivityClientRecord, mPendingActions); + + verify(mHandler).handleDestroyActivity(eq(mActivityClientRecord), eq(false) /* finishing */, + eq(123) /* configChanges */, eq(false) /* getNonConfigInstance */, any()); + } + + @Test + public void testLaunchActivityItem_getContextToUpdate() { + final LaunchActivityItem item = new TestUtils.LaunchActivityItemBuilder( + mActivityToken, new Intent(), new ActivityInfo()) + .build(); + + final Context context = item.getContextToUpdate(mHandler); + + assertEquals(ActivityThread.currentApplication(), context); + } + + @Test + public void testMoveToDisplayItem_getContextToUpdate() { + final MoveToDisplayItem item = MoveToDisplayItem + .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration); + final Context context = item.getContextToUpdate(mHandler); + + assertEquals(mActivity, context); + } + + @Test + public void testWindowContextInfoChangeItem_execute() { + final WindowContextInfoChangeItem item = WindowContextInfoChangeItem + .obtain(mWindowClientToken, mConfiguration, DEFAULT_DISPLAY); + item.execute(mHandler, mPendingActions); + + verify(mHandler).handleWindowContextInfoChanged(mWindowClientToken, + new WindowContextInfo(mConfiguration, DEFAULT_DISPLAY)); + } + + @Test + public void testWindowContextInfoChangeItem_getContextToUpdate() { + doReturn(mWindowContext).when(mHandler).getWindowContext(mWindowClientToken); + + final WindowContextInfoChangeItem item = WindowContextInfoChangeItem + .obtain(mWindowClientToken, mConfiguration, DEFAULT_DISPLAY); + final Context context = item.getContextToUpdate(mHandler); + + assertEquals(mWindowContext, context); + } + + @Test + public void testWindowContextWindowRemovalItem_execute() { + final WindowContextWindowRemovalItem item = WindowContextWindowRemovalItem.obtain( + mWindowClientToken); + item.execute(mHandler, mPendingActions); + + verify(mHandler).handleWindowContextWindowRemoval(mWindowClientToken); + } + + @Test + public void testWindowStateResizeItem_execute() throws RemoteException { + final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames, + true /* reportDraw */, mMergedConfiguration, mInsetsState, true /* forceLayout */, + true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, + true /* dragResizing */); + item.execute(mHandler, mPendingActions); + + verify(mWindow).resized(mFrames, + true /* reportDraw */, mMergedConfiguration, mInsetsState, true /* forceLayout */, + true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, + true /* dragResizing */); + } + + @Test + public void testWindowStateResizeItem_getContextToUpdate() { + final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames, + true /* reportDraw */, mMergedConfiguration, mInsetsState, true /* forceLayout */, + true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, + true /* dragResizing */); + final Context context = item.getContextToUpdate(mHandler); + + assertEquals(ActivityThread.currentApplication(), context); + } + +} diff --git a/core/tests/coretests/src/android/app/servertransaction/ConfigurationChangeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ConfigurationChangeItemTest.java deleted file mode 100644 index d9f5523c9782..000000000000 --- a/core/tests/coretests/src/android/app/servertransaction/ConfigurationChangeItemTest.java +++ /dev/null @@ -1,67 +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 android.app.servertransaction; - -import static android.content.Context.DEVICE_ID_DEFAULT; - -import static org.junit.Assert.assertEquals; - -import android.app.ActivityThread; -import android.app.ClientTransactionHandler; -import android.content.Context; -import android.content.res.Configuration; -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link ConfigurationChangeItem}. - * - * Build/Install/Run: - * atest FrameworksCoreTests:ConfigurationChangeItemTest - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -@Presubmit -public class ConfigurationChangeItemTest { - - @Mock - private ClientTransactionHandler mHandler; - // Can't mock final class. - private final Configuration mConfiguration = new Configuration(); - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testGetContextToUpdate() { - final ConfigurationChangeItem item = ConfigurationChangeItem - .obtain(mConfiguration, DEVICE_ID_DEFAULT); - final Context context = item.getContextToUpdate(mHandler); - - assertEquals(ActivityThread.currentApplication(), context); - } -} diff --git a/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java b/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java deleted file mode 100644 index ecd75a8370ce..000000000000 --- a/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java +++ /dev/null @@ -1,99 +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 android.app.servertransaction; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import android.app.ActivityThread.ActivityClientRecord; -import android.app.ClientTransactionHandler; -import android.os.IBinder; -import android.platform.test.annotations.Presubmit; -import android.util.ArrayMap; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link DestroyActivityItem}. - * - * Build/Install/Run: - * atest FrameworksCoreTests:DestroyActivityItemTest - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -@Presubmit -public class DestroyActivityItemTest { - - @Mock - private ClientTransactionHandler mHandler; - @Mock - private PendingTransactionActions mPendingActions; - @Mock - private IBinder mActivityToken; - - // Can't mock final class. - private ActivityClientRecord mActivityClientRecord; - - private ArrayMap<IBinder, DestroyActivityItem> mActivitiesToBeDestroyed; - private DestroyActivityItem mItem; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - mItem = DestroyActivityItem.obtain( - mActivityToken, false /* finished */, 123 /* configChanges */); - mActivityClientRecord = new ActivityClientRecord(); - mActivitiesToBeDestroyed = new ArrayMap<>(); - - doReturn(mActivitiesToBeDestroyed).when(mHandler).getActivitiesToBeDestroyed(); - } - - @Test - public void testPreExecute() { - mItem.preExecute(mHandler); - - assertEquals(1, mActivitiesToBeDestroyed.size()); - assertEquals(mItem, mActivitiesToBeDestroyed.get(mActivityToken)); - } - - @Test - public void testPostExecute() { - mItem.preExecute(mHandler); - mItem.postExecute(mHandler, mPendingActions); - - assertTrue(mActivitiesToBeDestroyed.isEmpty()); - } - - @Test - public void testExecute() { - mItem.execute(mHandler, mActivityClientRecord, mPendingActions); - - verify(mHandler).handleDestroyActivity(eq(mActivityClientRecord), eq(false) /* finishing */, - eq(123) /* configChanges */, eq(false) /* getNonConfigInstance */, any()); - } -} diff --git a/core/tests/coretests/src/android/app/servertransaction/WindowContextInfoChangeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/WindowContextInfoChangeItemTest.java deleted file mode 100644 index a801a76d16c9..000000000000 --- a/core/tests/coretests/src/android/app/servertransaction/WindowContextInfoChangeItemTest.java +++ /dev/null @@ -1,89 +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 android.app.servertransaction; - -import static android.view.Display.DEFAULT_DISPLAY; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import android.app.ClientTransactionHandler; -import android.content.Context; -import android.content.res.Configuration; -import android.os.IBinder; -import android.platform.test.annotations.Presubmit; -import android.window.WindowContext; -import android.window.WindowContextInfo; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link WindowContextInfoChangeItem}. - * - * Build/Install/Run: - * atest FrameworksCoreTests:WindowContextInfoChangeItemTest - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -@Presubmit -public class WindowContextInfoChangeItemTest { - - @Mock - private ClientTransactionHandler mHandler; - @Mock - private PendingTransactionActions mPendingActions; - @Mock - private IBinder mClientToken; - @Mock - private WindowContext mWindowContext; - // Can't mock final class. - private final Configuration mConfiguration = new Configuration(); - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testExecute() { - final WindowContextInfoChangeItem item = WindowContextInfoChangeItem - .obtain(mClientToken, mConfiguration, DEFAULT_DISPLAY); - item.execute(mHandler, mPendingActions); - - verify(mHandler).handleWindowContextInfoChanged(mClientToken, - new WindowContextInfo(mConfiguration, DEFAULT_DISPLAY)); - } - - @Test - public void testGetContextToUpdate() { - doReturn(mWindowContext).when(mHandler).getWindowContext(mClientToken); - - final WindowContextInfoChangeItem item = WindowContextInfoChangeItem - .obtain(mClientToken, mConfiguration, DEFAULT_DISPLAY); - final Context context = item.getContextToUpdate(mHandler); - - assertEquals(mWindowContext, context); - } -} diff --git a/core/tests/coretests/src/android/app/servertransaction/WindowContextWindowRemovalItemTest.java b/core/tests/coretests/src/android/app/servertransaction/WindowContextWindowRemovalItemTest.java deleted file mode 100644 index cf9935f2822f..000000000000 --- a/core/tests/coretests/src/android/app/servertransaction/WindowContextWindowRemovalItemTest.java +++ /dev/null @@ -1,65 +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 android.app.servertransaction; - -import static org.mockito.Mockito.verify; - -import android.app.ClientTransactionHandler; -import android.os.IBinder; -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link WindowContextWindowRemovalItem}. - * - * Build/Install/Run: - * atest FrameworksCoreTests:WindowContextWindowRemovalItemTest - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -@Presubmit -public class WindowContextWindowRemovalItemTest { - - @Mock - private ClientTransactionHandler mHandler; - @Mock - private PendingTransactionActions mPendingActions; - @Mock - private IBinder mClientToken; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testExecute() { - final WindowContextWindowRemovalItem item = WindowContextWindowRemovalItem.obtain( - mClientToken); - item.execute(mHandler, mPendingActions); - - verify(mHandler).handleWindowContextWindowRemoval(mClientToken); - } -} diff --git a/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java deleted file mode 100644 index 4d45daf3570c..000000000000 --- a/core/tests/coretests/src/android/app/servertransaction/WindowStateResizeItemTest.java +++ /dev/null @@ -1,82 +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 android.app.servertransaction; - -import static org.mockito.Mockito.verify; - -import android.app.ClientTransactionHandler; -import android.os.RemoteException; -import android.platform.test.annotations.Presubmit; -import android.util.MergedConfiguration; -import android.view.IWindow; -import android.view.InsetsState; -import android.window.ClientWindowFrames; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link WindowStateResizeItem}. - * - * Build/Install/Run: - * atest FrameworksCoreTests:WindowStateResizeItemTest - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -@Presubmit -public class WindowStateResizeItemTest { - - @Mock - private ClientTransactionHandler mHandler; - @Mock - private PendingTransactionActions mPendingActions; - @Mock - private IWindow mWindow; - - private InsetsState mInsetsState; - private ClientWindowFrames mFrames; - private MergedConfiguration mConfiguration; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - - mInsetsState = new InsetsState(); - mFrames = new ClientWindowFrames(); - mConfiguration = new MergedConfiguration(); - } - - @Test - public void testExecute() throws RemoteException { - final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames, - true /* reportDraw */, mConfiguration, mInsetsState, true /* forceLayout */, - true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, - true /* dragResizing */); - item.execute(mHandler, mPendingActions); - - verify(mWindow).resized(mFrames, - true /* reportDraw */, mConfiguration, mInsetsState, true /* forceLayout */, - true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, - true /* dragResizing */); - } -} diff --git a/core/tests/coretests/src/android/content/pm/ModuleInfoTest.java b/core/tests/coretests/src/android/content/pm/ModuleInfoTest.java new file mode 100644 index 000000000000..4366e02cdf23 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/ModuleInfoTest.java @@ -0,0 +1,99 @@ +/* + * 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.content.pm; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Parcel; +import android.platform.test.annotations.AppModeFull; +import android.text.TextUtils; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@AppModeFull +public class ModuleInfoTest { + + private static final String APEX_MODULE_NAME = "apexModuleName"; + private static final String APK_IN_APEX_PACKAGE_NAME = "apkInApexPackageName"; + private static final String MODULE_PACKAGE_NAME = "modulePackageName"; + private static final String MODULE_NAME = "moduleName"; + + @Test + public void testSimple() { + ModuleInfo info = new ModuleInfo(); + assertThat(info.toString()).isNotNull(); + } + + @Test + public void testDefaultCopy() { + ModuleInfo oldInfo = new ModuleInfo(); + ModuleInfo newInfo = new ModuleInfo(oldInfo); + assertThat(newInfo).isEqualTo(oldInfo); + } + + @Test + public void testCopy() { + boolean isHidden = false; + ModuleInfo info = new ModuleInfo(); + info.setHidden(isHidden); + info.setApexModuleName(APEX_MODULE_NAME); + info.setPackageName(MODULE_PACKAGE_NAME); + info.setName(MODULE_NAME); + info.setApkInApexPackageNames(List.of(APK_IN_APEX_PACKAGE_NAME)); + + ModuleInfo newInfo = new ModuleInfo(info); + assertThat(newInfo).isEqualTo(info); + } + + @Test + public void testGetApkInApexPackageNamesReturnEmptyListInDefault() { + ModuleInfo info = new ModuleInfo(); + assertThat(info.getApkInApexPackageNames()).isNotNull(); + assertThat(info.getApkInApexPackageNames()).isEmpty(); + } + + @Test + public void testModuleInfoParcelizeDeparcelize() { + boolean isHidden = false; + ModuleInfo info = new ModuleInfo(); + info.setHidden(isHidden); + info.setApexModuleName(APEX_MODULE_NAME); + info.setPackageName(MODULE_PACKAGE_NAME); + info.setName(MODULE_NAME); + info.setApkInApexPackageNames(List.of(APK_IN_APEX_PACKAGE_NAME)); + + final Parcel p = Parcel.obtain(); + info.writeToParcel(p, 0); + p.setDataPosition(0); + + final ModuleInfo targetInfo = ModuleInfo.CREATOR.createFromParcel(p); + p.recycle(); + + assertThat(info.isHidden()).isEqualTo(targetInfo.isHidden()); + assertThat(info.getApexModuleName()).isEqualTo(targetInfo.getApexModuleName()); + assertThat(info.getPackageName()).isEqualTo(targetInfo.getPackageName()); + assertThat(TextUtils.equals(info.getName(), targetInfo.getName())).isTrue(); + assertThat(info.getApkInApexPackageNames().toArray()).isEqualTo( + targetInfo.getApkInApexPackageNames().toArray()); + } +} diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java index faeae2cb6698..0d1dde38ca8f 100644 --- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java +++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java @@ -16,6 +16,8 @@ package android.view; +import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM; +import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.NO_CUTOUT; import static android.view.DisplayCutout.extractBoundsFromList; import static android.view.DisplayCutout.fromSpec; @@ -180,7 +182,7 @@ public class DisplayCutoutTest { final int displayHeight = 400; final float density = 1f; final DisplayCutout cutout = fromSpec(cutoutSpecString, displayWidth, displayHeight, - density, Insets.NONE); + density, Insets.NONE, null); assertThat(cutout.getCutoutPath(), notNullValue()); } @@ -191,9 +193,9 @@ public class DisplayCutoutTest { final int displayHeight = 400; final float density = 1f; final Path first = fromSpec(cutoutSpecString, displayWidth, displayHeight, - density, Insets.NONE).getCutoutPath(); + density, Insets.NONE, null).getCutoutPath(); final Path second = fromSpec(cutoutSpecString, displayWidth, displayHeight, - density, Insets.NONE).getCutoutPath(); + density, Insets.NONE, null).getCutoutPath(); assertThat(first, equalTo(second)); } @@ -203,9 +205,9 @@ public class DisplayCutoutTest { final int displayHeight = 400; final float density = 1f; final Path first = fromSpec("L1,0 L1,1 L0,1 z", displayWidth, displayHeight, - density, Insets.NONE).getCutoutPath(); + density, Insets.NONE, null).getCutoutPath(); final Path second = fromSpec("L2,0 L2,2 L0,2 z", displayWidth, displayHeight, - density, Insets.NONE).getCutoutPath(); + density, Insets.NONE, null).getCutoutPath(); assertThat(first, not(equalTo(second))); } @@ -216,7 +218,7 @@ public class DisplayCutoutTest { final int displayHeight = 400; final float density = 1f; final DisplayCutout cutout = fromSpec(cutoutSpecString, displayWidth, displayHeight, - density, Insets.NONE); + density, Insets.NONE, null); assertThat(displayWidth, equalTo(cutout.getCutoutPathParserInfo().getDisplayWidth())); assertThat(displayHeight, equalTo(cutout.getCutoutPathParserInfo().getDisplayHeight())); assertThat(density, equalTo(cutout.getCutoutPathParserInfo().getDensity())); @@ -360,63 +362,64 @@ public class DisplayCutoutTest { @Test public void fromSpec_caches() { Insets waterfallInsets = Insets.of(0, 20, 0, 20); - DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, waterfallInsets); + DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, waterfallInsets, null); assertThat( - fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, waterfallInsets), + fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, waterfallInsets, null), sameInstance(cached)); } @Test public void fromSpec_wontCacheIfSpecChanges() { - DisplayCutout cached = fromSpec("L1,0 L1000,1000 L0,1 z", 200, 400, 1f, Insets.NONE); + DisplayCutout cached = fromSpec("L1,0 L1000,1000 L0,1 z", 200, 400, 1f, Insets.NONE, null); assertThat( - fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE), + fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE, null), not(sameInstance(cached))); } @Test public void fromSpec_wontCacheIfScreenWidthChanges() { - DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 2000, 400, 1f, Insets.NONE); + DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 2000, 400, 1f, Insets.NONE, null); assertThat( - fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE), + fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE, null), not(sameInstance(cached))); } @Test public void fromSpec_wontCacheIfScreenHeightChanges() { - DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 4000, 1f, Insets.NONE); + DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 4000, 1f, Insets.NONE, null); assertThat( - fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE), + fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE, null), not(sameInstance(cached))); } @Test public void fromSpec_wontCacheIfDensityChanges() { - DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, Insets.NONE); + DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, Insets.NONE, null); assertThat( - fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE), + fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 1f, Insets.NONE, null), not(sameInstance(cached))); } @Test public void fromSpec_wontCacheIfWaterfallInsetsChange() { Insets waterfallInsets = Insets.of(0, 20, 0, 20); - DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, Insets.NONE); + DisplayCutout cached = fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, Insets.NONE, null); assertThat( - fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, waterfallInsets), + fromSpec("L1,0 L1,1 L0,1 z", 200, 400, 2f, waterfallInsets, null), not(sameInstance(cached))); } @Test public void fromSpec_setsSafeInsets_top() { - DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z", 200, 400, 2f, Insets.NONE); + DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z", 200, 400, 2f, + Insets.NONE, null); assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 20, 0, 0))); } @Test public void fromSpec_setsSafeInsets_top_and_bottom() { DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z" - + "@bottom M -50,0 v -10,0 h 100 v 20 z", 200, 400, 2f, Insets.NONE); + + "@bottom M -50,0 v -10,0 h 100 v 20 z", 200, 400, 2f, Insets.NONE, null); assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 20, 0, 10))); assertThat(cutout.getBoundingRectsAll(), equalTo(new Rect[]{ ZERO_RECT, new Rect(50, 0, 150, 20), @@ -426,33 +429,35 @@ public class DisplayCutoutTest { @Test public void fromSpec_setsSafeInsets_waterfallTopBottom() { - DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(0, 30, 0, 30)); + DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(0, 30, 0, 30), null); assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 30, 0, 30))); } @Test public void fromSpec_setsSafeInsets_waterfallLeftRight() { - DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(30, 0, 30, 0)); + DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(30, 0, 30, 0), null); assertThat(cutout.getSafeInsets(), equalTo(new Rect(30, 0, 30, 0))); } @Test public void fromSpec_setsSafeInsets_waterfall_allEdges() { - DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(30, 30, 30, 30)); + DisplayCutout cutout = fromSpec("", 200, 400, 2f, Insets.of(30, 30, 30, 30), null); assertThat(cutout.getSafeInsets(), equalTo(new Rect(30, 30, 30, 30))); } @Test public void fromSpec_setsSafeInsets_cutoutTopBottom_waterfallTopBottom() { DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z" - + "@bottom M -50,0 v -20,0 h 100 v 20 z", 200, 400, 2f, Insets.of(0, 30, 0, 30)); + + "@bottom M -50,0 v -20,0 h 100 v 20 z", 200, 400, 2f, + Insets.of(0, 30, 0, 30), null); assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 30, 0, 30))); } @Test public void fromSpec_setsSafeInsets_cutoutTopBottom_waterfallLeftRight() { DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z" - + "@bottom M -50,0 v -20,0 h 100 v 20 z", 200, 400, 2f, Insets.of(30, 0, 30, 0)); + + "@bottom M -50,0 v -20,0 h 100 v 20 z", 200, 400, 2f, + Insets.of(30, 0, 30, 0), null); assertThat(cutout.getSafeInsets(), equalTo(new Rect(30, 20, 30, 20))); } @@ -568,7 +573,84 @@ public class DisplayCutoutTest { DisplayCutout rotated = cutout.getRotated(displayH, displayW, ROTATION_90, ROTATION_180); assertEquals(expected, rotated); } + @Test + public void testGetRotatedCutoutWithOverride_top_rot0() { + int displayW = 500, displayH = 1000; + final int[] sideOverrides = new int[] {BOUNDS_POSITION_TOP, BOUNDS_POSITION_BOTTOM, + BOUNDS_POSITION_BOTTOM, BOUNDS_POSITION_TOP}; + DisplayCutout expected = new DisplayCutout(Insets.of(20, 100, 20, 0), + ZERO_RECT, new Rect(50, 0, 75, 100), ZERO_RECT, ZERO_RECT, + Insets.of(20, 0, 20, 0), null, sideOverrides); + DisplayCutout cutout = new DisplayCutout(Insets.of(20, 100, 20, 0), + ZERO_RECT, new Rect(50, 0, 75, 100), ZERO_RECT, ZERO_RECT, + Insets.of(20, 0, 20, 0), null, sideOverrides); + DisplayCutout rotated = cutout.getRotated(displayW, displayH, ROTATION_0, ROTATION_0); + assertEquals(expected, rotated); + } + @Test + public void testGetRotatedCutoutWithOverride_top_rot90() { + int displayW = 500, displayH = 1000; + final int[] sideOverrides = new int[] {BOUNDS_POSITION_TOP, BOUNDS_POSITION_BOTTOM, + BOUNDS_POSITION_BOTTOM, BOUNDS_POSITION_TOP}; + DisplayCutout expected = new DisplayCutout(Insets.of(0, 20, 0, 75), + ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(0, displayW - 75, 100, displayW - 50), + Insets.of(0, 20, 0, 20), createParserInfo(ROTATION_90), sideOverrides); + DisplayCutout cutout = new DisplayCutout(Insets.of(20, 100, 20, 0), + ZERO_RECT, new Rect(50, 0, 75, 100), ZERO_RECT, ZERO_RECT, + Insets.of(20, 0, 20, 0), null, sideOverrides); + DisplayCutout rotated = cutout.getRotated(displayW, displayH, ROTATION_0, ROTATION_90); + assertEquals(expected, rotated); + } + + @Test + public void testGetRotatedCutoutWithOverride_top_rot180() { + int displayW = 500, displayH = 1000; + final int[] sideOverrides = new int[] {BOUNDS_POSITION_TOP, BOUNDS_POSITION_BOTTOM, + BOUNDS_POSITION_BOTTOM, BOUNDS_POSITION_TOP}; + DisplayCutout expected = new DisplayCutout(Insets.of(20, 0, 20, 100), + ZERO_RECT, ZERO_RECT, ZERO_RECT, + new Rect(displayW - 75, displayH - 100, displayW - 50, displayH - 0), + Insets.of(20, 0, 20, 0), createParserInfo(ROTATION_180), sideOverrides); + DisplayCutout cutout = new DisplayCutout(Insets.of(20, 100, 20, 0), + ZERO_RECT, new Rect(50, 0, 75, 100), ZERO_RECT, ZERO_RECT, + Insets.of(20, 0, 20, 0), null, sideOverrides); + DisplayCutout rotated = cutout.getRotated(displayW, displayH, ROTATION_0, ROTATION_180); + assertEquals(expected, rotated); + } + + @Test + public void testGetRotatedCutoutWithOverride_top_rot270() { + int displayW = 500, displayH = 1000; + final int[] sideOverrides = new int[] {BOUNDS_POSITION_TOP, BOUNDS_POSITION_BOTTOM, + BOUNDS_POSITION_BOTTOM, BOUNDS_POSITION_TOP}; + DisplayCutout expected = new DisplayCutout(Insets.of(0, 75, 0, 20), + ZERO_RECT, new Rect(displayH - 100, 50, displayH - 0, 75), ZERO_RECT, ZERO_RECT, + Insets.of(0, 20, 0, 20), createParserInfo(ROTATION_270), sideOverrides); + DisplayCutout cutout = new DisplayCutout(Insets.of(20, 100, 20, 0), + ZERO_RECT, new Rect(50, 0, 75, 100), ZERO_RECT, ZERO_RECT, + Insets.of(20, 0, 20, 0), null, sideOverrides); + DisplayCutout rotated = cutout.getRotated(displayW, displayH, ROTATION_0, ROTATION_270); + assertEquals(expected, rotated); + } + + @Test + public void testGetRotatedCutoutWithOverride_top_rot90to180() { + int displayW = 500, displayH = 1000; + final int[] sideOverrides = new int[] {BOUNDS_POSITION_TOP, BOUNDS_POSITION_BOTTOM, + BOUNDS_POSITION_BOTTOM, BOUNDS_POSITION_TOP}; + DisplayCutout expected = new DisplayCutout(Insets.of(20, 0, 20, 100), + ZERO_RECT, ZERO_RECT, ZERO_RECT, + new Rect(displayW - 75, displayH - 100, displayW - 50, displayH - 0), + Insets.of(20, 0, 20, 0), createParserInfo(ROTATION_180), + sideOverrides); + DisplayCutout cutout = new DisplayCutout(Insets.of(0, 20, 0, 75), + ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(0, displayW - 75, 100, displayW - 50), + Insets.of(0, 20, 0, 20), null, sideOverrides); + // starting from 90, so the start displayW/H are swapped: + DisplayCutout rotated = cutout.getRotated(displayH, displayW, ROTATION_90, ROTATION_180); + assertEquals(expected, rotated); + } private static DisplayCutout createCutoutTop() { return createCutoutWithInsets(0, 100, 0, 0); } diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java index 35ddfdb3723b..e52aa1b0fff4 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java @@ -153,7 +153,7 @@ public class ContentCaptureManagerTest { final ContentCaptureManager manager = new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS); // Ensure main session is created. - final MainContentCaptureSession unused = manager.getMainContentCaptureSession(); + final ContentCaptureSession unused = manager.getMainContentCaptureSession(); final WindowManager.LayoutParams initialParam = new WindowManager.LayoutParams(); initialParam.flags |= WindowManager.LayoutParams.FLAG_SECURE; @@ -167,7 +167,7 @@ public class ContentCaptureManagerTest { final ContentCaptureManager manager = new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS); // Ensure main session is created. - final MainContentCaptureSession unused = manager.getMainContentCaptureSession(); + final ContentCaptureSession unused = manager.getMainContentCaptureSession(); final WindowManager.LayoutParams initialParam = new WindowManager.LayoutParams(); initialParam.flags |= WindowManager.LayoutParams.FLAG_SECURE; // Default param does not have FLAG_SECURE set. @@ -184,7 +184,7 @@ public class ContentCaptureManagerTest { final ContentCaptureManager manager = new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS); // Ensure main session is created. - final MainContentCaptureSession unused = manager.getMainContentCaptureSession(); + final ContentCaptureSession unused = manager.getMainContentCaptureSession(); // Default param does not have FLAG_SECURE set. final WindowManager.LayoutParams resetParam = new WindowManager.LayoutParams(); diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java index 23b9b9bdb451..4a4c693d7122 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java @@ -21,12 +21,19 @@ import static com.google.common.truth.Truth.assertThat; import static org.testng.Assert.assertThrows; import android.compat.testing.PlatformCompatChangeRule; +import android.content.ComponentName; import android.graphics.Insets; +import android.graphics.Rect; +import android.os.IBinder; +import android.util.SparseArray; import android.view.View; import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.contentcapture.ViewNode.ViewStructureImpl; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.google.common.collect.ImmutableMap; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; @@ -40,6 +47,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import java.util.ArrayList; import java.util.Map; /** @@ -195,6 +203,22 @@ public class ContentCaptureSessionTest { } @Override + void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, + @NonNull ComponentName component, int flags) { + throw new UnsupportedOperationException("should not have been called"); + } + + @Override + boolean isDisabled() { + throw new UnsupportedOperationException("should not have been called"); + } + + @Override + boolean setDisabled(boolean disabled) { + throw new UnsupportedOperationException("should not have been called"); + } + + @Override ContentCaptureSession newChild(ContentCaptureContext context) { throw new UnsupportedOperationException("should not have been called"); } @@ -210,20 +234,20 @@ public class ContentCaptureSessionTest { } @Override - void internalNotifyViewAppeared(ViewStructureImpl node) { + void internalNotifyViewAppeared(final int sessionId, ViewStructureImpl node) { throw new UnsupportedOperationException("should not have been called"); } @Override - void internalNotifyViewDisappeared(AutofillId id) {} + void internalNotifyViewDisappeared(final int sessionId, AutofillId id) {} @Override - void internalNotifyViewTextChanged(AutofillId id, CharSequence text) { + void internalNotifyViewTextChanged(final int sessionId, AutofillId id, CharSequence text) { throw new UnsupportedOperationException("should not have been called"); } @Override - public void internalNotifyViewTreeEvent(boolean started) { + public void internalNotifyViewTreeEvent(final int sessionId, boolean started) { if (started) { mInternalNotifyViewTreeEventStartedCount += 1; } else { @@ -242,7 +266,34 @@ public class ContentCaptureSessionTest { } @Override - void internalNotifyViewInsetsChanged(Insets viewInsets) { + void internalNotifyChildSessionStarted(int parentSessionId, int childSessionId, + @NonNull ContentCaptureContext clientContext) { + throw new UnsupportedOperationException("should not have been called"); + } + + @Override + void internalNotifyChildSessionFinished(int parentSessionId, int childSessionId) { + throw new UnsupportedOperationException("should not have been called"); + } + + @Override + void internalNotifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) { + throw new UnsupportedOperationException("should not have been called"); + } + + @Override + public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) { + throw new UnsupportedOperationException("should not have been called"); + } + + @Override + public void notifyContentCaptureEvents( + @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) { + + } + + @Override + void internalNotifyViewInsetsChanged(final int sessionId, Insets viewInsets) { throw new UnsupportedOperationException("should not have been called"); } diff --git a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionV2Test.java b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionV2Test.java new file mode 100644 index 000000000000..f0f3a9683353 --- /dev/null +++ b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionV2Test.java @@ -0,0 +1,530 @@ +/* + * 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.view.contentcapture; + +import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED; +import static android.view.contentcapture.ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED; +import static android.view.contentcapture.ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARING; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.content.ComponentName; +import android.content.ContentCaptureOptions; +import android.content.Context; +import android.content.pm.ParceledListSlice; +import android.graphics.Insets; +import android.os.Handler; +import android.os.RemoteException; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.SparseArray; +import android.view.View; +import android.view.autofill.AutofillId; +import android.view.contentprotection.ContentProtectionEventProcessor; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Test for {@link MainContentCaptureSessionV2}. + * + * <p>Run with: {@code atest + * FrameworksCoreTests:android.view.contentcapture.MainContentCaptureSessionV2Test} + */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +@TestableLooper.RunWithLooper +public class MainContentCaptureSessionV2Test { + + private static final int BUFFER_SIZE = 100; + + private static final int REASON = 123; + + private static final ContentCaptureEvent EVENT = + new ContentCaptureEvent(/* sessionId= */ 0, TYPE_SESSION_STARTED); + + private static final ComponentName COMPONENT_NAME = + new ComponentName("com.test.package", "TestClass"); + + private static final Context sContext = ApplicationProvider.getApplicationContext(); + + private static final ContentCaptureManager.StrippedContext sStrippedContext = + new ContentCaptureManager.StrippedContext(sContext); + + private TestableLooper mTestableLooper; + + @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock private IContentCaptureManager mMockSystemServerInterface; + + @Mock private ContentProtectionEventProcessor mMockContentProtectionEventProcessor; + + @Mock private IContentCaptureDirectManager mMockContentCaptureDirectManager; + + @Before + public void setup() { + mTestableLooper = TestableLooper.get(this); + } + + @Test + public void onSessionStarted_contentProtectionEnabled_processorCreated() { + MainContentCaptureSessionV2 session = createSession(); + assertThat(session.mContentProtectionEventProcessor).isNull(); + + session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null); + mTestableLooper.processAllMessages(); + + assertThat(session.mContentProtectionEventProcessor).isNotNull(); + } + + @Test + public void onSessionStarted_contentProtectionDisabled_processorNotCreated() { + MainContentCaptureSessionV2 session = + createSession( + /* enableContentCaptureReceiver= */ true, + /* enableContentProtectionReceiver= */ false); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null); + mTestableLooper.processAllMessages(); + + assertThat(session.mContentProtectionEventProcessor).isNull(); + verifyZeroInteractions(mMockContentProtectionEventProcessor); + } + + @Test + public void onSessionStarted_contentProtectionNoBuffer_processorNotCreated() { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ true, + new ContentCaptureOptions.ContentProtectionOptions( + /* enableReceiver= */ true, + -BUFFER_SIZE, + /* requiredGroups= */ List.of(List.of("a")), + /* optionalGroups= */ Collections.emptyList(), + /* optionalGroupsThreshold= */ 0)); + MainContentCaptureSessionV2 session = createSession(options); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null); + mTestableLooper.processAllMessages(); + + assertThat(session.mContentProtectionEventProcessor).isNull(); + verifyZeroInteractions(mMockContentProtectionEventProcessor); + } + + @Test + public void onSessionStarted_contentProtectionNoGroups_processorNotCreated() { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ true, + new ContentCaptureOptions.ContentProtectionOptions( + /* enableReceiver= */ true, + BUFFER_SIZE, + /* requiredGroups= */ Collections.emptyList(), + /* optionalGroups= */ Collections.emptyList(), + /* optionalGroupsThreshold= */ 0)); + MainContentCaptureSessionV2 session = createSession(options); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null); + mTestableLooper.processAllMessages(); + + assertThat(session.mContentProtectionEventProcessor).isNull(); + verifyZeroInteractions(mMockContentProtectionEventProcessor); + } + + @Test + public void onSessionStarted_noComponentName_processorNotCreated() { + MainContentCaptureSessionV2 session = createSession(); + session.mComponentName = null; + + session.onSessionStarted(/* resultCode= */ 0, /* binder= */ null); + mTestableLooper.processAllMessages(); + + assertThat(session.mContentProtectionEventProcessor).isNull(); + } + + @Test + public void sendEvent_contentCaptureDisabled_contentProtectionDisabled() { + MainContentCaptureSessionV2 session = + createSession( + /* enableContentCaptureReceiver= */ false, + /* enableContentProtectionReceiver= */ false); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.sendEvent(EVENT); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mEvents).isNull(); + } + + @Test + public void sendEvent_contentCaptureDisabled_contentProtectionEnabled() { + MainContentCaptureSessionV2 session = + createSession( + /* enableContentCaptureReceiver= */ false, + /* enableContentProtectionReceiver= */ true); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.sendEvent(EVENT); + mTestableLooper.processAllMessages(); + + verify(mMockContentProtectionEventProcessor).processEvent(EVENT); + assertThat(session.mEvents).isNull(); + } + + @Test + public void sendEvent_contentCaptureEnabled_contentProtectionDisabled() { + MainContentCaptureSessionV2 session = + createSession( + /* enableContentCaptureReceiver= */ true, + /* enableContentProtectionReceiver= */ false); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.sendEvent(EVENT); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mEvents).isNotNull(); + assertThat(session.mEvents).containsExactly(EVENT); + } + + @Test + public void sendEvent_contentCaptureEnabled_contentProtectionEnabled() { + MainContentCaptureSessionV2 session = createSession(); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.sendEvent(EVENT); + mTestableLooper.processAllMessages(); + + verify(mMockContentProtectionEventProcessor).processEvent(EVENT); + assertThat(session.mEvents).isNotNull(); + assertThat(session.mEvents).containsExactly(EVENT); + } + + @Test + public void sendEvent_contentProtectionEnabled_processorNotCreated() { + MainContentCaptureSessionV2 session = + createSession( + /* enableContentCaptureReceiver= */ false, + /* enableContentProtectionReceiver= */ true); + + session.sendEvent(EVENT); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mEvents).isNull(); + } + + @Test + public void flush_contentCaptureDisabled_contentProtectionDisabled() throws Exception { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ false, + /* enableContentProtectionReceiver= */ false); + MainContentCaptureSessionV2 session = createSession(options); + session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); + session.mDirectServiceInterface = mMockContentCaptureDirectManager; + + session.flush(REASON); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentProtectionEventProcessor); + verifyZeroInteractions(mMockContentCaptureDirectManager); + assertThat(session.mEvents).containsExactly(EVENT); + } + + @Test + public void flush_contentCaptureDisabled_contentProtectionEnabled() { + MainContentCaptureSessionV2 session = + createSession( + /* enableContentCaptureReceiver= */ false, + /* enableContentProtectionReceiver= */ true); + session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); + session.mDirectServiceInterface = mMockContentCaptureDirectManager; + + session.flush(REASON); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentProtectionEventProcessor); + verifyZeroInteractions(mMockContentCaptureDirectManager); + assertThat(session.mEvents).containsExactly(EVENT); + } + + @Test + public void flush_contentCaptureEnabled_contentProtectionDisabled() throws Exception { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ true, + /* enableContentProtectionReceiver= */ false); + MainContentCaptureSessionV2 session = createSession(options); + session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); + session.mDirectServiceInterface = mMockContentCaptureDirectManager; + + session.flush(REASON); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mEvents).isEmpty(); + assertEventFlushedContentCapture(options); + } + + @Test + public void flush_contentCaptureEnabled_contentProtectionEnabled() throws Exception { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ true, + /* enableContentProtectionReceiver= */ true); + MainContentCaptureSessionV2 session = createSession(options); + session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); + session.mDirectServiceInterface = mMockContentCaptureDirectManager; + + session.flush(REASON); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mEvents).isEmpty(); + assertEventFlushedContentCapture(options); + } + + @Test + public void destroySession() throws Exception { + MainContentCaptureSessionV2 session = createSession(); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.destroySession(); + mTestableLooper.processAllMessages(); + + verify(mMockSystemServerInterface).finishSession(anyInt()); + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mDirectServiceInterface).isNull(); + assertThat(session.mContentProtectionEventProcessor).isNull(); + } + + @Test + public void resetSession() { + MainContentCaptureSessionV2 session = createSession(); + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + session.resetSession(/* newState= */ 0); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockSystemServerInterface); + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mDirectServiceInterface).isNull(); + assertThat(session.mContentProtectionEventProcessor).isNull(); + } + + @Test + @SuppressWarnings("GuardedBy") + public void notifyContentCaptureEvents_notStarted_ContentCaptureDisabled_ProtectionDisabled() { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ false, + /* enableContentProtectionReceiver= */ false); + MainContentCaptureSessionV2 session = createSession(options); + + notifyContentCaptureEvents(session); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentCaptureDirectManager); + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mEvents).isNull(); + } + + @Test + @SuppressWarnings("GuardedBy") + public void notifyContentCaptureEvents_started_ContentCaptureDisabled_ProtectionDisabled() { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ false, + /* enableContentProtectionReceiver= */ false); + MainContentCaptureSessionV2 session = createSession(options); + + session.onSessionStarted(0x2, null); + notifyContentCaptureEvents(session); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentCaptureDirectManager); + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mEvents).isNull(); + } + + @Test + @SuppressWarnings("GuardedBy") + public void notifyContentCaptureEvents_notStarted_ContentCaptureEnabled_ProtectionEnabled() { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ true, + /* enableContentProtectionReceiver= */ true); + MainContentCaptureSessionV2 session = createSession(options); + session.mDirectServiceInterface = mMockContentCaptureDirectManager; + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + + notifyContentCaptureEvents(session); + mTestableLooper.processAllMessages(); + + verifyZeroInteractions(mMockContentCaptureDirectManager); + verifyZeroInteractions(mMockContentProtectionEventProcessor); + assertThat(session.mEvents).isNull(); + } + + @Test + @SuppressWarnings("GuardedBy") + public void notifyContentCaptureEvents_started_ContentCaptureEnabled_ProtectionEnabled() + throws RemoteException { + ContentCaptureOptions options = + createOptions( + /* enableContentCaptureReceiver= */ true, + /* enableContentProtectionReceiver= */ true); + MainContentCaptureSessionV2 session = createSession(options); + session.mDirectServiceInterface = mMockContentCaptureDirectManager; + + session.onSessionStarted(0x2, null); + // Override the processor for interaction verification. + session.mContentProtectionEventProcessor = mMockContentProtectionEventProcessor; + notifyContentCaptureEvents(session); + mTestableLooper.processAllMessages(); + + // Force flush will happen twice. + verify(mMockContentCaptureDirectManager, times(1)) + .sendEvents(any(), eq(FLUSH_REASON_VIEW_TREE_APPEARING), any()); + verify(mMockContentCaptureDirectManager, times(1)) + .sendEvents(any(), eq(FLUSH_REASON_VIEW_TREE_APPEARED), any()); + // Other than the five view events, there will be two additional tree appearing events. + verify(mMockContentProtectionEventProcessor, times(7)).processEvent(any()); + assertThat(session.mEvents).isEmpty(); + } + + /** Simulates the regular content capture events sequence. */ + private void notifyContentCaptureEvents(final MainContentCaptureSessionV2 session) { + final ArrayList<Object> events = new ArrayList<>( + List.of( + prepareView(session), + prepareView(session), + new AutofillId(0), + prepareView(session), + Insets.of(0, 0, 0, 0) + ) + ); + + final SparseArray<ArrayList<Object>> contentCaptureEvents = new SparseArray<>(); + contentCaptureEvents.set(session.getId(), events); + + session.notifyContentCaptureEvents(contentCaptureEvents); + } + + private View prepareView(final MainContentCaptureSessionV2 session) { + final View view = new View(sContext); + view.setContentCaptureSession(session); + return view; + } + + private static ContentCaptureOptions createOptions( + boolean enableContentCaptureReceiver, + ContentCaptureOptions.ContentProtectionOptions contentProtectionOptions) { + return new ContentCaptureOptions( + /* loggingLevel= */ 0, + BUFFER_SIZE, + /* idleFlushingFrequencyMs= */ 0, + /* textChangeFlushingFrequencyMs= */ 0, + /* logHistorySize= */ 0, + /* disableFlushForViewTreeAppearing= */ false, + enableContentCaptureReceiver, + contentProtectionOptions, + /* whitelistedComponents= */ null); + } + + private static ContentCaptureOptions createOptions( + boolean enableContentCaptureReceiver, boolean enableContentProtectionReceiver) { + return createOptions( + enableContentCaptureReceiver, + new ContentCaptureOptions.ContentProtectionOptions( + enableContentProtectionReceiver, + BUFFER_SIZE, + /* requiredGroups= */ List.of(List.of("a")), + /* optionalGroups= */ Collections.emptyList(), + /* optionalGroupsThreshold= */ 0)); + } + + private ContentCaptureManager createManager(ContentCaptureOptions options) { + return new ContentCaptureManager(sContext, mMockSystemServerInterface, options); + } + + private MainContentCaptureSessionV2 createSession(ContentCaptureManager manager) { + final Handler testHandler = Handler.createAsync(mTestableLooper.getLooper()); + MainContentCaptureSessionV2 session = + new MainContentCaptureSessionV2( + sStrippedContext, + manager, + testHandler, + testHandler, + mMockSystemServerInterface); + session.mComponentName = COMPONENT_NAME; + return session; + } + + private MainContentCaptureSessionV2 createSession(ContentCaptureOptions options) { + return createSession(createManager(options)); + } + + private MainContentCaptureSessionV2 createSession( + boolean enableContentCaptureReceiver, boolean enableContentProtectionReceiver) { + return createSession( + createOptions(enableContentCaptureReceiver, enableContentProtectionReceiver)); + } + + private MainContentCaptureSessionV2 createSession() { + return createSession( + /* enableContentCaptureReceiver= */ true, + /* enableContentProtectionReceiver= */ true); + } + + private void assertEventFlushedContentCapture(ContentCaptureOptions options) throws Exception { + ArgumentCaptor<ParceledListSlice> captor = ArgumentCaptor.forClass(ParceledListSlice.class); + verify(mMockContentCaptureDirectManager) + .sendEvents(captor.capture(), eq(REASON), eq(options)); + + assertThat(captor.getValue()).isNotNull(); + List<ContentCaptureEvent> actual = captor.getValue().getList(); + assertThat(actual).isNotNull(); + assertThat(actual).containsExactly(EVENT); + } +} diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml index 421bc25d60e9..bf6094469215 100644 --- a/data/etc/preinstalled-packages-platform.xml +++ b/data/etc/preinstalled-packages-platform.xml @@ -128,4 +128,9 @@ to pre-existing users, but cannot uninstall pre-existing system packages from pr <install-in-user-type package="com.android.wallpaperbackup"> <install-in user-type="FULL" /> </install-in-user-type> + + <!-- AvatarPicker (AvatarPicker app)--> + <install-in-user-type package="com.android.avatarpicker"> + <install-in user-type="FULL" /> + </install-in-user-type> </config> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 742d5a2627eb..917a30061aca 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -4453,6 +4453,12 @@ "group": "WM_DEBUG_BACK_PREVIEW", "at": "com\/android\/server\/wm\/BackNavigationController.java" }, + "1946983717": { + "message": "Waiting for screen on due to %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" + }, "1947239194": { "message": "Deferring rotation, still finishing previous rotation", "level": "VERBOSE", diff --git a/data/keyboards/Vendor_0428_Product_4001.kl b/data/keyboards/Vendor_0428_Product_4001.kl new file mode 100644 index 000000000000..7d1dd128033d --- /dev/null +++ b/data/keyboards/Vendor_0428_Product_4001.kl @@ -0,0 +1,27 @@ +# Gravis GamePad Pro USB + +# Yellow +key 0x131 BUTTON_A +# Green +key 0x132 BUTTON_B +# Red +key 0x130 BUTTON_X +# Blue +key 0x133 BUTTON_Y + +# Left Upper Shoulder "1" +key 0x134 BUTTON_L1 +# Right Upper Shoulder "1" +key 0x135 BUTTON_R1 +# Left Lower Shoulder "2" +key 0x136 BUTTON_L2 +# Right Lower Shoulder "2" +key 0x137 BUTTON_R2 + +# Select & Start +key 0x138 BUTTON_SELECT +key 0x139 BUTTON_START + +# D-Pad +axis 0x00 HAT_X +axis 0x01 HAT_Y diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java index ed99501b867d..29cf05407a61 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java @@ -55,7 +55,7 @@ public class WindowExtensionsImpl implements WindowExtensions { // TODO(b/241126279) Introduce constants to better version functionality @Override public int getVendorApiLevel() { - return 4; + return 5; } @NonNull diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java index ca3d8d18db83..592f9a57884c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -19,6 +19,7 @@ package androidx.window.extensions.embedding; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_DIM_ON_TASK; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ISOLATED_NAVIGATION; import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior; @@ -356,6 +357,13 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { wct.addTaskFragmentOperation(fragmentToken, operation); } + void setTaskFragmentDimOnTask(@NonNull WindowContainerTransaction wct, + @NonNull IBinder fragmentToken, boolean dimOnTask) { + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_SET_DIM_ON_TASK).setDimOnTask(dimOnTask).build(); + wct.addTaskFragmentOperation(fragmentToken, operation); + } + void updateTaskFragmentInfo(@NonNull TaskFragmentInfo taskFragmentInfo) { mFragmentInfos.put(taskFragmentInfo.getFragmentToken(), taskFragmentInfo); } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index 543570c63ad7..6f356fa35d41 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -20,6 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.PackageManager.MATCH_ALL; +import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_TASK; + import android.app.Activity; import android.app.ActivityThread; import android.app.WindowConfiguration; @@ -56,6 +58,7 @@ import androidx.window.extensions.layout.WindowLayoutComponentImpl; import androidx.window.extensions.layout.WindowLayoutInfo; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; import java.util.ArrayList; import java.util.List; @@ -384,6 +387,13 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), splitRule, isStacked); + // Sets the dim area when the two TaskFragments are adjacent. + final boolean dimOnTask = !isStacked + && splitAttributes.getWindowAttributes().getDimArea() == DIM_AREA_ON_TASK + && Flags.fullscreenDimFlag(); + setTaskFragmentDimOnTask(wct, primaryContainer.getTaskFragmentToken(), dimOnTask); + setTaskFragmentDimOnTask(wct, secondaryContainer.getTaskFragmentToken(), dimOnTask); + // Setting isolated navigation and clear non-sticky pinned container if needed. final SplitPinRule splitPinRule = splitRule instanceof SplitPinRule ? (SplitPinRule) splitRule : null; @@ -578,6 +588,23 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { bounds.isEmpty() ? WINDOWING_MODE_FULLSCREEN : WINDOWING_MODE_MULTI_WINDOW); } + @Override + void setTaskFragmentDimOnTask(@NonNull WindowContainerTransaction wct, + @NonNull IBinder fragmentToken, boolean dimOnTask) { + final TaskFragmentContainer container = mController.getContainer(fragmentToken); + if (container == null) { + throw new IllegalStateException("setTaskFragmentDimOnTask on TaskFragment that is" + + " not registered with controller."); + } + + if (container.isLastDimOnTask() == dimOnTask) { + return; + } + + container.setLastDimOnTask(dimOnTask); + super.setTaskFragmentDimOnTask(wct, fragmentToken, dimOnTask); + } + /** * Expands the split container if the current split bounds are smaller than the Activity or * Intent that is added to the container. diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java index 810bded8a7f0..b52971a15a3c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -172,6 +172,11 @@ class TaskFragmentContainer { private boolean mIsIsolatedNavigationEnabled; /** + * Whether to apply dimming on the parent Task that was requested last. + */ + private boolean mLastDimOnTask; + + /** * @see #TaskFragmentContainer(Activity, Intent, TaskContainer, SplitController, * TaskFragmentContainer, String, Bundle) */ @@ -836,6 +841,16 @@ class TaskFragmentContainer { mIsIsolatedNavigationEnabled = isolatedNavigationEnabled; } + /** Sets whether to apply dim on the parent Task. */ + void setLastDimOnTask(boolean lastDimOnTask) { + mLastDimOnTask = lastDimOnTask; + } + + /** Returns whether to apply dim on the parent Task. */ + boolean isLastDimOnTask() { + return mLastDimOnTask; + } + /** * Adds the pending appeared activity that has requested to be launched in this task fragment. * @see android.app.ActivityClient#isRequestedToLaunchInTaskFragment diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java index 6981d9d7ebb8..941b4e1c3e41 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java @@ -235,6 +235,19 @@ public class SplitPresenterTest { } @Test + public void testSetTaskFragmentDimOnTask() { + final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + + mPresenter.setTaskFragmentDimOnTask(mTransaction, container.getTaskFragmentToken(), true); + verify(mTransaction).addTaskFragmentOperation(eq(container.getTaskFragmentToken()), any()); + + // No request to set the same adjacent TaskFragments. + clearInvocations(mTransaction); + mPresenter.setTaskFragmentDimOnTask(mTransaction, container.getTaskFragmentToken(), true); + verify(mTransaction, never()).addTaskFragmentOperation(any(), any()); + } + + @Test public void testUpdateAnimationParams() { final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml index cec7ee233236..ef7478c04dda 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml @@ -18,13 +18,13 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/desktop_mode_caption" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_horizontal"> <ImageButton android:id="@+id/caption_handle" - android:layout_width="128dp" + android:layout_width="@dimen/desktop_mode_fullscreen_decor_caption_width" android:layout_height="@dimen/desktop_mode_fullscreen_decor_caption_height" android:paddingVertical="16dp" android:contentDescription="@string/handle_text" diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index 6ad172807f6a..9d4e6f0ce660 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -57,7 +57,7 @@ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"如需退出,请从屏幕底部向上滑动,或点按应用上方的任意位置"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"启动单手模式"</string> <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"退出单手模式"</string> - <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>对话泡的设置"</string> + <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>消息气泡的设置"</string> <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"菜单"</string> <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"重新加入叠放"</string> <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -69,22 +69,22 @@ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"展开“<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>”"</string> <string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"收起“<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>”"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>设置"</string> - <string name="bubble_dismiss_text" msgid="8816558050659478158">"关闭对话泡"</string> - <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不以对话泡形式显示对话"</string> - <string name="bubbles_user_education_title" msgid="2112319053732691899">"使用对话泡聊天"</string> - <string name="bubbles_user_education_description" msgid="4215862563054175407">"新对话会以浮动图标或对话泡形式显示。点按即可打开对话泡。拖动即可移动对话泡。"</string> - <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"随时控制对话泡"</string> - <string name="bubbles_user_education_manage" msgid="3460756219946517198">"点按“管理”按钮,可关闭来自此应用的对话泡"</string> + <string name="bubble_dismiss_text" msgid="8816558050659478158">"关闭消息气泡"</string> + <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不以消息气泡形式显示对话"</string> + <string name="bubbles_user_education_title" msgid="2112319053732691899">"使用消息气泡聊天"</string> + <string name="bubbles_user_education_description" msgid="4215862563054175407">"新对话会以浮动图标或消息气泡形式显示。点按即可打开消息气泡。拖动即可移动消息气泡。"</string> + <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"随时控制消息气泡"</string> + <string name="bubbles_user_education_manage" msgid="3460756219946517198">"点按“管理”按钮,可关闭来自此应用的消息气泡"</string> <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"知道了"</string> - <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近没有对话泡"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"此处会显示最近的对话泡和已关闭的对话泡"</string> - <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"使用对话泡聊天"</string> + <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近没有消息气泡"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"此处会显示最近的消息气泡和已关闭的消息气泡"</string> + <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"使用消息气泡聊天"</string> <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"新对话会以图标形式显示在屏幕底部的角落中。点按图标即可展开对话,拖动图标即可关闭对话。"</string> - <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"随时控制对话泡"</string> - <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"点按此处即可管理哪些应用和对话可以显示对话泡"</string> + <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"随时控制消息气泡"</string> + <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"点按此处即可管理哪些应用和对话可以显示消息气泡"</string> <string name="notification_bubble_title" msgid="6082910224488253378">"气泡"</string> <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string> - <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已关闭对话泡。"</string> + <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已关闭消息气泡。"</string> <string name="restart_button_description" msgid="4564728020654658478">"点按即可重启此应用,获得更好的视觉体验"</string> <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"在“设置”中更改此应用的宽高比"</string> <string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"更改高宽比"</string> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 0a40cea3134d..28e709845e88 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -413,6 +413,9 @@ <!-- Height of desktop mode caption for fullscreen tasks. --> <dimen name="desktop_mode_fullscreen_decor_caption_height">36dp</dimen> + <!-- Width of desktop mode caption for fullscreen tasks. --> + <dimen name="desktop_mode_fullscreen_decor_caption_width">128dp</dimen> + <!-- Required empty space to be visible for partially offscreen tasks. --> <dimen name="freeform_required_visible_empty_space_in_header">48dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java index afd3b14e8b1d..81d13999e73c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java @@ -232,6 +232,7 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract return taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton && (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed || taskInfo.appCompatTaskInfo.isUserFullscreenOverrideEnabled) + && !taskInfo.appCompatTaskInfo.isSystemFullscreenOverrideEnabled && Intent.ACTION_MAIN.equals(intent.getAction()) && intent.hasCategory(Intent.CATEGORY_LAUNCHER) && (!mUserAspectRatioButtonShownChecker.get() || isShowingButton()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 71bf487249fb..0ef047f44909 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -235,7 +235,8 @@ public abstract class WMShellModule { mainChoreographer, taskOrganizer, displayController, - syncQueue); + syncQueue, + transitions); } // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java index dc82fc1b35dd..88949b2a5acd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java @@ -55,6 +55,26 @@ public class DesktopModeStatus { "persist.wm.debug.desktop_stashing", false); /** + * Flag to indicate whether to apply shadows to windows in desktop mode. + */ + private static final boolean USE_WINDOW_SHADOWS = SystemProperties.getBoolean( + "persist.wm.debug.desktop_use_window_shadows", true); + + /** + * Flag to indicate whether to apply shadows to the focused window in desktop mode. + * + * Note: this flag is only relevant if USE_WINDOW_SHADOWS is false. + */ + private static final boolean USE_WINDOW_SHADOWS_FOCUSED_WINDOW = SystemProperties.getBoolean( + "persist.wm.debug.desktop_use_window_shadows_focused_window", false); + + /** + * Flag to indicate whether to apply shadows to windows in desktop mode. + */ + private static final boolean USE_ROUNDED_CORNERS = SystemProperties.getBoolean( + "persist.wm.debug.desktop_use_rounded_corners", true); + + /** * Return {@code true} is desktop windowing proto 2 is enabled */ public static boolean isEnabled() { @@ -81,4 +101,21 @@ public class DesktopModeStatus { public static boolean isStashingEnabled() { return IS_STASHING_ENABLED; } + + /** + * Return whether to use window shadows. + * + * @param isFocusedWindow whether the window to apply shadows to is focused + */ + public static boolean useWindowShadow(boolean isFocusedWindow) { + return USE_WINDOW_SHADOWS + || (USE_WINDOW_SHADOWS_FOCUSED_WINDOW && isFocusedWindow); + } + + /** + * Return whether to use rounded corners for windows. + */ + public static boolean useRoundedCorners() { + return USE_ROUNDED_CORNERS; + } } 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 144555dd70c3..4a1bcaa7168a 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 @@ -721,6 +721,9 @@ class DesktopTasksController( finishTransaction: SurfaceControl.Transaction ) { // Add rounded corners to freeform windows + if (!DesktopModeStatus.useRoundedCorners()) { + return + } val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) info.changes .filter { it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index 48a0a46dccc1..3b0e7c139bed 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -19,6 +19,7 @@ package com.android.wm.shell.pip2.phone; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_PIP; +import static android.view.WindowManager.TRANSIT_TO_FRONT; import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; @@ -54,6 +55,8 @@ public class PipTransition extends PipTransitionController { @Nullable private WindowContainerToken mPipTaskToken; @Nullable + private IBinder mEnterTransition; + @Nullable private IBinder mAutoEnterButtonNavTransition; @Nullable private IBinder mExitViaExpandTransition; @@ -98,11 +101,8 @@ public class PipTransition extends PipTransitionController { @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request) { - if (isAutoEnterInButtonNavigation(request)) { - mAutoEnterButtonNavTransition = transition; - return getEnterPipTransaction(transition, request); - } else if (isLegacyEnter(request)) { - mLegacyEnterTransition = transition; + if (isAutoEnterInButtonNavigation(request) || isEnterPictureInPictureModeRequest(request)) { + mEnterTransition = transition; return getEnterPipTransaction(transition, request); } return null; @@ -111,12 +111,9 @@ public class PipTransition extends PipTransitionController { @Override public void augmentRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWct) { - if (isAutoEnterInButtonNavigation(request)) { + if (isAutoEnterInButtonNavigation(request) || isEnterPictureInPictureModeRequest(request)) { outWct.merge(getEnterPipTransaction(transition, request), true /* transfer */); - mAutoEnterButtonNavTransition = transition; - } else if (isLegacyEnter(request)) { - outWct.merge(getEnterPipTransaction(transition, request), true /* transfer */); - mLegacyEnterTransition = transition; + mEnterTransition = transition; } } @@ -162,7 +159,7 @@ public class PipTransition extends PipTransitionController { && pipTask.pictureInPictureParams.isAutoEnterEnabled(); } - private boolean isLegacyEnter(@NonNull TransitionRequestInfo requestInfo) { + private boolean isEnterPictureInPictureModeRequest(@NonNull TransitionRequestInfo requestInfo) { return requestInfo.getType() == TRANSIT_PIP; } @@ -172,13 +169,15 @@ public class PipTransition extends PipTransitionController { @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { - if (transition == mAutoEnterButtonNavTransition) { - mAutoEnterButtonNavTransition = null; - return startAutoEnterButtonNavAnimation(info, startTransaction, finishTransaction, - finishCallback); - } else if (transition == mLegacyEnterTransition) { - mLegacyEnterTransition = null; - return startLegacyEnterAnimation(info, startTransaction, finishTransaction, + if (transition == mEnterTransition) { + mEnterTransition = null; + if (isLegacyEnter(info)) { + // If this is a legacy-enter-pip (auto-enter is off and PiP activity went to pause), + // then we should run an ALPHA type (cross-fade) animation. + return startAlphaTypeEnterAnimation(info, startTransaction, finishTransaction, + finishCallback); + } + return startBoundsTypeEnterAnimation(info, startTransaction, finishTransaction, finishCallback); } else if (transition == mExitViaExpandTransition) { mExitViaExpandTransition = null; @@ -187,7 +186,15 @@ public class PipTransition extends PipTransitionController { return false; } - private boolean startAutoEnterButtonNavAnimation(@NonNull TransitionInfo info, + private boolean isLegacyEnter(@NonNull TransitionInfo info) { + TransitionInfo.Change pipChange = getPipChange(info); + // If the only change in the changes list is a TO_FRONT mode PiP task, + // then this is legacy-enter PiP. + return pipChange != null && pipChange.getMode() == TRANSIT_TO_FRONT + && info.getChanges().size() == 1; + } + + private boolean startBoundsTypeEnterAnimation(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { @@ -205,7 +212,7 @@ public class PipTransition extends PipTransitionController { return true; } - private boolean startLegacyEnterAnimation(@NonNull TransitionInfo info, + private boolean startAlphaTypeEnterAnimation(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index ccc34389557c..e4213569b526 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -347,7 +347,7 @@ public class RecentTasksController implements TaskStackListenerCallback, continue; } - final int pairedTaskId = mSplitTasks.get(taskInfo.taskId); + final int pairedTaskId = mSplitTasks.get(taskInfo.taskId, INVALID_TASK_ID); if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains( pairedTaskId)) { final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index cf1692018518..cebc4006656a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -54,6 +54,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private final Choreographer mMainChoreographer; private final DisplayController mDisplayController; private final SyncTransactionQueue mSyncQueue; + private final Transitions mTransitions; private TaskOperations mTaskOperations; private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>(); @@ -64,13 +65,15 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { Choreographer mainChoreographer, ShellTaskOrganizer taskOrganizer, DisplayController displayController, - SyncTransactionQueue syncQueue) { + SyncTransactionQueue syncQueue, + Transitions transitions) { mContext = context; mMainHandler = mainHandler; mMainChoreographer = mainChoreographer; mTaskOrganizer = taskOrganizer; mDisplayController = displayController; mSyncQueue = syncQueue; + mTransitions = transitions; if (!Transitions.ENABLE_SHELL_TRANSITIONS) { mTaskOperations = new TaskOperations(null, mContext, mSyncQueue); } @@ -133,7 +136,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { if (decoration == null) { createWindowDecoration(taskInfo, taskSurface, startT, finishT); } else { - decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */); + decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */, + false /* setTaskCropAndPosition */); } } @@ -145,7 +149,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); if (decoration == null) return; - decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */); + decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */, + false /* setTaskCropAndPosition */); } @Override @@ -191,16 +196,17 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { mSyncQueue); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); - final DragPositioningCallback dragPositioningCallback = - new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController, - 0 /* disallowedAreaForEndBoundsHeight */); + final FluidResizeTaskPositioner taskPositioner = + new FluidResizeTaskPositioner(mTaskOrganizer, mTransitions, windowDecoration, + mDisplayController, 0 /* disallowedAreaForEndBoundsHeight */); final CaptionTouchEventListener touchEventListener = - new CaptionTouchEventListener(taskInfo, dragPositioningCallback); + new CaptionTouchEventListener(taskInfo, taskPositioner); windowDecoration.setCaptionListeners(touchEventListener, touchEventListener); - windowDecoration.setDragPositioningCallback(dragPositioningCallback); + windowDecoration.setDragPositioningCallback(taskPositioner); windowDecoration.setDragDetector(touchEventListener.mDragDetector); + windowDecoration.setTaskDragResizer(taskPositioner); windowDecoration.relayout(taskInfo, startT, finishT, - false /* applyStartTransactionOnDraw */); + false /* applyStartTransactionOnDraw */, false /* setTaskCropAndPosition */); setupCaptionColor(taskInfo, windowDecoration); } 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 6e7d11d9082b..1debb02e86af 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 @@ -157,15 +157,21 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL @Override void relayout(RunningTaskInfo taskInfo) { final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + // The crop and position of the task should only be set when a task is fluid resizing. In + // all other cases, it is expected that the transition handler positions and crops the task + // in order to allow the handler time to animate before the task before the final + // position and crop are set. + final boolean shouldSetTaskPositionAndCrop = mTaskDragResizer.isResizingOrAnimating(); // Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is // synced with the buffer transaction (that draws the View). Both will be shown on screen // at the same, whereas applying them independently causes flickering. See b/270202228. - relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */); + relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */, + shouldSetTaskPositionAndCrop); } void relayout(RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, - boolean applyStartTransactionOnDraw) { + boolean applyStartTransactionOnDraw, boolean setTaskCropAndPosition) { final int shadowRadiusID = taskInfo.isFocused ? R.dimen.freeform_decor_shadow_focused_thickness : R.dimen.freeform_decor_shadow_unfocused_thickness; @@ -183,6 +189,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL mRelayoutParams.mCaptionHeightId = getCaptionHeightId(taskInfo.getWindowingMode()); mRelayoutParams.mShadowRadiusId = shadowRadiusID; mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; + mRelayoutParams.mSetTaskPositionAndCrop = setTaskCropAndPosition; 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 ab29df1f780c..61a8e9b5dd59 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 @@ -335,7 +335,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { if (decoration == null) { createWindowDecoration(taskInfo, taskSurface, startT, finishT); } else { - decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */); + decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */, + false /* shouldSetTaskPositionAndCrop */); } } @@ -347,7 +348,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); if (decoration == null) return; - decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */); + decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */, + false /* shouldSetTaskPositionAndCrop */); } @Override @@ -724,7 +726,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private void handleEventOutsideFocusedCaption(MotionEvent ev, DesktopModeWindowDecoration relevantDecor) { // Returns if event occurs within caption - if (relevantDecor == null || relevantDecor.checkTouchEventInCaption(ev)) { + if (relevantDecor == null || relevantDecor.checkTouchEventInCaptionHandle(ev)) { return; } @@ -759,7 +761,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { || windowingMode == WINDOWING_MODE_MULTI_WINDOW; } - if (dragFromStatusBarAllowed && relevantDecor.checkTouchEventInHandle(ev)) { + if (dragFromStatusBarAllowed + && relevantDecor.checkTouchEventInCaptionHandle(ev)) { mTransitionDragActive = true; } } @@ -1010,8 +1013,23 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); windowDecoration.createResizeVeil(); - final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback( - windowDecoration); + final DragPositioningCallback dragPositioningCallback; + final int transitionAreaHeight = mContext.getResources().getDimensionPixelSize( + R.dimen.desktop_mode_transition_area_height); + if (!DesktopModeStatus.isVeiledResizeEnabled()) { + dragPositioningCallback = new FluidResizeTaskPositioner( + mTaskOrganizer, mTransitions, windowDecoration, mDisplayController, + mDragStartListener, mTransactionFactory, transitionAreaHeight); + windowDecoration.setTaskDragResizer( + (FluidResizeTaskPositioner) dragPositioningCallback); + } else { + dragPositioningCallback = new VeiledResizeTaskPositioner( + mTaskOrganizer, windowDecoration, mDisplayController, + mDragStartListener, mTransitions, transitionAreaHeight); + windowDecoration.setTaskDragResizer( + (VeiledResizeTaskPositioner) dragPositioningCallback); + } + final DesktopModeTouchEventListener touchEventListener = new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback); @@ -1021,23 +1039,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { windowDecoration.setDragPositioningCallback(dragPositioningCallback); windowDecoration.setDragDetector(touchEventListener.mDragDetector); windowDecoration.relayout(taskInfo, startT, finishT, - false /* applyStartTransactionOnDraw */); + false /* applyStartTransactionOnDraw */, false /* shouldSetTaskPositionAndCrop */); incrementEventReceiverTasks(taskInfo.displayId); } - private DragPositioningCallback createDragPositioningCallback( - @NonNull DesktopModeWindowDecoration windowDecoration) { - final int transitionAreaHeight = mContext.getResources().getDimensionPixelSize( - R.dimen.desktop_mode_transition_area_height); - if (!DesktopModeStatus.isVeiledResizeEnabled()) { - return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration, - mDisplayController, mDragStartListener, mTransactionFactory, - transitionAreaHeight); - } else { - return new VeiledResizeTaskPositioner(mTaskOrganizer, windowDecoration, - mDisplayController, mDragStartListener, mTransitions, - transitionAreaHeight); - } - } private RunningTaskInfo getOtherSplitTask(int taskId) { @SplitPosition int remainingTaskPosition = mSplitScreenController @@ -1138,7 +1142,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } } - } 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 3b6be8afb9e7..d08b655e43f8 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 @@ -46,6 +46,7 @@ import android.view.ViewConfiguration; import android.widget.ImageButton; import android.window.WindowContainerTransaction; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.IconProvider; @@ -186,55 +187,33 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get(); + // The crop and position of the task should only be set when a task is fluid resizing. In + // all other cases, it is expected that the transition handler positions and crops the task + // in order to allow the handler time to animate before the task before the final + // position and crop are set. + final boolean shouldSetTaskPositionAndCrop = !DesktopModeStatus.isVeiledResizeEnabled() + && mTaskDragResizer.isResizingOrAnimating(); // Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is // synced with the buffer transaction (that draws the View). Both will be shown on screen // at the same, whereas applying them independently causes flickering. See b/270202228. - relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */); + relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */, + shouldSetTaskPositionAndCrop); } void relayout(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, - boolean applyStartTransactionOnDraw) { - final int shadowRadiusID = taskInfo.isFocused - ? R.dimen.freeform_decor_shadow_focused_thickness - : R.dimen.freeform_decor_shadow_unfocused_thickness; - final boolean isFreeform = - taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; - final boolean isDragResizeable = isFreeform && taskInfo.isResizeable; - + boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) { if (isHandleMenuActive()) { mHandleMenu.relayout(startT); } + updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw, + shouldSetTaskPositionAndCrop); + final WindowDecorLinearLayout oldRootView = mResult.mRootView; final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final WindowContainerTransaction wct = new WindowContainerTransaction(); - final int windowDecorLayoutId = getDesktopModeWindowDecorLayoutId( - taskInfo.getWindowingMode()); - mRelayoutParams.reset(); - mRelayoutParams.mRunningTaskInfo = taskInfo; - mRelayoutParams.mLayoutResId = windowDecorLayoutId; - mRelayoutParams.mCaptionHeightId = getCaptionHeightId(taskInfo.getWindowingMode()); - mRelayoutParams.mShadowRadiusId = shadowRadiusID; - mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; - // The configuration used to lay out the window decoration. The system context's config is - // used when the task density has been overridden to a custom density so that the resources - // and views of the decoration aren't affected and match the rest of the System UI, if not - // then just use the task's configuration. A copy is made instead of using the original - // reference so that the configuration isn't mutated on config changes and diff checks can - // be made in WindowDecoration#relayout using the pre/post-relayout configuration. - // See b/301119301. - // TODO(b/301119301): consider moving the config data needed for diffs to relayout params - // instead of using a whole Configuration as a parameter. - final Configuration windowDecorConfig = new Configuration(); - windowDecorConfig.setTo(DesktopTasksController.isDesktopDensityOverrideSet() - ? mContext.getResources().getConfiguration() // Use system context. - : mTaskInfo.configuration); // Use task configuration. - mRelayoutParams.mWindowDecorConfig = windowDecorConfig; - - mRelayoutParams.mCornerRadius = - (int) ScreenDecorationsUtils.getWindowCornerRadius(mContext); relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo @@ -273,6 +252,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin closeMaximizeMenu(); } + final boolean isFreeform = + taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; + final boolean isDragResizeable = isFreeform && taskInfo.isResizeable; if (!isDragResizeable) { if (!mTaskInfo.positionInParent.equals(mPositionInParent)) { // We still want to track caption bar's exclusion region on a non-resizeable task. @@ -323,6 +305,59 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } } + @VisibleForTesting + static void updateRelayoutParams( + RelayoutParams relayoutParams, + Context context, + ActivityManager.RunningTaskInfo taskInfo, + boolean applyStartTransactionOnDraw, + boolean shouldSetTaskPositionAndCrop) { + relayoutParams.reset(); + relayoutParams.mRunningTaskInfo = taskInfo; + relayoutParams.mLayoutResId = + getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode()); + relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode()); + relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId); + if (DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ taskInfo.isFocused)) { + relayoutParams.mShadowRadiusId = taskInfo.isFocused + ? R.dimen.freeform_decor_shadow_focused_thickness + : R.dimen.freeform_decor_shadow_unfocused_thickness; + } + relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; + relayoutParams.mSetTaskPositionAndCrop = shouldSetTaskPositionAndCrop; + // The configuration used to lay out the window decoration. The system context's config is + // used when the task density has been overridden to a custom density so that the resources + // and views of the decoration aren't affected and match the rest of the System UI, if not + // then just use the task's configuration. A copy is made instead of using the original + // reference so that the configuration isn't mutated on config changes and diff checks can + // be made in WindowDecoration#relayout using the pre/post-relayout configuration. + // See b/301119301. + // TODO(b/301119301): consider moving the config data needed for diffs to relayout params + // instead of using a whole Configuration as a parameter. + final Configuration windowDecorConfig = new Configuration(); + windowDecorConfig.setTo(DesktopTasksController.isDesktopDensityOverrideSet() + ? context.getResources().getConfiguration() // Use system context. + : taskInfo.configuration); // Use task configuration. + relayoutParams.mWindowDecorConfig = windowDecorConfig; + + if (DesktopModeStatus.useRoundedCorners()) { + relayoutParams.mCornerRadius = + (int) ScreenDecorationsUtils.getWindowCornerRadius(context); + } + } + + /** + * If task has focused window decor, return the caption id of the fullscreen caption size + * resource. Otherwise, return ID_NULL and caption width be set to task width. + */ + private static int getCaptionWidthId(int layoutResId) { + if (layoutResId == R.layout.desktop_mode_focused_window_decor) { + return R.dimen.desktop_mode_fullscreen_decor_caption_width; + } + return Resources.ID_NULL; + } + + private PointF calculateMaximizeMenuPosition() { final PointF position = new PointF(); final Resources resources = mContext.getResources(); @@ -535,7 +570,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin .setOnClickListener(mOnCaptionButtonClickListener) .setOnTouchListener(mOnCaptionTouchListener) .setLayoutId(mRelayoutParams.mLayoutResId) - .setCaptionPosition(mRelayoutParams.mCaptionX, mRelayoutParams.mCaptionY) .setWindowingButtonsVisible(DesktopModeStatus.isEnabled()) .setCaptionHeight(mResult.mCaptionHeight) .build(); @@ -612,35 +646,25 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mTaskOrganizer.getRunningTaskInfo(mTaskInfo.taskId); if (taskInfo == null) return result; final Point positionInParent = taskInfo.positionInParent; - result.offset(-mRelayoutParams.mCaptionX, -mRelayoutParams.mCaptionY); result.offset(-positionInParent.x, -positionInParent.y); return result; } /** - * Determine if a passed MotionEvent is in a view in caption + * Checks if motion event occurs in the caption handle area. This should be used in cases where + * onTouchListener will not work (i.e. when caption is in status bar area). * * @param ev the {@link MotionEvent} to check - * @param layoutId the id of the view * @return {@code true} if event is inside the specified view, {@code false} if not */ - private boolean checkEventInCaptionView(MotionEvent ev, int layoutId) { - if (mResult.mRootView == null) return false; + boolean checkTouchEventInCaptionHandle(MotionEvent ev) { + if (isHandleMenuActive() || !(mWindowDecorViewHolder + instanceof DesktopModeFocusedWindowDecorationViewHolder)) { + return false; + } final PointF inputPoint = offsetCaptionLocation(ev); - final View view = mResult.mRootView.findViewById(layoutId); - return view != null && pointInView(view, inputPoint.x, inputPoint.y); - } - - boolean checkTouchEventInHandle(MotionEvent ev) { - if (isHandleMenuActive()) return false; - return checkEventInCaptionView(ev, R.id.caption_handle); - } - - /** - * Returns true if motion event is within the caption's root view's bounds. - */ - boolean checkTouchEventInCaption(MotionEvent ev) { - return checkEventInCaptionView(ev, getCaptionViewId()); + return ((DesktopModeFocusedWindowDecorationViewHolder) mWindowDecorViewHolder) + .pointInCaption(inputPoint, mResult.mCaptionX); } /** @@ -653,24 +677,19 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin void checkClickEvent(MotionEvent ev) { if (mResult.mRootView == null) return; if (!isHandleMenuActive()) { + // Click if point in caption handle view final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption); final View handle = caption.findViewById(R.id.caption_handle); - clickIfPointInView(new PointF(ev.getX(), ev.getY()), handle); + if (checkTouchEventInCaptionHandle(ev)) { + mOnCaptionButtonClickListener.onClick(handle); + } } else { mHandleMenu.checkClickEvent(ev); closeHandleMenuIfNeeded(ev); } } - private boolean clickIfPointInView(PointF inputPoint, View v) { - if (pointInView(v, inputPoint.x, inputPoint.y)) { - mOnCaptionButtonClickListener.onClick(v); - return true; - } - return false; - } - - boolean pointInView(View v, float x, float y) { + private boolean pointInView(View v, float x, float y) { return v != null && v.getLeft() <= x && v.getRight() >= x && v.getTop() <= y && v.getBottom() >= y; } @@ -684,7 +703,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin super.close(); } - private int getDesktopModeWindowDecorLayoutId(@WindowingMode int windowingMode) { + private static int getDesktopModeWindowDecorLayoutId(@WindowingMode int windowingMode) { return windowingMode == WINDOWING_MODE_FREEFORM ? R.layout.desktop_mode_app_controls_window_decor : R.layout.desktop_mode_focused_window_decor; @@ -730,6 +749,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin @Override int getCaptionHeightId(@WindowingMode int windowingMode) { + return getCaptionHeightIdStatic(windowingMode); + } + + private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) { return windowingMode == WINDOWING_MODE_FULLSCREEN ? R.dimen.desktop_mode_fullscreen_decor_caption_height : R.dimen.desktop_mode_freeform_decor_caption_height; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java index 677c7f1fb5a8..5afbd54088d1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java @@ -26,9 +26,7 @@ import android.graphics.PointF; import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.SurfaceControl; -import android.window.WindowContainerTransaction; -import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; /** @@ -130,8 +128,7 @@ public class DragPositioningCallbackUtility { Rect taskBoundsAtDragStart, PointF repositionStartPoint, SurfaceControl.Transaction t, float x, float y) { updateTaskBounds(repositionTaskBounds, taskBoundsAtDragStart, repositionStartPoint, x, y); - t.setPosition(decoration.mTaskSurface, repositionTaskBounds.left, - repositionTaskBounds.top); + t.setPosition(decoration.mTaskSurface, repositionTaskBounds.left, repositionTaskBounds.top); } private static void updateTaskBounds(Rect repositionTaskBounds, Rect taskBoundsAtDragStart, @@ -188,18 +185,6 @@ public class DragPositioningCallbackUtility { } } - /** - * Apply a bounds change to a task. - * @param windowDecoration decor of task we are changing bounds for - * @param taskBounds new bounds of this task - * @param taskOrganizer applies the provided WindowContainerTransaction - */ - static void applyTaskBoundsChange(WindowContainerTransaction wct, - WindowDecoration windowDecoration, Rect taskBounds, ShellTaskOrganizer taskOrganizer) { - wct.setBounds(windowDecoration.mTaskInfo.token, taskBounds); - taskOrganizer.applyTransaction(wct); - } - private static float getMinWidth(DisplayController displayController, WindowDecoration windowDecoration) { return windowDecoration.mTaskInfo.minWidth < 0 ? getDefaultMinSize(displayController, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java index 5d006fb4d9e2..6bfc7cdcb33e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java @@ -16,23 +16,42 @@ package com.android.wm.shell.windowdecor; +import static android.view.WindowManager.TRANSIT_CHANGE; + import android.graphics.PointF; import android.graphics.Rect; +import android.os.IBinder; import android.view.Surface; import android.view.SurfaceControl; +import android.window.TransitionInfo; +import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.transition.Transitions; import java.util.function.Supplier; /** * A task positioner that resizes/relocates task contents as it is dragged. * Utilizes {@link DragPositioningCallbackUtility} to determine new task bounds. + * + * This positioner applies the final bounds after a resize or drag using a shell transition in order + * to utilize the startAnimation callback to set the final task position and crop. In most cases, + * the transition will be aborted since the final bounds are usually the same bounds set in the + * final {@link #onDragPositioningMove} call. In this case, the cropping and positioning would be + * set by {@link WindowDecoration#relayout} due to the final bounds change; however, it is important + * that we send the final shell transition since we still utilize the {@link #onTransitionConsumed} + * callback. */ -class FluidResizeTaskPositioner implements DragPositioningCallback { +class FluidResizeTaskPositioner implements DragPositioningCallback, + TaskDragResizer, Transitions.TransitionHandler { private final ShellTaskOrganizer mTaskOrganizer; + private final Transitions mTransitions; private final WindowDecoration mWindowDecoration; private final Supplier<SurfaceControl.Transaction> mTransactionSupplier; private DisplayController mDisplayController; @@ -45,21 +64,28 @@ class FluidResizeTaskPositioner implements DragPositioningCallback { // finalize the bounds there using WCT#setBounds private final int mDisallowedAreaForEndBoundsHeight; private boolean mHasDragResized; + private boolean mIsResizingOrAnimatingResize; private int mCtrlType; + private IBinder mDragResizeEndTransition; @Surface.Rotation private int mRotation; - FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration, - DisplayController displayController, int disallowedAreaForEndBoundsHeight) { - this(taskOrganizer, windowDecoration, displayController, dragStartListener -> {}, - SurfaceControl.Transaction::new, disallowedAreaForEndBoundsHeight); + FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, Transitions transitions, + WindowDecoration windowDecoration, DisplayController displayController, + int disallowedAreaForEndBoundsHeight) { + this(taskOrganizer, transitions, windowDecoration, displayController, + dragStartListener -> {}, SurfaceControl.Transaction::new, + disallowedAreaForEndBoundsHeight); } - FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration, + FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, + Transitions transitions, + WindowDecoration windowDecoration, DisplayController displayController, DragPositioningCallbackUtility.DragStartListener dragStartListener, Supplier<SurfaceControl.Transaction> supplier, int disallowedAreaForEndBoundsHeight) { mTaskOrganizer = taskOrganizer; + mTransitions = transitions; mWindowDecoration = windowDecoration; mDisplayController = displayController; mDragStartListener = dragStartListener; @@ -103,9 +129,10 @@ class FluidResizeTaskPositioner implements DragPositioningCallback { // This is the first bounds change since drag resize operation started. wct.setDragResizing(mWindowDecoration.mTaskInfo.token, true /* dragResizing */); } - DragPositioningCallbackUtility.applyTaskBoundsChange(wct, mWindowDecoration, - mRepositionTaskBounds, mTaskOrganizer); + wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds); + mTaskOrganizer.applyTransaction(wct); mHasDragResized = true; + mIsResizingOrAnimatingResize = true; } else if (mCtrlType == CTRL_TYPE_UNDEFINED) { final SurfaceControl.Transaction t = mTransactionSupplier.get(); DragPositioningCallbackUtility.setPositionOnDrag(mWindowDecoration, @@ -129,7 +156,7 @@ class FluidResizeTaskPositioner implements DragPositioningCallback { mWindowDecoration)) { wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds); } - mTaskOrganizer.applyTransaction(wct); + mDragResizeEndTransition = mTransitions.startTransition(TRANSIT_CHANGE, wct, this); } else if (mCtrlType == CTRL_TYPE_UNDEFINED && DragPositioningCallbackUtility.isBelowDisallowedArea( mDisallowedAreaForEndBoundsHeight, mTaskBoundsAtDragStart, mRepositionStartPoint, @@ -139,7 +166,7 @@ class FluidResizeTaskPositioner implements DragPositioningCallback { mTaskBoundsAtDragStart, mRepositionStartPoint, x, y, mWindowDecoration.calculateValidDragArea()); wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds); - mTaskOrganizer.applyTransaction(wct); + mTransitions.startTransition(TRANSIT_CHANGE, wct, this); } mTaskBoundsAtDragStart.setEmpty(); @@ -154,4 +181,51 @@ class FluidResizeTaskPositioner implements DragPositioningCallback { || (mCtrlType & CTRL_TYPE_LEFT) != 0 || (mCtrlType & CTRL_TYPE_RIGHT) != 0; } + @Override + public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + for (TransitionInfo.Change change: info.getChanges()) { + final SurfaceControl sc = change.getLeash(); + final Rect endBounds = change.getEndAbsBounds(); + startTransaction.setWindowCrop(sc, endBounds.width(), endBounds.height()) + .setPosition(sc, endBounds.left, endBounds.top); + finishTransaction.setWindowCrop(sc, endBounds.width(), endBounds.height()) + .setPosition(sc, endBounds.left, endBounds.top); + } + + startTransaction.apply(); + if (transition.equals(mDragResizeEndTransition)) { + mIsResizingOrAnimatingResize = false; + mDragResizeEndTransition = null; + } + finishCallback.onTransitionFinished(null); + return true; + } + + /** + * We should never reach this as this handler's transitions are only started from shell + * explicitly. + */ + @Nullable + @Override + public WindowContainerTransaction handleRequest(@NonNull IBinder transition, + @NonNull TransitionRequestInfo request) { + return null; + } + + @Override + public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted, + @Nullable SurfaceControl.Transaction finishTransaction) { + if (transition.equals(mDragResizeEndTransition)) { + mIsResizingOrAnimatingResize = false; + mDragResizeEndTransition = null; + } + } + + @Override + public boolean isResizingOrAnimating() { + return mIsResizingOrAnimatingResize; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java index 652a2ed39c67..b37dd0d6fd2d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java @@ -64,8 +64,6 @@ class HandleMenu { private final View.OnTouchListener mOnTouchListener; private final RunningTaskInfo mTaskInfo; private final int mLayoutResId; - private final int mCaptionX; - private final int mCaptionY; private int mMarginMenuTop; private int mMarginMenuStart; private int mMenuHeight; @@ -74,16 +72,13 @@ class HandleMenu { private HandleMenuAnimator mHandleMenuAnimator; - HandleMenu(WindowDecoration parentDecor, int layoutResId, int captionX, int captionY, - View.OnClickListener onClickListener, View.OnTouchListener onTouchListener, - Bitmap appIcon, CharSequence appName, boolean shouldShowWindowingPill, - int captionHeight) { + HandleMenu(WindowDecoration parentDecor, int layoutResId, View.OnClickListener onClickListener, + View.OnTouchListener onTouchListener, Bitmap appIcon, CharSequence appName, + boolean shouldShowWindowingPill, int captionHeight) { mParentDecor = parentDecor; mContext = mParentDecor.mDecorWindowContext; mTaskInfo = mParentDecor.mTaskInfo; mLayoutResId = layoutResId; - mCaptionX = captionX; - mCaptionY = captionY; mOnClickListener = onClickListener; mOnTouchListener = onTouchListener; mAppIconBitmap = appIcon; @@ -225,12 +220,12 @@ class HandleMenu { if (mLayoutResId == R.layout.desktop_mode_app_controls_window_decor) { // Align the handle menu to the left of the caption. - menuX = mCaptionX + mMarginMenuStart; - menuY = mCaptionY + mMarginMenuTop; + menuX = mMarginMenuStart; + menuY = mMarginMenuTop; } else { // Position the handle menu at the center of the caption. - menuX = mCaptionX + (captionWidth / 2) - (mMenuWidth / 2); - menuY = mCaptionY + mMarginMenuStart; + menuX = (captionWidth / 2) - (mMenuWidth / 2); + menuY = mMarginMenuStart; } // Handle Menu position setup. @@ -346,8 +341,6 @@ class HandleMenu { private View.OnClickListener mOnClickListener; private View.OnTouchListener mOnTouchListener; private int mLayoutId; - private int mCaptionX; - private int mCaptionY; private boolean mShowWindowingPill; private int mCaptionHeight; @@ -381,12 +374,6 @@ class HandleMenu { return this; } - Builder setCaptionPosition(int captionX, int captionY) { - mCaptionX = captionX; - mCaptionY = captionY; - return this; - } - Builder setWindowingButtonsVisible(boolean windowingButtonsVisible) { mShowWindowingPill = windowingButtonsVisible; return this; @@ -398,8 +385,8 @@ class HandleMenu { } HandleMenu build() { - return new HandleMenu(mParent, mLayoutId, mCaptionX, mCaptionY, mOnClickListener, - mOnTouchListener, mAppIcon, mName, mShowWindowingPill, mCaptionHeight); + return new HandleMenu(mParent, mLayoutId, mOnClickListener, mOnTouchListener, + mAppIcon, mName, mShowWindowingPill, mCaptionHeight); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskDragResizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskDragResizer.java new file mode 100644 index 000000000000..40421b599889 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskDragResizer.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.windowdecor; + +/** + * Holds the state of a drag resize. + */ +interface TaskDragResizer { + + /** + * Returns true if task is currently being resized or animating the final transition after + * a resize is complete. + */ + boolean isResizingOrAnimating(); +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java index 4363558ca00b..c1b18f959641 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java @@ -43,7 +43,7 @@ import java.util.function.Supplier; * If the drag is repositioning, we update in the typical manner. */ public class VeiledResizeTaskPositioner implements DragPositioningCallback, - Transitions.TransitionHandler { + TaskDragResizer, Transitions.TransitionHandler { private DesktopModeWindowDecoration mDesktopWindowDecoration; private ShellTaskOrganizer mTaskOrganizer; @@ -59,10 +59,12 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, private final int mDisallowedAreaForEndBoundsHeight; private final Supplier<SurfaceControl.Transaction> mTransactionSupplier; private int mCtrlType; + private boolean mIsResizingOrAnimatingResize; @Surface.Rotation private int mRotation; public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, - DesktopModeWindowDecoration windowDecoration, DisplayController displayController, + DesktopModeWindowDecoration windowDecoration, + DisplayController displayController, DragPositioningCallbackUtility.DragStartListener dragStartListener, Transitions transitions, int disallowedAreaForEndBoundsHeight) { @@ -71,12 +73,13 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, } public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, - DesktopModeWindowDecoration windowDecoration, DisplayController displayController, + DesktopModeWindowDecoration windowDecoration, + DisplayController displayController, DragPositioningCallbackUtility.DragStartListener dragStartListener, Supplier<SurfaceControl.Transaction> supplier, Transitions transitions, int disallowedAreaForEndBoundsHeight) { - mTaskOrganizer = taskOrganizer; mDesktopWindowDecoration = windowDecoration; + mTaskOrganizer = taskOrganizer; mDisplayController = displayController; mDragStartListener = dragStartListener; mTransactionSupplier = supplier; @@ -117,6 +120,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta, mDisplayController, mDesktopWindowDecoration)) { mDesktopWindowDecoration.updateResizeVeil(mRepositionTaskBounds); + mIsResizingOrAnimatingResize = true; } else if (mCtrlType == CTRL_TYPE_UNDEFINED) { final SurfaceControl.Transaction t = mTransactionSupplier.get(); DragPositioningCallbackUtility.setPositionOnDrag(mDesktopWindowDecoration, @@ -138,24 +142,22 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, mDesktopWindowDecoration.updateResizeVeil(mRepositionTaskBounds); final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mDesktopWindowDecoration.mTaskInfo.token, mRepositionTaskBounds); - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - mTransitions.startTransition(TRANSIT_CHANGE, wct, this); - } else { - mTaskOrganizer.applyTransaction(wct); - } + mTransitions.startTransition(TRANSIT_CHANGE, wct, this); } else { // If bounds haven't changed, perform necessary veil reset here as startAnimation // won't be called. mDesktopWindowDecoration.hideResizeVeil(); + mIsResizingOrAnimatingResize = false; } } else if (DragPositioningCallbackUtility.isBelowDisallowedArea( mDisallowedAreaForEndBoundsHeight, mTaskBoundsAtDragStart, mRepositionStartPoint, y)) { + final WindowContainerTransaction wct = new WindowContainerTransaction(); DragPositioningCallbackUtility.onDragEnd(mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, x, y, mDesktopWindowDecoration.calculateValidDragArea()); - DragPositioningCallbackUtility.applyTaskBoundsChange(new WindowContainerTransaction(), - mDesktopWindowDecoration, mRepositionTaskBounds, mTaskOrganizer); + wct.setBounds(mDesktopWindowDecoration.mTaskInfo.token, mRepositionTaskBounds); + mTransitions.startTransition(TRANSIT_CHANGE, wct, this); } mCtrlType = CTRL_TYPE_UNDEFINED; @@ -174,10 +176,20 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { + for (TransitionInfo.Change change: info.getChanges()) { + final SurfaceControl sc = change.getLeash(); + final Rect endBounds = change.getEndAbsBounds(); + startTransaction.setWindowCrop(sc, endBounds.width(), endBounds.height()) + .setPosition(sc, endBounds.left, endBounds.top); + finishTransaction.setWindowCrop(sc, endBounds.width(), endBounds.height()) + .setPosition(sc, endBounds.left, endBounds.top); + } + startTransaction.apply(); mDesktopWindowDecoration.hideResizeVeil(); mCtrlType = CTRL_TYPE_UNDEFINED; finishCallback.onTransitionFinished(null); + mIsResizingOrAnimatingResize = false; return true; } @@ -191,4 +203,9 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, @NonNull TransitionRequestInfo request) { return null; } + + @Override + public boolean isResizingOrAnimating() { + return mIsResizingOrAnimatingResize; + } } 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 ee0e31ec3aef..6a9258c68acf 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 @@ -124,6 +124,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> private WindowlessWindowManager mCaptionWindowManager; private SurfaceControlViewHost mViewHost; private Configuration mWindowDecorConfig; + TaskDragResizer mTaskDragResizer; private boolean mIsCaptionVisible; private final Binder mOwner = new Binder(); @@ -278,9 +279,12 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } outResult.mCaptionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId); - final int captionWidth = taskBounds.width(); + final int captionWidth = params.mCaptionWidthId != Resources.ID_NULL + ? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width(); + outResult.mCaptionX = (outResult.mWidth - captionWidth) / 2; startT.setWindowCrop(mCaptionContainerSurface, captionWidth, outResult.mCaptionHeight) + .setPosition(mCaptionContainerSurface, outResult.mCaptionX, 0 /* y */) .setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER) .show(mCaptionContainerSurface); @@ -291,7 +295,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mCaptionInsetsRect.set(taskBounds); if (mIsCaptionVisible) { mCaptionInsetsRect.bottom = - mCaptionInsetsRect.top + outResult.mCaptionHeight + params.mCaptionY; + mCaptionInsetsRect.top + outResult.mCaptionHeight; wct.addInsetsSource(mTaskInfo.token, mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect); wct.addInsetsSource(mTaskInfo.token, @@ -311,25 +315,21 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> float shadowRadius; final Point taskPosition = mTaskInfo.positionInParent; if (isFullscreen) { - // Setting the task crop to the width/height stops input events from being sent to - // some regions of the app window. See b/300324920 - // TODO(b/296921174): investigate whether crop/position needs to be set by window - // decorations at all when transition handlers are already taking ownership of the task - // surface placement/crop, especially when in fullscreen where tasks cannot be - // drag-resized by the window decoration. - startT.setWindowCrop(mTaskSurface, null); - finishT.setWindowCrop(mTaskSurface, null); // Shadow is not needed for fullscreen tasks shadowRadius = 0; } else { - startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight); - finishT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight); shadowRadius = loadDimension(resources, params.mShadowRadiusId); } + + if (params.mSetTaskPositionAndCrop) { + startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight); + finishT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight) + .setPosition(mTaskSurface, taskPosition.x, taskPosition.y); + } + startT.setShadowRadius(mTaskSurface, shadowRadius) .show(mTaskSurface); - finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y) - .setShadowRadius(mTaskSurface, shadowRadius); + finishT.setShadowRadius(mTaskSurface, shadowRadius); if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { if (!DesktopModeStatus.isVeiledResizeEnabled()) { // When fluid resize is enabled, add a background to freeform tasks @@ -394,6 +394,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } } + void setTaskDragResizer(TaskDragResizer taskDragResizer) { + mTaskDragResizer = taskDragResizer; + } + private void setCaptionVisibility(View rootView, boolean visible) { if (rootView == null) { return; @@ -553,12 +557,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> int mCornerRadius; - int mCaptionX; - int mCaptionY; - Configuration mWindowDecorConfig; boolean mApplyStartTransactionOnDraw; + boolean mSetTaskPositionAndCrop; void reset() { mLayoutResId = Resources.ID_NULL; @@ -568,16 +570,15 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mCornerRadius = 0; - mCaptionX = 0; - mCaptionY = 0; - mApplyStartTransactionOnDraw = false; + mSetTaskPositionAndCrop = false; mWindowDecorConfig = null; } } static class RelayoutResult<T extends View & TaskFocusStateConsumer> { int mCaptionHeight; + int mCaptionX; int mWidth; int mHeight; T mRootView; @@ -586,6 +587,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mWidth = 0; mHeight = 0; mCaptionHeight = 0; + mCaptionX = 0; mRootView = null; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt index 4930cb721336..5f77022a577d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt @@ -5,6 +5,7 @@ import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.res.ColorStateList import android.graphics.Color +import android.graphics.PointF import android.view.View import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS import android.widget.ImageButton @@ -35,9 +36,6 @@ internal class DesktopModeFocusedWindowDecorationViewHolder( } override fun bindData(taskInfo: RunningTaskInfo) { - taskInfo.taskDescription?.statusBarColor?.let { captionColor -> - captionView.setBackgroundColor(captionColor) - } captionHandle.imageTintList = ColorStateList.valueOf(getCaptionHandleBarColor(taskInfo)) } @@ -49,6 +47,17 @@ internal class DesktopModeFocusedWindowDecorationViewHolder( animateCaptionHandleAlpha(startValue = 0f, endValue = 1f) } + /** + * Returns true if input point is in the caption's view. + * @param inputPoint the input point relative to the task in full "focus" (i.e. fullscreen). + */ + fun pointInCaption(inputPoint: PointF, captionX: Int): Boolean { + return inputPoint.x >= captionX && + inputPoint.x <= captionX + captionView.width && + inputPoint.y >= 0 && + inputPoint.y <= captionView.height + } + private fun getCaptionHandleBarColor(taskInfo: RunningTaskInfo): Int { return if (shouldUseLightCaptionColors(taskInfo)) { context.getColor(R.color.desktop_mode_caption_handle_bar_light) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt index 690b4e4be122..81bc34c876b6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt @@ -17,9 +17,9 @@ internal abstract class DesktopModeWindowDecorationViewHolder(rootView: View) { */ abstract fun bindData(taskInfo: RunningTaskInfo) - /** Callback when the handle menu is opened. */ - abstract fun onHandleMenuOpened() + /** Callback when the handle menu is opened. */ + abstract fun onHandleMenuOpened() - /** Callback when the handle menu is closed. */ - abstract fun onHandleMenuClosed() + /** Callback when the handle menu is closed. */ + abstract fun onHandleMenuClosed() } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt index 32f12592135d..143f7a726ed3 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt @@ -69,7 +69,7 @@ open class NetflixEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransit setup { standardAppHelper.launchViaIntent( wmHelper, - NetflixAppHelper.getNetflixWatchVideoIntent("70184207"), + NetflixAppHelper.getNetflixWatchVideoIntent("81605060"), ComponentNameMatcher(NetflixAppHelper.PACKAGE_NAME, NetflixAppHelper.WATCH_ACTIVITY) ) standardAppHelper.waitForVideoPlaying() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index 18fcdd00df9d..193f16da3e39 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -16,16 +16,24 @@ package com.android.wm.shell.windowdecor; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.content.ComponentName; import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; import android.os.Handler; +import android.os.SystemProperties; import android.testing.AndroidTestingRunner; +import android.testing.TestableContext; import android.view.Choreographer; import android.view.Display; import android.view.SurfaceControl; @@ -34,14 +42,17 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import com.android.internal.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -57,6 +68,13 @@ import java.util.function.Supplier; @SmallTest @RunWith(AndroidTestingRunner.class) public class DesktopModeWindowDecorationTests extends ShellTestCase { + private static final String USE_WINDOW_SHADOWS_SYSPROP_KEY = + "persist.wm.debug.desktop_use_window_shadows"; + private static final String FOCUSED_USE_WINDOW_SHADOWS_SYSPROP_KEY = + "persist.wm.debug.desktop_use_window_shadows_focused_window"; + private static final String USE_ROUNDED_CORNERS_SYSPROP_KEY = + "persist.wm.debug.desktop_use_rounded_corners"; + @Mock private DisplayController mMockDisplayController; @Mock @@ -79,14 +97,29 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private SurfaceControlViewHost mMockSurfaceControlViewHost; @Mock private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory; + @Mock + private TypedArray mMockRoundedCornersRadiusArray; private final Configuration mConfiguration = new Configuration(); + private TestableContext mTestableContext; + + /** Set up run before test class. */ + @BeforeClass + public static void setUpClass() { + // Reset the sysprop settings before running the test. + SystemProperties.set(USE_WINDOW_SHADOWS_SYSPROP_KEY, ""); + SystemProperties.set(FOCUSED_USE_WINDOW_SHADOWS_SYSPROP_KEY, ""); + SystemProperties.set(USE_ROUNDED_CORNERS_SYSPROP_KEY, ""); + } + @Before public void setUp() { doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory).create( any(), any(), any()); doReturn(mMockTransaction).when(mMockTransactionSupplier).get(); + mTestableContext = new TestableContext(mContext); + mTestableContext.ensureTestableResources(); } @Test @@ -105,6 +138,52 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } + @Test + public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreEnabled() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + RelayoutParams relayoutParams = new RelayoutParams(); + + DesktopModeWindowDecoration.updateRelayoutParams( + relayoutParams, mContext, taskInfo, /* applyStartTransactionOnDraw= */ true, + /* shouldSetTaskPositionAndCrop */ false); + + assertThat(relayoutParams.mShadowRadiusId).isNotEqualTo(Resources.ID_NULL); + } + + @Test + public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersAreEnabled() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + fillRoundedCornersResources(/* fillValue= */ 30); + RelayoutParams relayoutParams = new RelayoutParams(); + + DesktopModeWindowDecoration.updateRelayoutParams( + relayoutParams, + mTestableContext, + taskInfo, + /* applyStartTransactionOnDraw= */ true, + /* shouldSetTaskPositionAndCrop */ false); + + assertThat(relayoutParams.mCornerRadius).isGreaterThan(0); + } + + private void fillRoundedCornersResources(int fillValue) { + when(mMockRoundedCornersRadiusArray.getDimensionPixelSize(anyInt(), anyInt())) + .thenReturn(fillValue); + mTestableContext.getOrCreateTestableResources().addOverride( + R.array.config_roundedCornerRadiusArray, mMockRoundedCornersRadiusArray); + mTestableContext.getOrCreateTestableResources().addOverride( + R.dimen.rounded_corner_radius, fillValue); + mTestableContext.getOrCreateTestableResources().addOverride( + R.array.config_roundedCornerTopRadiusArray, mMockRoundedCornersRadiusArray); + mTestableContext.getOrCreateTestableResources().addOverride( + R.dimen.rounded_corner_radius_top, fillValue); + mTestableContext.getOrCreateTestableResources().addOverride( + R.array.config_roundedCornerBottomRadiusArray, mMockRoundedCornersRadiusArray); + mTestableContext.getOrCreateTestableResources().addOverride( + R.dimen.rounded_corner_radius_bottom, fillValue); + } + + private DesktopModeWindowDecoration createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo) { return new DesktopModeWindowDecoration(mContext, mMockDisplayController, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt index 2ce49cf62614..de6903d9a06a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt @@ -10,6 +10,7 @@ import android.view.Surface import android.view.Surface.ROTATION_270 import android.view.Surface.ROTATION_90 import android.view.SurfaceControl +import android.view.WindowManager import android.window.WindowContainerToken import android.window.WindowContainerTransaction import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING @@ -18,13 +19,17 @@ import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.transition.Transitions import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito @@ -34,6 +39,7 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import org.mockito.kotlin.doReturn import java.util.function.Supplier import org.mockito.Mockito.`when` as whenever @@ -50,6 +56,8 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { @Mock private lateinit var mockShellTaskOrganizer: ShellTaskOrganizer @Mock + private lateinit var mockTransitions: Transitions + @Mock private lateinit var mockWindowDecoration: WindowDecoration<*> @Mock private lateinit var mockDragStartListener: DragPositioningCallbackUtility.DragStartListener @@ -69,6 +77,8 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { private lateinit var mockTransactionFactory: Supplier<SurfaceControl.Transaction> @Mock private lateinit var mockTransaction: SurfaceControl.Transaction + @Mock + private lateinit var mockTransitionBinder: IBinder private lateinit var taskPositioner: FluidResizeTaskPositioner @@ -106,9 +116,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { `when`(mockWindowDecoration.calculateValidDragArea()).thenReturn(VALID_DRAG_AREA) mockWindowDecoration.mDisplay = mockDisplay whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID } + whenever(mockTransitions.startTransition(anyInt(), any(), any())) + .doReturn(mockTransitionBinder) taskPositioner = FluidResizeTaskPositioner( mockShellTaskOrganizer, + mockTransitions, mockWindowDecoration, mockDisplayController, mockDragStartListener, @@ -118,7 +131,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { } @Test - fun testDragResize_notMove_skipsTransactionOnEnd() { + fun testDragResize_notMove_skipsTransitionOnEnd() { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, STARTING_BOUNDS.left.toFloat(), @@ -130,16 +143,16 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { STARTING_BOUNDS.top.toFloat() + 10 ) - verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> + verify(mockTransitions, never()).startTransition( + eq(WindowManager.TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) - } - }) + }}, eq(taskPositioner)) } @Test - fun testDragResize_noEffectiveMove_skipsTransactionOnMoveAndEnd() { + fun testDragResize_noEffectiveMove_skipsTransitionOnMoveAndEnd() { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, STARTING_BOUNDS.left.toFloat(), @@ -151,21 +164,28 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { STARTING_BOUNDS.top.toFloat() ) + verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> + return@argThat wct.changes.any { (token, change) -> + token == taskBinder && + ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) + } + }) + taskPositioner.onDragPositioningEnd( STARTING_BOUNDS.left.toFloat() + 10, STARTING_BOUNDS.top.toFloat() + 10 ) - verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> + verify(mockTransitions, never()).startTransition( + eq(WindowManager.TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) - } - }) + }}, eq(taskPositioner)) } @Test - fun testDragResize_hasEffectiveMove_issuesTransactionOnMoveAndEnd() { + fun testDragResize_hasEffectiveMove_issuesTransitionOnMoveAndEnd() { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, STARTING_BOUNDS.left.toFloat(), @@ -192,13 +212,13 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { ) val rectAfterEnd = Rect(rectAfterMove) rectAfterEnd.top += 10 - verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> - return@argThat wct.changes.any { (token, change) -> - token == taskBinder && - (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 && - change.configuration.windowConfiguration.bounds == rectAfterEnd - } - }) + verify(mockTransitions).startTransition( + eq(WindowManager.TRANSIT_CHANGE), argThat { wct -> + return@argThat wct.changes.any { (token, change) -> + token == taskBinder && + (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 && + change.configuration.windowConfiguration.bounds == rectAfterEnd + }}, eq(taskPositioner)) } @Test @@ -226,6 +246,13 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { change.dragResizing } }) + verify(mockTransitions, never()).startTransition( + eq(WindowManager.TRANSIT_CHANGE), argThat { wct -> + return@argThat wct.changes.any { (token, change) -> + token == taskBinder && + ((change.changeMask and CHANGE_DRAG_RESIZING) != 0) && + change.dragResizing + }}, eq(taskPositioner)) } @Test @@ -253,13 +280,13 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { change.dragResizing } }) - verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> + verify(mockTransitions).startTransition( + eq(WindowManager.TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && ((change.changeMask and CHANGE_DRAG_RESIZING) != 0) && !change.dragResizing - } - }) + }}, eq(taskPositioner)) } @Test @@ -270,7 +297,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { STARTING_BOUNDS.top.toFloat() ) - // Resize to width of 95px and height of 5px with min width of 10px + // Resize to width of 95px and height of 5px with min height of 10px val newX = STARTING_BOUNDS.right.toFloat() - 5 val newY = STARTING_BOUNDS.top.toFloat() + 95 taskPositioner.onDragPositioningMove( @@ -566,12 +593,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { taskPositioner.onDragPositioningEnd(newX, newY) - verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> + verify(mockTransitions, never()).startTransition( + eq(WindowManager.TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) - } - }) + }}, eq(taskPositioner)) } private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean { @@ -650,14 +677,14 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { ) // Verify task's top bound is set to stable bounds top since dragged outside stable bounds // but not in disallowed end bounds area. - verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> + verify(mockTransitions).startTransition( + eq(WindowManager.TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 && change.configuration.windowConfiguration.bounds.top == STABLE_BOUNDS_LANDSCAPE.top - } - }) + }}, eq(taskPositioner)) } @Test @@ -680,7 +707,8 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { newX, newY ) - verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> + verify(mockTransitions).startTransition( + eq(WindowManager.TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 && @@ -688,8 +716,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { VALID_DRAG_AREA.bottom && change.configuration.windowConfiguration.bounds.left == VALID_DRAG_AREA.left - } - }) + }}, eq(taskPositioner)) } @Test @@ -741,6 +768,59 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { verify(mockDisplayLayout, Mockito.times(2)).getStableBounds(any()) } + @Test + fun testIsResizingOrAnimatingResizeSet() { + assertFalse(taskPositioner.isResizingOrAnimating) + + taskPositioner.onDragPositioningStart( + CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, + STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat() + ) + + taskPositioner.onDragPositioningMove( + STARTING_BOUNDS.left.toFloat() - 20, + STARTING_BOUNDS.top.toFloat() - 20 + ) + + // isResizingOrAnimating should be set to true after move during a resize + assertTrue(taskPositioner.isResizingOrAnimating) + + taskPositioner.onDragPositioningEnd( + STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat() + ) + + // isResizingOrAnimating should be not be set till false until after transition animation + assertTrue(taskPositioner.isResizingOrAnimating) + } + + @Test + fun testIsResizingOrAnimatingResizeResetAfterAbortedTransition() { + performDrag(STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat(), STARTING_BOUNDS.left.toFloat() - 20, + STARTING_BOUNDS.top.toFloat() - 20, CTRL_TYPE_TOP or CTRL_TYPE_RIGHT) + + taskPositioner.onTransitionConsumed(mockTransitionBinder, true /* aborted */, + mockTransaction) + + // isResizingOrAnimating should be set to false until after transition successfully consumed + assertFalse(taskPositioner.isResizingOrAnimating) + } + + @Test + fun testIsResizingOrAnimatingResizeResetAfterNonAbortedTransition() { + performDrag(STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat(), STARTING_BOUNDS.left.toFloat() - 20, + STARTING_BOUNDS.top.toFloat() - 20, CTRL_TYPE_TOP or CTRL_TYPE_RIGHT) + + taskPositioner.onTransitionConsumed(mockTransitionBinder, false /* aborted */, + mockTransaction) + + // isResizingOrAnimating should be set to false until after transition successfully consumed + assertFalse(taskPositioner.isResizingOrAnimating) + } + private fun performDrag( startX: Float, startY: Float, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt index a759b53f4238..08412101c30c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt @@ -26,6 +26,7 @@ import android.view.Surface.ROTATION_270 import android.view.Surface.ROTATION_90 import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE +import android.window.TransitionInfo import android.window.WindowContainerToken import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTaskOrganizer @@ -33,10 +34,12 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.transition.Transitions +import com.android.wm.shell.transition.Transitions.TransitionFinishCallback import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED +import junit.framework.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -85,6 +88,12 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { @Mock private lateinit var mockTransaction: SurfaceControl.Transaction @Mock + private lateinit var mockTransitionBinder: IBinder + @Mock + private lateinit var mockTransitionInfo: TransitionInfo + @Mock + private lateinit var mockFinishCallback: TransitionFinishCallback + @Mock private lateinit var mockTransitions: Transitions private lateinit var taskPositioner: VeiledResizeTaskPositioner @@ -188,13 +197,12 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { verify(mockDesktopWindowDecoration, never()).createResizeVeil() verify(mockDesktopWindowDecoration, never()).hideResizeVeil() - verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> + verify(mockTransitions).startTransition(eq(TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 && - change.configuration.windowConfiguration.bounds == rectAfterEnd - } - }) + change.configuration.windowConfiguration.bounds == rectAfterEnd }}, + eq(taskPositioner)) } @Test @@ -369,14 +377,13 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { ) // Verify task's top bound is set to stable bounds top since dragged outside stable bounds // but not in disallowed end bounds area. - verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> + verify(mockTransitions).startTransition(eq(TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 && change.configuration.windowConfiguration.bounds.top == - STABLE_BOUNDS_LANDSCAPE.top - } - }) + STABLE_BOUNDS_LANDSCAPE.top }}, + eq(taskPositioner)) } @Test @@ -399,16 +406,15 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { newX, newY ) - verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> + verify(mockTransitions).startTransition(eq(TRANSIT_CHANGE), argThat { wct -> return@argThat wct.changes.any { (token, change) -> token == taskBinder && (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 && change.configuration.windowConfiguration.bounds.top == VALID_DRAG_AREA.bottom && change.configuration.windowConfiguration.bounds.left == - VALID_DRAG_AREA.left - } - }) + VALID_DRAG_AREA.left }}, + eq(taskPositioner)) } @Test @@ -456,6 +462,47 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { verify(mockDisplayLayout, times(2)).getStableBounds(any()) } + @Test + fun testIsResizingOrAnimatingResizeSet() { + Assert.assertFalse(taskPositioner.isResizingOrAnimating) + + taskPositioner.onDragPositioningStart( + CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, + STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat() + ) + + taskPositioner.onDragPositioningMove( + STARTING_BOUNDS.left.toFloat() - 20, + STARTING_BOUNDS.top.toFloat() - 20 + ) + + // isResizingOrAnimating should be set to true after move during a resize + Assert.assertTrue(taskPositioner.isResizingOrAnimating) + + taskPositioner.onDragPositioningEnd( + STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat() + ) + + // isResizingOrAnimating should be not be set till false until after transition animation + Assert.assertTrue(taskPositioner.isResizingOrAnimating) + } + + @Test + fun testIsResizingOrAnimatingResizeResetAfterStartAnimation() { + performDrag( + STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat(), + STARTING_BOUNDS.left.toFloat() - 20, STARTING_BOUNDS.top.toFloat() - 20, + CTRL_TYPE_TOP or CTRL_TYPE_RIGHT) + + taskPositioner.startAnimation(mockTransitionBinder, mockTransitionInfo, mockTransaction, + mockTransaction, mockFinishCallback) + + // isResizingOrAnimating should be set to false until after transition successfully consumed + Assert.assertFalse(taskPositioner.isResizingOrAnimating) + } + private fun performDrag( startX: Float, startY: Float, 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 fe508e23af33..7b53f70a771c 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 @@ -32,6 +32,7 @@ import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.argThat; @@ -261,11 +262,6 @@ public class WindowDecorationTests extends ShellTestCase { eq(new Rect(100, 300, 400, 364))); } - verify(mMockSurfaceControlFinishT) - .setPosition(mMockTaskSurface, TASK_POSITION_IN_PARENT.x, - TASK_POSITION_IN_PARENT.y); - verify(mMockSurfaceControlFinishT) - .setWindowCrop(mMockTaskSurface, 300, 100); verify(mMockSurfaceControlStartT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS); verify(mMockSurfaceControlFinishT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS); verify(mMockSurfaceControlStartT) @@ -642,6 +638,66 @@ public class WindowDecorationTests extends ShellTestCase { eq(0) /* index */, eq(mandatorySystemGestures())); } + @Test + public void testTaskPositionAndCropNotSetWhenFalse() { + final Display defaultDisplay = mock(Display.class); + doReturn(defaultDisplay).when(mMockDisplayController) + .getDisplay(Display.DEFAULT_DISPLAY); + + final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setBounds(TASK_BOUNDS) + .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y) + .setVisible(true) + .setWindowingMode(WINDOWING_MODE_FREEFORM) + .build(); + taskInfo.isFocused = true; + // Density is 2. Shadow radius is 10px. Caption height is 64px. + taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; + final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo); + + + mRelayoutParams.mSetTaskPositionAndCrop = false; + windowDecor.relayout(taskInfo); + + verify(mMockSurfaceControlStartT, never()).setWindowCrop( + eq(mMockTaskSurface), anyInt(), anyInt()); + verify(mMockSurfaceControlFinishT, never()).setPosition( + eq(mMockTaskSurface), anyFloat(), anyFloat()); + verify(mMockSurfaceControlFinishT, never()).setWindowCrop( + eq(mMockTaskSurface), anyInt(), anyInt()); + } + + @Test + public void testTaskPositionAndCropSetWhenSetTrue() { + final Display defaultDisplay = mock(Display.class); + doReturn(defaultDisplay).when(mMockDisplayController) + .getDisplay(Display.DEFAULT_DISPLAY); + + final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setBounds(TASK_BOUNDS) + .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y) + .setVisible(true) + .setWindowingMode(WINDOWING_MODE_FREEFORM) + .build(); + taskInfo.isFocused = true; + // Density is 2. Shadow radius is 10px. Caption height is 64px. + taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; + final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo); + + mRelayoutParams.mSetTaskPositionAndCrop = true; + windowDecor.relayout(taskInfo); + + verify(mMockSurfaceControlStartT).setWindowCrop( + eq(mMockTaskSurface), anyInt(), anyInt()); + verify(mMockSurfaceControlFinishT).setPosition( + eq(mMockTaskSurface), anyFloat(), anyFloat()); + verify(mMockSurfaceControlFinishT).setWindowCrop( + eq(mMockTaskSurface), anyInt(), anyInt()); + } + + private TestWindowDecoration createWindowDecoration(ActivityManager.RunningTaskInfo taskInfo) { return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer, taskInfo, mMockTaskSurface, mWindowConfiguration, @@ -716,15 +772,13 @@ public class WindowDecorationTests extends ShellTestCase { private WindowDecoration.AdditionalWindow addTestWindow() { final Resources resources = mDecorWindowContext.getResources(); - int x = mRelayoutParams.mCaptionX; - int y = mRelayoutParams.mCaptionY; int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId); int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId); String name = "Test Window"; WindowDecoration.AdditionalWindow additionalWindow = addWindow(R.layout.desktop_mode_window_decor_handle_menu, name, - mMockSurfaceControlAddWindowT, mMockSurfaceSyncGroup, x, y, - width, height); + mMockSurfaceControlAddWindowT, mMockSurfaceSyncGroup, 0 /* x */, + 0 /* y */, width, height); return additionalWindow; } } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 47411701e5ab..eebf8aabd89c 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -38,6 +38,7 @@ aconfig_declarations { cc_aconfig_library { name: "hwui_flags_cc_lib", + host_supported: true, aconfig_declarations: "hwui_flags", } @@ -109,12 +110,15 @@ cc_defaults { "libbase", "libharfbuzz_ng", "libminikin", + "server_configurable_flags", ], static_libs: [ "libui-types", ], + whole_static_libs: ["hwui_flags_cc_lib"], + target: { android: { shared_libs: [ @@ -146,7 +150,6 @@ cc_defaults { "libstatspull_lazy", "libstatssocket_lazy", "libtonemap", - "hwui_flags_cc_lib", ], }, host: { diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig index ca119757e816..c156c46a5a9b 100644 --- a/libs/hwui/aconfig/hwui_flags.aconfig +++ b/libs/hwui/aconfig/hwui_flags.aconfig @@ -15,6 +15,13 @@ flag { } flag { + name: "high_contrast_text_luminance" + namespace: "accessibility" + description: "Use luminance to determine how to make text more high contrast, instead of RGB heuristic" + bug: "186567103" +} + +flag { name: "hdr_10bit_plus" namespace: "core_graphics" description: "Use 10101010 and FP16 formats for HDR-UI when available" diff --git a/libs/hwui/hwui/DrawTextFunctor.h b/libs/hwui/hwui/DrawTextFunctor.h index 2e6e97634aec..8f999904a8ab 100644 --- a/libs/hwui/hwui/DrawTextFunctor.h +++ b/libs/hwui/hwui/DrawTextFunctor.h @@ -16,7 +16,9 @@ #include <SkFontMetrics.h> #include <SkRRect.h> +#include <com_android_graphics_hwui_flags.h> +#include "../utils/Color.h" #include "Canvas.h" #include "FeatureFlags.h" #include "MinikinUtils.h" @@ -27,6 +29,8 @@ #include "hwui/PaintFilter.h" #include "pipeline/skia/SkiaRecordingCanvas.h" +namespace flags = com::android::graphics::hwui::flags; + namespace android { static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness, @@ -73,8 +77,14 @@ public: if (CC_UNLIKELY(canvas->isHighContrastText() && paint.getAlpha() != 0)) { // high contrast draw path int color = paint.getColor(); - int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color); - bool darken = channelSum < (128 * 3); + bool darken; + if (flags::high_contrast_text_luminance()) { + uirenderer::Lab lab = uirenderer::sRGBToLab(color); + darken = lab.L <= 50; + } else { + int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color); + darken = channelSum < (128 * 3); + } // outline gDrawTextBlobMode = DrawTextBlobMode::HctOutline; diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h index 6a052dbb7cea..260547cda1c2 100644 --- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h +++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h @@ -90,11 +90,6 @@ protected: mOutput << mIdent << "drawTextBlob" << std::endl; } - void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, - const SkPaint*) override { - mOutput << mIdent << "drawImage" << std::endl; - } - void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&, const SkPaint*, SrcRectConstraint) override { mOutput << mIdent << "drawImageRect" << std::endl; diff --git a/libs/hwui/tests/common/CallCountingCanvas.h b/libs/hwui/tests/common/CallCountingCanvas.h index dc36a2e01815..df5f04f9904e 100644 --- a/libs/hwui/tests/common/CallCountingCanvas.h +++ b/libs/hwui/tests/common/CallCountingCanvas.h @@ -109,12 +109,6 @@ public: drawPoints++; } - int drawImageCount = 0; - void onDrawImage2(const SkImage* image, SkScalar dx, SkScalar dy, const SkSamplingOptions&, - const SkPaint* paint) override { - drawImageCount++; - } - int drawImageRectCount = 0; void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&, const SkPaint*, SkCanvas::SrcRectConstraint) override { diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp index 18c50472a7df..4ae76e2f1fd2 100644 --- a/libs/hwui/tests/unit/CanvasOpTests.cpp +++ b/libs/hwui/tests/unit/CanvasOpTests.cpp @@ -492,7 +492,7 @@ TEST(CanvasOp, simpleDrawImage) { CallCountingCanvas canvas; EXPECT_EQ(0, canvas.sumTotalDrawCalls()); rasterizeCanvasBuffer(buffer, &canvas); - EXPECT_EQ(1, canvas.drawImageCount); + EXPECT_EQ(1, canvas.drawImageRectCount); EXPECT_EQ(1, canvas.sumTotalDrawCalls()); } diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h index 96a0c6114682..8b95e0cd267d 100644 --- a/libs/hwui/tests/unit/FatalTestCanvas.h +++ b/libs/hwui/tests/unit/FatalTestCanvas.h @@ -69,10 +69,6 @@ public: void onDrawPath(const SkPath&, const SkPaint&) { ADD_FAILURE() << "onDrawPath not expected in this test"; } - void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, - const SkPaint*) { - ADD_FAILURE() << "onDrawImage not expected in this test"; - } void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&, const SkPaint*, SrcRectConstraint) { ADD_FAILURE() << "onDrawImageRect not expected in this test"; diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index 073a8357e574..ca540874833c 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -941,8 +941,9 @@ RENDERTHREAD_TEST(RenderNodeDrawable, simple) { void onDrawRect(const SkRect& rect, const SkPaint& paint) override { EXPECT_EQ(0, mDrawCounter++); } - void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, - const SkPaint*) override { + void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, + const SkSamplingOptions&, const SkPaint*, + SrcRectConstraint) override { EXPECT_EQ(1, mDrawCounter++); } }; diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 3ded540c3152..785e2869d15e 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -303,8 +303,9 @@ RENDERTHREAD_TEST(SkiaPipeline, clipped) { class ClippedTestCanvas : public SkCanvas { public: ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {} - void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, - const SkPaint*) override { + void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, + const SkSamplingOptions&, const SkPaint*, + SrcRectConstraint) override { EXPECT_EQ(0, mDrawCounter++); EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this)); EXPECT_TRUE(getTotalMatrix().isIdentity()); @@ -338,8 +339,9 @@ RENDERTHREAD_TEST(SkiaPipeline, clipped_rotated) { class ClippedTestCanvas : public SkCanvas { public: ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {} - void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, - const SkPaint*) override { + void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, + const SkSamplingOptions&, const SkPaint*, + SrcRectConstraint) override { EXPECT_EQ(0, mDrawCounter++); // Expect clip to be rotated. EXPECT_EQ(SkRect::MakeLTRB(CANVAS_HEIGHT - dirty.fTop - dirty.height(), dirty.fLeft, diff --git a/libs/hwui/utils/ForceDark.h b/libs/hwui/utils/ForceDark.h index 28538c4b7a7b..ecfe41f39ecb 100644 --- a/libs/hwui/utils/ForceDark.h +++ b/libs/hwui/utils/ForceDark.h @@ -17,6 +17,8 @@ #ifndef FORCEDARKUTILS_H #define FORCEDARKUTILS_H +#include <stdint.h> + namespace android { namespace uirenderer { @@ -26,9 +28,9 @@ namespace uirenderer { * This should stay in sync with the java @IntDef in * frameworks/base/graphics/java/android/graphics/ForceDarkType.java */ -enum class ForceDarkType : __uint8_t { NONE = 0, FORCE_DARK = 1, FORCE_INVERT_COLOR_DARK = 2 }; +enum class ForceDarkType : uint8_t { NONE = 0, FORCE_DARK = 1, FORCE_INVERT_COLOR_DARK = 2 }; } /* namespace uirenderer */ } /* namespace android */ -#endif // FORCEDARKUTILS_H
\ No newline at end of file +#endif // FORCEDARKUTILS_H diff --git a/location/java/android/location/flags/gnss.aconfig b/location/java/android/location/flags/gnss.aconfig index a8464d3f86ec..794a555e22cb 100644 --- a/location/java/android/location/flags/gnss.aconfig +++ b/location/java/android/location/flags/gnss.aconfig @@ -34,3 +34,10 @@ flag { description: "Flag for location validation" bug: "314328533" } + +flag { + name: "gnss_configuration_from_resource" + namespace: "location" + description: "Flag for GNSS configuration from resource" + bug: "317734846" +} diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING index 8f5f1f6a4794..4fbe9ee90c4c 100644 --- a/media/TEST_MAPPING +++ b/media/TEST_MAPPING @@ -48,9 +48,7 @@ {"exclude-annotation": "androidx.test.filters.FlakyTest"}, {"exclude-annotation": "org.junit.Ignore"} ] - } - ], - "postsubmit": [ + }, { "file_patterns": [ "[^/]*(LoudnessCodec)[^/]*\\.java" diff --git a/media/java/android/media/AudioHalVersionInfo.java b/media/java/android/media/AudioHalVersionInfo.java index 0f48abeb6882..25b14041c8fa 100644 --- a/media/java/android/media/AudioHalVersionInfo.java +++ b/media/java/android/media/AudioHalVersionInfo.java @@ -78,11 +78,10 @@ public final class AudioHalVersionInfo implements Parcelable, Comparable<AudioHa /** * List of all valid Audio HAL versions. This list need to be in sync with sAudioHALVersions - * defined in frameworks/av/media/libaudiohal/FactoryHalHidl.cpp. + * defined in frameworks/av/media/libaudiohal/FactoryHal.cpp. */ - // TODO: add AIDL_1_0 with sAudioHALVersions. public static final @NonNull List<AudioHalVersionInfo> VERSIONS = - List.of(HIDL_7_1, HIDL_7_0, HIDL_6_0, HIDL_5_0, HIDL_4_0); + List.of(AIDL_1_0, HIDL_7_1, HIDL_7_0, HIDL_6_0, HIDL_5_0, HIDL_4_0); private static final String TAG = "AudioHalVersionInfo"; private AudioHalVersion mHalVersion = new AudioHalVersion(); diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 46a0b9934376..0f6cbffef300 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -2499,14 +2499,12 @@ public class AudioSystem * </ul> */ public static int getPlatformType(Context context) { - if (((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)) - .isVoiceCapable()) { + if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { + return PLATFORM_AUTOMOTIVE; + } else if ((context.getSystemService(TelephonyManager.class)).isVoiceCapable()) { return PLATFORM_VOICE; } else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { return PLATFORM_TELEVISION; - } else if (context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_AUTOMOTIVE)) { - return PLATFORM_AUTOMOTIVE; } else { return PLATFORM_DEFAULT; } diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 5e235515c852..89792c7638cb 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -18,8 +18,8 @@ package android.media; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES; -import static com.android.media.flags.Flags.FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2; import static com.android.media.flags.Flags.FLAG_ENABLE_CROSS_USER_ROUTING_IN_MEDIA_ROUTER2; +import static com.android.media.flags.Flags.FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2; import android.Manifest; import android.annotation.CallbackExecutor; @@ -344,25 +344,13 @@ public final class MediaRouter2 { mImpl = new LocalMediaRouter2Impl(mContext.getPackageName()); mHandler = new Handler(Looper.getMainLooper()); - List<MediaRoute2Info> currentSystemRoutes = null; - try { - currentSystemRoutes = mMediaRouterService.getSystemRoutes(); - } catch (RemoteException ex) { - ex.rethrowFromSystemServer(); - } - - if (currentSystemRoutes == null || currentSystemRoutes.isEmpty()) { - throw new RuntimeException("Null or empty currentSystemRoutes. Something is wrong."); - } + loadSystemRoutes(); RoutingSessionInfo currentSystemSessionInfo = mImpl.getSystemSessionInfo(); if (currentSystemSessionInfo == null) { throw new RuntimeException("Null currentSystemSessionInfo. Something is wrong."); } - for (MediaRoute2Info route : currentSystemRoutes) { - mRoutes.put(route.getId(), route); - } mSystemController = new SystemRoutingController(currentSystemSessionInfo); } @@ -374,6 +362,8 @@ public final class MediaRouter2 { IMediaRouterService.Stub.asInterface( ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); + loadSystemRoutes(); + mSystemController = new SystemRoutingController( ProxyMediaRouter2Impl.getSystemSessionInfoImpl( @@ -381,6 +371,24 @@ public final class MediaRouter2 { mImpl = new ProxyMediaRouter2Impl(context, clientPackageName, user); } + @GuardedBy("mLock") + private void loadSystemRoutes() { + List<MediaRoute2Info> currentSystemRoutes = null; + try { + currentSystemRoutes = mMediaRouterService.getSystemRoutes(); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + + if (currentSystemRoutes == null || currentSystemRoutes.isEmpty()) { + throw new RuntimeException("Null or empty currentSystemRoutes. Something is wrong."); + } + + for (MediaRoute2Info route : currentSystemRoutes) { + mRoutes.put(route.getId(), route); + } + } + /** * Gets the client package name of the app which this media router controls. * diff --git a/media/tests/LoudnessCodecApiTest/src/com/android/loudnesscodecapitest/LoudnessCodecConfiguratorTest.java b/media/tests/LoudnessCodecApiTest/src/com/android/loudnesscodecapitest/LoudnessCodecConfiguratorTest.java index 3b15632d065d..ce1004c4c58c 100644 --- a/media/tests/LoudnessCodecApiTest/src/com/android/loudnesscodecapitest/LoudnessCodecConfiguratorTest.java +++ b/media/tests/LoudnessCodecApiTest/src/com/android/loudnesscodecapitest/LoudnessCodecConfiguratorTest.java @@ -95,12 +95,17 @@ public class LoudnessCodecConfiguratorTest { @RequiresFlagsEnabled(FLAG_LOUDNESS_CONFIGURATOR_API) public void setAudioTrack_callsAudioServiceStart() throws Exception { final AudioTrack track = createAudioTrack(); + final MediaCodec mediaCodec = createAndConfigureMediaCodec(); - mLcc.addMediaCodec(createAndConfigureMediaCodec()); - mLcc.setAudioTrack(track); + try { + mLcc.addMediaCodec(mediaCodec); + mLcc.setAudioTrack(track); - verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), - anyList()); + verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), + anyList()); + } finally { + mediaCodec.release(); + } } @Test @@ -108,10 +113,15 @@ public class LoudnessCodecConfiguratorTest { public void getLoudnessCodecParams_callsAudioServiceGetLoudness() throws Exception { when(mAudioService.getLoudnessParams(anyInt(), any())).thenReturn(new PersistableBundle()); final AudioTrack track = createAudioTrack(); + final MediaCodec mediaCodec = createAndConfigureMediaCodec(); - mLcc.getLoudnessCodecParams(track, createAndConfigureMediaCodec()); + try { + mLcc.getLoudnessCodecParams(track, mediaCodec); - verify(mAudioService).getLoudnessParams(eq(track.getPlayerIId()), any()); + verify(mAudioService).getLoudnessParams(eq(track.getPlayerIId()), any()); + } finally { + mediaCodec.release(); + } } @Test @@ -120,10 +130,14 @@ public class LoudnessCodecConfiguratorTest { final AudioTrack track = createAudioTrack(); final MediaCodec mediaCodec = createAndConfigureMediaCodec(); - mLcc.addMediaCodec(mediaCodec); - mLcc.setAudioTrack(track); + try { + mLcc.addMediaCodec(mediaCodec); + mLcc.setAudioTrack(track); - verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), anyList()); + verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), anyList()); + } finally { + mediaCodec.release(); + } } @Test @@ -132,24 +146,33 @@ public class LoudnessCodecConfiguratorTest { final AudioTrack track = createAudioTrack(); final MediaCodec mediaCodec = createAndConfigureMediaCodec(); - mLcc.addMediaCodec(mediaCodec); - mLcc.setAudioTrack(track); - mLcc.setAudioTrack(track); + try { + mLcc.addMediaCodec(mediaCodec); + mLcc.setAudioTrack(track); + mLcc.setAudioTrack(track); - verify(mAudioService, times(1)).startLoudnessCodecUpdates(eq(track.getPlayerIId()), - anyList()); + verify(mAudioService, times(1)).startLoudnessCodecUpdates(eq(track.getPlayerIId()), + anyList()); + } finally { + mediaCodec.release(); + } } @Test @RequiresFlagsEnabled(FLAG_LOUDNESS_CONFIGURATOR_API) public void setTrackNull_stopCodecUpdates() throws Exception { final AudioTrack track = createAudioTrack(); + final MediaCodec mediaCodec = createAndConfigureMediaCodec(); - mLcc.addMediaCodec(createAndConfigureMediaCodec()); - mLcc.setAudioTrack(track); + try { + mLcc.addMediaCodec(mediaCodec); + mLcc.setAudioTrack(track); - mLcc.setAudioTrack(null); // stops updates - verify(mAudioService).stopLoudnessCodecUpdates(eq(track.getPlayerIId())); + mLcc.setAudioTrack(null); // stops updates + verify(mAudioService).stopLoudnessCodecUpdates(eq(track.getPlayerIId())); + } finally { + mediaCodec.release(); + } } @Test @@ -157,27 +180,37 @@ public class LoudnessCodecConfiguratorTest { public void addMediaCodecTwice_triggersIAE() throws Exception { final MediaCodec mediaCodec = createAndConfigureMediaCodec(); - mLcc.addMediaCodec(mediaCodec); + try { + mLcc.addMediaCodec(mediaCodec); - assertThrows(IllegalArgumentException.class, () -> mLcc.addMediaCodec(mediaCodec)); + assertThrows(IllegalArgumentException.class, () -> mLcc.addMediaCodec(mediaCodec)); + } finally { + mediaCodec.release(); + } } @Test @RequiresFlagsEnabled(FLAG_LOUDNESS_CONFIGURATOR_API) public void setClearTrack_removeAllAudioServicePiidCodecs() throws Exception { final ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class); - final AudioTrack track = createAudioTrack(); - - mLcc.addMediaCodec(createAndConfigureMediaCodec()); - mLcc.setAudioTrack(track); - verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), - argument.capture()); - assertEquals(argument.getValue().size(), 1); - - mLcc.addMediaCodec(createAndConfigureMediaCodec()); - mLcc.setAudioTrack(null); - verify(mAudioService).stopLoudnessCodecUpdates(eq(track.getPlayerIId())); + final MediaCodec mediaCodec1 = createAndConfigureMediaCodec(); + final MediaCodec mediaCodec2 = createAndConfigureMediaCodec(); + + try { + mLcc.addMediaCodec(mediaCodec1); + mLcc.setAudioTrack(track); + verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), + argument.capture()); + assertEquals(argument.getValue().size(), 1); + + mLcc.addMediaCodec(mediaCodec2); + mLcc.setAudioTrack(null); + verify(mAudioService).stopLoudnessCodecUpdates(eq(track.getPlayerIId())); + } finally { + mediaCodec1.release(); + mediaCodec2.release(); + } } @Test @@ -186,24 +219,35 @@ public class LoudnessCodecConfiguratorTest { final AudioTrack track = createAudioTrack(); final MediaCodec mediaCodec = createAndConfigureMediaCodec(); - mLcc.addMediaCodec(mediaCodec); - mLcc.setAudioTrack(track); - mLcc.removeMediaCodec(mediaCodec); + try { + mLcc.addMediaCodec(mediaCodec); + mLcc.setAudioTrack(track); + mLcc.removeMediaCodec(mediaCodec); - verify(mAudioService).removeLoudnessCodecInfo(eq(track.getPlayerIId()), any()); + verify(mAudioService).removeLoudnessCodecInfo(eq(track.getPlayerIId()), any()); + } finally { + mediaCodec.release(); + } } @Test @RequiresFlagsEnabled(FLAG_LOUDNESS_CONFIGURATOR_API) public void addMediaCodecAfterSetTrack_callsAudioServiceAdd() throws Exception { final AudioTrack track = createAudioTrack(); - - mLcc.addMediaCodec(createAndConfigureMediaCodec()); - mLcc.setAudioTrack(track); - verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), anyList()); - - mLcc.addMediaCodec(createAndConfigureMediaCodec()); - verify(mAudioService).addLoudnessCodecInfo(eq(track.getPlayerIId()), anyInt(), any()); + final MediaCodec mediaCodec1 = createAndConfigureMediaCodec(); + final MediaCodec mediaCodec2 = createAndConfigureMediaCodec(); + + try { + mLcc.addMediaCodec(mediaCodec1); + mLcc.setAudioTrack(track); + verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), anyList()); + + mLcc.addMediaCodec(mediaCodec2); + verify(mAudioService).addLoudnessCodecInfo(eq(track.getPlayerIId()), anyInt(), any()); + } finally { + mediaCodec1.release(); + mediaCodec2.release(); + } } @Test @@ -212,25 +256,36 @@ public class LoudnessCodecConfiguratorTest { final AudioTrack track = createAudioTrack(); final MediaCodec mediaCodec = createAndConfigureMediaCodec(); - mLcc.addMediaCodec(mediaCodec); - mLcc.setAudioTrack(track); - verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), anyList()); + try { + mLcc.addMediaCodec(mediaCodec); + mLcc.setAudioTrack(track); + verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), anyList()); - mLcc.removeMediaCodec(mediaCodec); - verify(mAudioService).removeLoudnessCodecInfo(eq(track.getPlayerIId()), any()); + mLcc.removeMediaCodec(mediaCodec); + verify(mAudioService).removeLoudnessCodecInfo(eq(track.getPlayerIId()), any()); + } finally { + mediaCodec.release(); + } } @Test @RequiresFlagsEnabled(FLAG_LOUDNESS_CONFIGURATOR_API) public void removeWrongMediaCodecAfterSetTrack_triggersIAE() throws Exception { final AudioTrack track = createAudioTrack(); - - mLcc.addMediaCodec(createAndConfigureMediaCodec()); - mLcc.setAudioTrack(track); - verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), anyList()); - - assertThrows(IllegalArgumentException.class, - () -> mLcc.removeMediaCodec(createAndConfigureMediaCodec())); + final MediaCodec mediaCodec1 = createAndConfigureMediaCodec(); + final MediaCodec mediaCodec2 = createAndConfigureMediaCodec(); + + try { + mLcc.addMediaCodec(mediaCodec1); + mLcc.setAudioTrack(track); + verify(mAudioService).startLoudnessCodecUpdates(eq(track.getPlayerIId()), anyList()); + + assertThrows(IllegalArgumentException.class, + () -> mLcc.removeMediaCodec(mediaCodec2)); + } finally { + mediaCodec1.release(); + mediaCodec2.release(); + } } private static AudioTrack createAudioTrack() { @@ -250,19 +305,21 @@ public class LoudnessCodecConfiguratorTest { MediaExtractor extractor; extractor = new MediaExtractor(); - extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(), + try { + extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(), testFd.getLength()); - testFd.close(); - - assertEquals("wrong number of tracks", 1, extractor.getTrackCount()); - MediaFormat format = extractor.getTrackFormat(0); - String mime = format.getString(MediaFormat.KEY_MIME); - assertTrue("not an audio file", mime.startsWith(TEST_MEDIA_AUDIO_CODEC_PREFIX)); - final MediaCodec mediaCodec = MediaCodec.createDecoderByType(mime); - - Log.v(TAG, "configuring with " + format); - mediaCodec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */); - - return mediaCodec; + assertEquals("wrong number of tracks", 1, extractor.getTrackCount()); + MediaFormat format = extractor.getTrackFormat(0); + String mime = format.getString(MediaFormat.KEY_MIME); + assertTrue("not an audio file", mime.startsWith(TEST_MEDIA_AUDIO_CODEC_PREFIX)); + final MediaCodec mediaCodec = MediaCodec.createDecoderByType(mime); + + Log.v(TAG, "configuring with " + format); + mediaCodec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */); + return mediaCodec; + } finally { + testFd.close(); + extractor.release(); + } } } diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt index e0df7945ab0e..193728a1c780 100644 --- a/native/graphics/jni/libjnigraphics.map.txt +++ b/native/graphics/jni/libjnigraphics.map.txt @@ -18,21 +18,21 @@ LIBJNIGRAPHICS { AImageDecoder_getRepeatCount; # introduced=31 AImageDecoder_advanceFrame; # introduced=31 AImageDecoder_rewind; # introduced=31 - AImageDecoder_getFrameInfo; # introduced = 31 - AImageDecoder_setInternallyHandleDisposePrevious; # introduced = 31 + AImageDecoder_getFrameInfo; # introduced=31 + AImageDecoder_setInternallyHandleDisposePrevious; # introduced=31 AImageDecoderHeaderInfo_getWidth; # introduced=30 AImageDecoderHeaderInfo_getHeight; # introduced=30 AImageDecoderHeaderInfo_getMimeType; # introduced=30 AImageDecoderHeaderInfo_getAlphaFlags; # introduced=30 AImageDecoderHeaderInfo_getAndroidBitmapFormat; # introduced=30 AImageDecoderHeaderInfo_getDataSpace; # introduced=30 - AImageDecoderFrameInfo_create; # introduced = 31 - AImageDecoderFrameInfo_delete; # introduced = 31 - AImageDecoderFrameInfo_getDuration; # introduced = 31 - AImageDecoderFrameInfo_getFrameRect; # introduced = 31 - AImageDecoderFrameInfo_hasAlphaWithinBounds; # introduced = 31 - AImageDecoderFrameInfo_getDisposeOp; # introduced = 31 - AImageDecoderFrameInfo_getBlendOp; # introduced = 31 + AImageDecoderFrameInfo_create; # introduced=31 + AImageDecoderFrameInfo_delete; # introduced=31 + AImageDecoderFrameInfo_getDuration; # introduced=31 + AImageDecoderFrameInfo_getFrameRect; # introduced=31 + AImageDecoderFrameInfo_hasAlphaWithinBounds; # introduced=31 + AImageDecoderFrameInfo_getDisposeOp; # introduced=31 + AImageDecoderFrameInfo_getBlendOp; # introduced=31 AndroidBitmap_getInfo; AndroidBitmap_getDataSpace; AndroidBitmap_lockPixels; diff --git a/packages/CarrierDefaultApp/res/values-fr/strings.xml b/packages/CarrierDefaultApp/res/values-fr/strings.xml index 4bc03ffab291..9e859698e2d8 100644 --- a/packages/CarrierDefaultApp/res/values-fr/strings.xml +++ b/packages/CarrierDefaultApp/res/values-fr/strings.xml @@ -16,7 +16,7 @@ <string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans le navigateur"</string> <string name="performance_boost_notification_channel" msgid="3475440855635538592">"Boost de performances"</string> <string name="performance_boost_notification_title" msgid="3126203390685781861">"Options 5G de votre opérateur"</string> - <string name="performance_boost_notification_detail" msgid="216569851036236346">"Accédez au site Web de %s pour consulter les options pour l\'expérience de votre appli"</string> + <string name="performance_boost_notification_detail" msgid="216569851036236346">"Accédez au site Web de %s pour consulter les options de votre appli"</string> <string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Pas maintenant"</string> <string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gérer"</string> <string name="slice_purchase_app_label" msgid="7170191659233241166">"Achetez un boost de performances."</string> diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml index 285d2d1f94e4..1f39509d4aad 100644 --- a/packages/CompanionDeviceManager/res/values-af/strings.xml +++ b/packages/CompanionDeviceManager/res/values-af/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Toestelle in die omtrek"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Verander media-uitset"</string> <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Kennisgewings"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Stroming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Maak en bestuur foonoproepe"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Lees en skryf foonoproeprekord neer"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Stuur en bekyk SMS-boodskappe"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Verkry toegang tot jou kontakte"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Verkry toegang tot jou kalender"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Neem oudio op"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Vind, koppel aan en bepaal die relatiewe posisie van toestelle in die omtrek"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Lees alle kennisgewings, insluitend inligting soos kontakte, boodskappe en foto’s"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Lees alle kennisgewings, insluitend inligting soos kontakte, boodskappe en foto’s<br/>• Stuur kennisgewings<br/><br/>Jy kan hierdie app se vermoë om kennisgewings te lees en te stuur, enige tyd in Instellings bestuur > Kennisgewings."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml index 996d2ea42c36..007173cb8fad 100644 --- a/packages/CompanionDeviceManager/res/values-am/strings.xml +++ b/packages/CompanionDeviceManager/res/values-am/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"በአቅራቢያ ያሉ መሣሪያዎች"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"የሚዲያ ውጤትን ይቀይሩ"</string> <string name="permission_storage" msgid="6831099350839392343">"ፎቶዎች እና ሚዲያ"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"ማሳወቂያዎች"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"መተግበሪያዎች"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"በዥረት መልቀቅ"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"የስልክ ጥሪዎች ያድርጉ እና ያስተዳድሩ"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"የስልክ ጥሪ ምዝግብ ማስታወሻን ያንብቡ እና ይጻፉ"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"የኤስኤምኤስ መልዕክቶችን ይላኩና ይመልከቱ"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"የእርስዎን እውቂያዎች ይድረሱባቸው"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"የእርስዎን ቀን መቁጠሪያ ይድረሱበት"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ኦዲዮ ቅረጽ"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"በአቅራቢያ ያሉ መሣሪያዎችን ማግኘት፣ ከእነሱ ጋር መገናኘት እና አንጻራዊ ቦታቸውን መወሰን"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"እንደ እውቂያዎች፣ መልዕክቶች እና ፎቶዎች ያሉ መረጃዎችን ጨምሮ ሁሉንም ማሳወቂያዎች ማንበብ"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• እንደ እውቂያዎች፣ መልዕክቶች እና ፎቶዎች ያሉ መረጃዎችን ጨምሮ ሁሉንም ማሳወቂያዎች ያንብቡ<br/>• ማሳወቂያዎችን መላክ<br/><br/>የዚህን መተግበሪያ ማሳወቂያዎችን የማንበብ እና የመላክ ችሎታን በቅንብሮች > ማሳወቂያዎች ውስጥ ማስተዳደር ይችላሉ።"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml index 58cf9267f227..5b893b0e1b37 100644 --- a/packages/CompanionDeviceManager/res/values-ar/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml @@ -54,8 +54,7 @@ <string name="permission_microphone" msgid="2152206421428732949">"الميكروفون"</string> <string name="permission_call_logs" msgid="5546761417694586041">"سجلّ المكالمات"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"الأجهزة المجاورة"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"تغيير جهاز إخراج الوسائط"</string> <string name="permission_storage" msgid="6831099350839392343">"الصور والوسائط"</string> <!-- no translation found for permission_notifications (4099418516590632909) --> <skip /> @@ -82,8 +81,7 @@ <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"يتيح لك هذا الإذن الاطّلاع على مجموعة من الأجهزة المتاحة وتحديد الجهاز المسموح له بتشغيل الصوت أو الفيديو أو بثّهما من التطبيقات الأخرى."</string> <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 fddc24c30daf..623b2121e39a 100644 --- a/packages/CompanionDeviceManager/res/values-as/strings.xml +++ b/packages/CompanionDeviceManager/res/values-as/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"নিকটৱৰ্তী ডিভাইচ"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"মিডিয়া আউটপুট সলনি কৰক"</string> <string name="permission_storage" msgid="6831099350839392343">"ফট’ আৰু মিডিয়া"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"জাননী"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"এপ্"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ষ্ট্ৰীম কৰি থকা হৈছে"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ফ’ন কল কৰক আৰু সেয়া পৰিচলনা কৰক"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ফ’নৰ কল লগ পঢ়ক আৰু লিখক"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"এছএমএছ বার্তাবোৰ প্ৰেৰণ কৰক আৰু চাওক"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"আপোনাৰ সম্পৰ্কসূচী এক্সেছ কৰক"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"আপোনাৰ কেলেণ্ডাৰ এক্সেছ কৰক"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"অডিঅ’ ৰেকৰ্ড কৰক"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"নিকটৱৰ্তী ডিভাইচসমূহ বিচাৰক, সেইসমূহৰ সৈতে সংযোগ কৰক আৰু সেইসমূহৰ প্ৰাসংগিক অৱস্থান নিৰ্ধাৰণ কৰক"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"সম্পৰ্কসূচী, বাৰ্তা আৰু ফট’ৰ দৰে তথ্যকে ধৰি আটাইবোৰ জাননী পঢ়ক"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• সম্পৰ্কসূচী, বাৰ্তা আৰু ফট’ৰ দৰে তথ্যকে ধৰি আটাইবোৰ জাননী পঢ়ক<br/>• জাননী পঠিয়াওক<br/><br/>আপুনি যিকোনো সময়তে ছেটিং > জাননীলৈ গৈ এই এপ্টোৰ জাননী পঢ়া আৰু পঠিওৱাৰ সক্ষমতা পৰিচালনা কৰিব পাৰে।"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml index a3ed66946f98..65f3a62cdb57 100644 --- a/packages/CompanionDeviceManager/res/values-az/strings.xml +++ b/packages/CompanionDeviceManager/res/values-az/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Yaxınlıqdakı cihazlar"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Media çıxışını dəyişin"</string> <string name="permission_storage" msgid="6831099350839392343">"Foto və media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Bildirişlər"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Tətbiqlər"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Yayım"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Telefon zənglərinin edilməsi və idarəsi"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Telefon zəng siyahısının oxunması və yazılması"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS mesajlarının göndərilməsi və onlara baxmaq"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Kontaktlara giriş"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Təqvimə giriş"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Audionun qeydə alınması"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Yaxınlıqdakı cihazların tapılması, onlara qoşulmaq və nisbi mövqelərinin təyin edilməsi"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Kontakt, mesaj və foto kimi məlumatlar daxil olmaqla bütün bildirişlərin oxunması"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Kontakt, mesaj və foto kimi məlumatlar daxil olmaqla bütün bildirişlərin oxunması<br/>• Bildirişlərin göndərilməsi<br/><br/>Bu tətbiqin bildirişləri oxumaq və göndərmək imkanını Ayarlar > Bildirişlər bölməsində idarə edə bilərsiniz."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml index 071d93e6ce6c..314d9ffe43b4 100644 --- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Uređaji u blizini"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Promena medijskog izlaza"</string> <string name="permission_storage" msgid="6831099350839392343">"Slike i mediji"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Obaveštenja"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Striming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Upućivanje telefonskih poziva i upravljanje njima"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Čitanje i pisanje evidencije poziva na telefonu"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Slanje i pregled SMS poruka"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Pristup kontaktima"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Pristup kalendaru"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Snimanje zvuka"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Pronalaženje uređaja u blizini, utvrđivanje njihove relativne pozicije i povezivanje sa njima"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Čitanje svih obaveštenja, uključujući informacija poput kontakata, poruka i slika"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Čitanje svih obaveštenja, uključujući informacija poput kontakata, poruka i slika<br/>• Slanje obaveštenja<br/><br/>Da biste upravljali dozvolama ove aplikacije za čitanje i slanje obaveštenja, idite u Podešavanja > Obaveštenja."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml index d99b815a9fb5..fc17899768c9 100644 --- a/packages/CompanionDeviceManager/res/values-be/strings.xml +++ b/packages/CompanionDeviceManager/res/values-be/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Прылады паблізу"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Змяніць прыладу вываду медыя"</string> <string name="permission_storage" msgid="6831099350839392343">"Фота і медыяфайлы"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Апавяшчэнні"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Праграмы"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Перадача плынню"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Ажыццяўленне тэлефонных выклікаў і кіраванне імі"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Чытанне і запіс журнала тэлефонных выклікаў"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Адпраўка SMS-паведамленняў і іх прагляд"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Доступ да вашых кантактаў"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Доступ да вашага календара"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Запіс гуку"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Пошук прылад паблізу, падключэнне да іх і вызначэнне іх адноснага месцазнаходжання"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Чытанне ўсіх апавяшчэнняў, у тым ліку такой інфармацыі, як кантакты, паведамленні і фота"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Чытанне ўсіх апавяшчэнняў, у тым ліку такой інфармацыі, як кантакты, паведамленні і фота.<br/>• Адпраўка апавяшчэнняў.<br/><br/>Дазволы гэтай праграмы на чытанне і адпраўку апавяшчэнняў можна змяніць у любы час, выбраўшы пункт меню \"Налады > Апавяшчэнні\"."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml index 3840698ec58d..c9f85dd2ec6b 100644 --- a/packages/CompanionDeviceManager/res/values-bg/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Устройства в близост"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Промяна на мултимедийния изход"</string> <string name="permission_storage" msgid="6831099350839392343">"Снимки и мултимедия"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Известия"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Приложения"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Поточно предаване"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Извършване и управление на телефонни обаждания"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Четене и запис на списъка с обажданията"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Изпращане и преглед на SMS съобщения"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Достъп до контактите ви"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Достъп до календара ви"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Записване на звук"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Намиране и свързване с устройства в близост, както и определяне на относителната им позиция"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Четене на всички известия, включително различна информация, като например контакти, съобщения и снимки"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Четене на всички известия, включително различна информация, като например контакти, съобщения и снимки.<br/>• Изпращане на известия.<br/><br/>Можете да управлявате способността на това приложение да чете и изпраща известия по всяко време в „Настройки“ > „Известия“."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml index 38521d6a9cd2..c3ceda07b211 100644 --- a/packages/CompanionDeviceManager/res/values-bn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml @@ -54,36 +54,24 @@ <string name="permission_microphone" msgid="2152206421428732949">"মাইক্রোফোন"</string> <string name="permission_call_logs" msgid="5546761417694586041">"কল লগ"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"আশেপাশের ডিভাইস"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"মিডিয়া আউটপুট পরিবর্তন করুন"</string> <string name="permission_storage" msgid="6831099350839392343">"ফটো ও মিডিয়া"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"বিজ্ঞপ্তি"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"অ্যাপ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"স্ট্রিমিং"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ফোন কল করুন এবং ম্যানেজ করুন"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ফোন কল লগ দেখে তাতে পরিবর্তন করার অনুমতি দিন"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"এসএমএস মেসেজ দেখুন ও পাঠান"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"আপনার পরিচিতি অ্যাক্সেস করুন"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"আপনার ক্যালেন্ডার অ্যাক্সেস করার অনুমতি দিন"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"অডিও রেকর্ড করুন"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"আশেপাশের ডিভাইস খুঁজুন, তার সাথে কানেক্ট করুন এবং তার আপেক্ষিক অবস্থান নির্ধারণ করুন"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"পরিচিতি, মেসেজ এবং ফটোর মতো তথ্য সহ সমস্ত বিজ্ঞপ্তি পড়ুন"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• পরিচিতি, মেসেজ এবং ফটোর মতো তথ্য সহ সমস্ত বিজ্ঞপ্তি পড়ুন<br/>• বিজ্ঞপ্তি পাঠান<br/><br/>আপনি সেটিংস > বিজ্ঞপ্তি থেকে এই অ্যাপটির বিজ্ঞপ্তি পড়ার এবং পাঠানোর ক্ষমতা ম্যানেজ করতে পারবেন।"</string> <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"উপলভ্য থাকা ডিভাইসের তালিকা অ্যাক্সেস করুন এবং কোন ডিভাইস অন্যান্য অ্যাপ থেকে অডিও বা ভিডিও স্ট্রিম অথবা কাস্ট করতে পারে তা কন্ট্রোল করুন"</string> <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 6b03d24a9081..259a06a245d7 100644 --- a/packages/CompanionDeviceManager/res/values-bs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Uređaji u blizini"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Promijeni izlaz med. sadržaja"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Obavještenja"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Prijenos"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Pozivanje i upravljanje telefonskim pozivima"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Čitanje i pisanje zapisnika telefonskih poziva"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Slanje i pregledanje SMS poruka"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Pristup vašim kontaktima"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Pristup vašem kalendaru"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Snimanje zvuka"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Pronalaženje uređaja u blizini, povezivanje s njima i određivanje njihovog relativnog položaja"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Čitanje svih obavještenja, uključujući informacije poput kontakata, poruka i fotografija"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• čitanje svih obavještenja, uključujući informacije poput kontakata, poruka i fotografija<br/>• slanje obavještenja<br/><br/>Da upravljate mogućnošću ove aplikacije da čita i šalje obavještenja, idite u Postavke > Obavještenja."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml index dcafb07c9da8..62fe858559b0 100644 --- a/packages/CompanionDeviceManager/res/values-ca/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositius propers"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Canvia la sortida multimèdia"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos i contingut multimèdia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notificacions"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplicacions"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Reproducció en línia"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Fer i gestionar trucades telefòniques"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Llegir i escriure el registre de trucades del telèfon"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Enviar i llegir missatges SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Accedir als contactes"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Accedir al calendari"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Gravar àudio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Determinar la posició relativa dels dispositius propers, trobar-los i connectar-s\'hi"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Llegir totes les notificacions, inclosa informació com ara els contactes, els missatges i les fotos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Llegir totes les notificacions, inclosa informació com ara els contactes, els missatges i les fotos.<br/>• Enviar notificacions.<br/><br/>A Configuració > Notificacions, pots gestionar en qualsevol moment els permisos de l\'aplicació per llegir i enviar notificacions."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml index 98412c815143..76c0a4a774e7 100644 --- a/packages/CompanionDeviceManager/res/values-cs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Zařízení v okolí"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Změna mediálního výstupu"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotky a média"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Oznámení"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikace"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streamování"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Uskutečňování a správa telefonních hovorů"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Čtení seznamu hovorů a zapisování do něj"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Odesílání a zobrazování zpráv SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Přístup ke kontaktům"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Přístup ke kalendáři"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Nahrávání zvuku"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Vyhledávání zařízení v okolí, připojování se k nim a zjišťování jejich relativní polohy"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Čtení veškerých oznámení včetně informací, jako jsou kontakty, zprávy a fotky"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Čtení veškerých oznámení, včetně informací, jako jsou kontakty, zprávy a fotky<br/>• Odesílání oznámení<br/><br/>Oprávnění této aplikace číst a odesílat oznámení můžete kdykoli změnit v Nastavení > Oznámení."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml index 86be312dc8f7..f765c83b28ff 100644 --- a/packages/CompanionDeviceManager/res/values-da/strings.xml +++ b/packages/CompanionDeviceManager/res/values-da/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Enheder i nærheden"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Skift medieoutput"</string> <string name="permission_storage" msgid="6831099350839392343">"Billeder og medier"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notifikationer"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Foretage og administrere telefonopkald"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Læse og redigere opkaldshistorik"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Sende og se sms-beskeder"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Få adgang til dine kontakter"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Få adgang til din kalender"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Optage lyd"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Finde, oprette forbindelse til og fastslå den omtrentlige lokation af enheder i nærheden"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Læse alle notifikationer, herunder oplysninger som f.eks. kontakter, beskeder og billeder"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Læse alle notifikationer, herunder oplysninger som f.eks. kontakter, beskeder og billeder<br/>• Sende notifikationer<br/><br/>Du kan til enhver tid administrere appens mulighed for at læse og sende notifikationer under Indstillinger > Notifikationer."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml index 1bc2fed65de2..e21e8cddbe0c 100644 --- a/packages/CompanionDeviceManager/res/values-de/strings.xml +++ b/packages/CompanionDeviceManager/res/values-de/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Geräte in der Nähe"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Medienausgabe ändern"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos und Medien"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Benachrichtigungen"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Anrufe starten und verwalten"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Auf die Anrufliste zugreifen und sie bearbeiten"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS senden und ansehen"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Auf deine Kontakte zugreifen"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Auf deinen Kalender zugreifen"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Audio aufnehmen"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Geräte in der Nähe finden, eine Verbindung zu ihnen herstellen und ihren relativen Standort ermitteln"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Alle Benachrichtigungen sehen, einschließlich Informationen wie Kontakten, Nachrichten und Fotos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Alle Benachrichtigungen sehen, einschließlich Informationen wie Kontakte, Nachrichten und Fotos<br/>• Benachrichtigungen senden<br/><br/>Du kannst die Berechtigungen dieser App zum Sehen und Senden von Benachrichtigungen jederzeit unter „Einstellungen > Benachrichtigungen“ ändern."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml index c8d6904ad049..a95d06351427 100644 --- a/packages/CompanionDeviceManager/res/values-el/strings.xml +++ b/packages/CompanionDeviceManager/res/values-el/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Συσκευές σε κοντινή απόσταση"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Αλλαγή εξόδου μέσων"</string> <string name="permission_storage" msgid="6831099350839392343">"Φωτογραφίες και μέσα"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Ειδοποιήσεις"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Εφαρμογές"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Ροή"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Πραγματοποίηση και διαχείριση τηλεφωνικών κλήσεων"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Ανάγνωση και εγγραφή αρχείου καταγραφής τηλεφωνικών κλήσεων"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Αποστολή και προβολή μηνυμάτων SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Πρόσβαση στις επαφές σας"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Πρόσβαση στο ημερολόγιό σας"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Ηχογράφηση"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Εύρεση, σύνδεση και προσδιορισμός της σχετικής τοποθεσίας συσκευών σε κοντινή απόσταση"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Ανάγνωση όλων των ειδοποιήσεων, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Ανάγνωση όλων των ειδοποιήσεων, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες<br/>• Αποστολή ειδοποιήσεων<br/><br/>Μπορείτε να διαχειριστείτε τη δυνατότητα της εφαρμογής να διαβάζει και να στέλνει ειδοποιήσεις οποιαδήποτε στιγμή στις Ρυθμίσεις > Ειδοποιήσεις."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml index e42ee5efb33f..75cd49ca1237 100644 --- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos cercanos"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Cambia la salida multimedia"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos y contenido multimedia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notificaciones"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Transmisión"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Hacer y administrar llamadas telefónicas"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Leer y escribir el registro de llamadas telefónicas"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Enviar y ver mensajes SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Acceder a tus contactos"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Acceder al calendario"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Grabar audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Encontrar dispositivos cercanos, conectarse a ellos y determinar su posición relativa"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Leer todas las notificaciones, incluso con información como contactos, mensajes y fotos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Leer todas las notificaciones, incluso con información como contactos, mensajes y fotos<br/>• Enviar notificaciones<br/><br/>Puedes administrar la capacidad de esta app para leer y enviar notificaciones en cualquier momento en Configuración > Notificaciones."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml index 40b0a643dd77..ba6045bdba67 100644 --- a/packages/CompanionDeviceManager/res/values-es/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos cercanos"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Cambiar salida multimedia"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos y elementos multimedia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notificaciones"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplicaciones"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Emitir"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Hacer y gestionar llamadas telefónicas"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Leer y escribir en el registro de llamadas del teléfono"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Enviar y ver mensajes SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Acceder a tus contactos"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Acceder a tu calendario"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Grabar audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Buscar, conectarse y determinar la posición relativa de dispositivos cercanos"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Leer todas las notificaciones, incluida información como contactos, mensajes y fotos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Leer todas las notificaciones, incluida información como contactos, mensajes y fotos<br/>• Enviar notificaciones<br/><br/>Puedes gestionar los permisos de esta aplicación para leer y enviar notificaciones cuando quieras en Ajustes > Notificaciones."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml index 8a436b32d6e5..dc8d9920030b 100644 --- a/packages/CompanionDeviceManager/res/values-et/strings.xml +++ b/packages/CompanionDeviceManager/res/values-et/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Läheduses olevad seadmed"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Muutke meediaväljundit"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotod ja meedia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Märguanded"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Rakendused"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Voogesitus"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Helistamine ja telefonikõnede haldamine"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Telefoni kõnelogi lugemine ja kirjutamine"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS-sõnumite saatmine ja vaatamine"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Juurdepääs kontaktidele"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Juurdepääs kalendrile"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Heli salvestamine"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Läheduses olevate seadmete leidmine, nendega ühenduse loomine ja nende suhtelise asendi määramine"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Kõikide märguannete, sh sellise teabe nagu kontaktid, sõnumid ja fotod lugemine"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Kõikide märguannete, sh sellise teabe nagu kontaktid, sõnumid ja fotod lugemine<br/>• Märguannete saatmine<br/><br/>Saate selle rakenduse võimalusi märguannete lugemiseks ja saatmiseks igal ajal hallata jaotises Seaded > Märguanded."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml index 38f05122965b..8cd4fdefad97 100644 --- a/packages/CompanionDeviceManager/res/values-eu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Inguruko gailuak"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Aldatu multimedia-irteera"</string> <string name="permission_storage" msgid="6831099350839392343">"Argazkiak eta multimedia-edukia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Jakinarazpenak"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikazioak"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Igortzea"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Telefono-deiak egin eta kudeatu"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Telefonoko deien erregistroa irakurri eta bertan idatzi"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS mezuak bidali eta ikusi"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Kontaktuak atzitu"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Egutegia atzitu"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Audioa grabatu"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Inguruko gailuak aurkitu, haietara konektatu eta haien posizio erlatiboa zehaztu"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Jakinarazpen guztiak irakurri; besteak beste, kontaktuak, mezuak, argazkiak eta antzeko informazioa"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Jakinarazpen guztiak irakurri; besteak beste, kontaktuak, mezuak, argazkiak eta antzeko informazioa.<br/>• Jakinarazpenak bidali.<br/><br/>Aplikazioak jakinarazpenak irakurri eta bidaltzeko dituen baimenak kudeatzeko, joan Ezarpenak > Jakinarazpenak atalera."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml index 5d0ad19f78a3..83628cb4a360 100644 --- a/packages/CompanionDeviceManager/res/values-fa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"دستگاههای اطراف"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"تغییر دادن خروجی رسانه"</string> <string name="permission_storage" msgid="6831099350839392343">"عکسها و رسانهها"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"اعلانها"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"برنامهها"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"جاریسازی"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"برقراری و مدیریت تماسهای تلفنی"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"خواندن و نوشتن گزارش تماس تلفنی"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"ارسال و مشاهده پیامکها"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"دسترسی به مخاطبین"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"دسترسی به تقویم"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ضبط کردن صدا"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"پیدا کردن، تعیین موقعیت نسبی، و متصل شدن به دستگاههای اطراف"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"خواندن همه اعلانها، شامل اطلاعاتی مثل مخاطبین، پیامها، و عکسها"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• خواندن همه اعلانها، شامل اطلاعاتی مثل مخاطبین، پیامها، و عکسها<br/>• ارسال اعلان<br/><br/>هرزمان بخواهید میتوانید این توانایی برنامه برای خواندن و ارسال اعلان را در «تنظیمات > اعلانها» مدیریت کنید."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml index b40de5fac130..86e79041357b 100644 --- a/packages/CompanionDeviceManager/res/values-fi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Lähellä olevat laitteet"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Median ulostulon muuttaminen"</string> <string name="permission_storage" msgid="6831099350839392343">"Kuvat ja media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Ilmoitukset"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Sovellukset"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Striimaus"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"soittaa ja hallinnoida puheluita"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"lukea puhelulokia ja kirjoittaa siihen"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"lähettää ja lukea tekstiviestejä"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"käyttää yhteystietoja"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"käyttää kalenteria"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"tallentaa audiota"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"löytää lähellä olevia laitteita, muodostaa niihin yhteyden ja määrittää niiden suhteellisen sijainnin"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"lukea kaikkia ilmoituksia, esim. yhteystietoihin, viesteihin ja kuviin liittyviä tietoja"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• lukea kaikkia ilmoituksia, esim. yhteystietoihin, viesteihin ja kuviin liittyviä tietoja<br/>• lähettää ilmoituksia.<br/><br/>Voit milloin tahansa valita, saako sovellus lukea ja lähettää ilmoituksia, avaamalla Asetukset > Ilmoitukset."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml index 9b5707cc4323..b74c8ee5d68a 100644 --- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml @@ -54,36 +54,24 @@ <string name="permission_microphone" msgid="2152206421428732949">"Microphone"</string> <string name="permission_call_logs" msgid="5546761417694586041">"Journaux d\'appels"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"Appareils à proximité"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"Modifier la sortie multimédia"</string> <string name="permission_storage" msgid="6831099350839392343">"Photos et fichiers multimédias"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notifications"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Applications"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Diffusion en continu"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Passez et gérez des appels téléphoniques"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Lisez et écrivez le journal d\'appels téléphoniques"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Envoyez et affichez des messages texte"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Accédez à vos contacts"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Accédez à votre agenda"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Enregistrez des fichiers audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Trouvez et déterminez la position relative des appareils à proximité, et connectez-vous à ceux-ci"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Lisez toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Lisez toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos<br/>• Envoyez des notifications<br/><br/>Vous pouvez gérer la capacité de cette application à lire et à envoyer des notifications à tout moment dans Paramètres > Notifications."</string> <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Accédez à une liste d\'appareils accessibles et contrôlez ceux qui diffusent du contenu audio ou vidéo à partir d\'autres applications"</string> <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 3437988bdc23..30b0c9af5f0b 100644 --- a/packages/CompanionDeviceManager/res/values-fr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Appareils à proximité"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Modifier la sortie multimédia"</string> <string name="permission_storage" msgid="6831099350839392343">"Photos et contenus multimédias"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notifications"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Applis"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Effectuer et gérer des appels téléphoniques"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Consulter et créer les journaux d\'appels du téléphone"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Envoyer et consulter des SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Accéder à vos contacts"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Accéder à votre agenda"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Enregistrer un fichier audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Trouver les appareils à proximité, s\'y connecter et déterminer leur position relative"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Lire toutes les notifications, y compris des informations comme les contacts, messages et photos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Lire toutes les notifications, y compris les informations comme les contacts, les messages et les photos<br/>• Envoyer des notifications<br/><br/>Vous pouvez gérer les autorisations de lecture et d\'envoi des notifications à tout moment dans Paramètres > Notifications."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml index e84f2d919f67..1b8b8d4d9078 100644 --- a/packages/CompanionDeviceManager/res/values-gl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos próximos"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Cambiar a saída multimedia"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos e contido multimedia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notificacións"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplicacións"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Reprodución en tempo real"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Fai e xestiona chamadas telefónicas"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Le e edita o rexistro de chamadas do teléfono"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Envía e consulta mensaxes SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Accede aos contactos"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Accede ao calendario"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Grava audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Busca dispositivos próximos, establece conexión con eles e determina a súa posición relativa"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Le todas as notificacións (que poden incluír información como contactos, mensaxes e fotos)"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Le todas as notificacións (que poden incluír información como contactos, mensaxes e fotos)<br/>• Envía notificacións<br/><br/>En Configuración > Notificacións podes xestionar en calquera momento a capacidade desta aplicación para ler e enviar notificacións."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml index 62e518a8ba22..474960cd7394 100644 --- a/packages/CompanionDeviceManager/res/values-gu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"નજીકના ડિવાઇસ"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"મીડિયા આઉટપુટ બદલો"</string> <string name="permission_storage" msgid="6831099350839392343">"ફોટા અને મીડિયા"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"નોટિફિકેશન"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ઍપ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"સ્ટ્રીમિંગ"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ફોન કૉલ કરવાની અને મેનેજ કરવાની"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ફોન કૉલ લૉગ વાંચવાની અને લખવાની"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS મેસેજ મોકલવાની અને જોવાની"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"તમારા સંપર્કોને ઍક્સેસ કરવાની"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ઑડિયો રેકોર્ડ કરવાની"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"નજીકના ડિવાઇસ શોધવાની, તેમની સાથે કનેક્ટ કરવાની અને તેમની સંબંધિત સ્થિતિ નિર્ધારિત કરવાની"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"સંપર્કો, મેસેજ અને ફોટા જેવી માહિતી સહિતના બધા નોટિફિકેશન વાંચવાની"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• સંપર્કો, મેસેજ અને ફોટા જેવી માહિતી સહિતના બધા નોટિફિકેશન વાંચવાની<br/>• નોટિફિકેશન મોકલવાની<br/><br/>તમે કોઈપણ સમયે સેટિંગમાં > નોટિફિકેશનમાં જઈને આ ઍપની નોટિફિકેશન વાંચવાની અને મોકલવાની ક્ષમતાને મેનેજ કરી શકો છો."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml index 3d3a2c139e42..931eab69b900 100644 --- a/packages/CompanionDeviceManager/res/values-hi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"आस-पास मौजूद डिवाइस"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"मीडिया आउटपुट बदलें"</string> <string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"सूचनाएं"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ऐप्लिकेशन"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"स्ट्रीमिंग"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"फ़ोन कॉल करने और उन्हें मैनेज करने की अनुमति दें"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"कॉल लॉग की जानकारी देखने और उसमें बदलाव करने की अनुमति दें"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"एसएमएस (मैसेज) भेजने और देखने की अनुमति दें"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"अपने संपर्कों को ऐक्सेस करने की अनुमति दें"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"अपने कैलेंडर को ऐक्सेस करने की अनुमति दें"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ऑडियो रिकॉर्ड करने की अनुमति दें"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"आस-पास मौजूद डिवाइसों को खोजने, उनसे कनेक्ट करने, और उनकी जगह की जानकारी का पता लगाने की अनुमति दें"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"सभी सूचनाएं देखने की अनुमति दें. जैसे, संपर्क, मैसेज, और फ़ोटो की जानकारी"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• सभी सूचनाएं देखने की अनुमति दें. जैसे, संपर्क, मैसेज, और फ़ोटो की जानकारी<br/>• सूचनाएं भेजने की अनुमति दें<br/><br/>सेटिंग > सूचनाएं में जाकर इस ऐप्लिकेशन के लिए, सूचनाओं को देखने और उनमें बदलाव करने की अनुमति में कभी भी बदलाव किया जा सकता है."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml index d6fbf2ffe5e3..6dc59ea0ceb0 100644 --- a/packages/CompanionDeviceManager/res/values-hr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Uređaji u blizini"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Promjena medijskog izlaza"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Obavijesti"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Uspostavljanje telefonskih poziva i upravljanje njima"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Čitanje i pisanje zapisnika poziva telefona"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Slanje i pregledavanje SMS poruka"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Pristup kontaktima"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Pristup kalendaru"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Snimanje zvuka"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Pronalaženje i određivanje relativnog položaja uređaja u blizini i povezivanje s njima"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Čitanje svih obavijesti, uključujući podatke kao što su kontakti, poruke i fotografije"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Čitanje svih obavijesti, uključujući podatke kao što su kontakti, poruke i fotografije<br/>• Slanje obavijesti<br/><br/>Uvijek možete upravljati mogućnostima ove aplikacije da čita i šalje obavijesti u postavkama i obavijestima"</string> <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">"Emitirajte stream aplikacija i drugih značajki sustava s vašeg telefona"</string> diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml index 0db1f7087840..4b1a6f7b98a7 100644 --- a/packages/CompanionDeviceManager/res/values-hu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Közeli eszközök"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Médiakiment módosítása"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotók és médiatartalmak"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Értesítések"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Alkalmazások"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streamelés"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Telefonhívások kezdeményezése és kezelése"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Hívásnapló olvasása és írása"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS-ek küldése és megtekintése"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Hozzáférés a névjegyekhez"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Hozzáférés a naptárhoz"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Hang rögzítése"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Megkeresheti a közeli eszközöket, meghatározhatja viszonylagos helyzetüket és csatlakozhat hozzájuk."</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Elolvashat minden értesítést, ideértve az olyan információkat, mint a névjegyek, az üzenetek és a fotók."</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Elolvashat minden értesítést, ideértve az olyan információkat, mint a névjegyek, az üzenetek és a fotók.<br/>• Értesítéseket küldhet.<br/><br/>A Beállítások > Értesítések menüpontban bármikor kezelheti az alkalmazás értesítések olvasására és küldésére való képességét."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml index 6e08a971bcfd..405a98387e33 100644 --- a/packages/CompanionDeviceManager/res/values-hy/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml @@ -54,36 +54,24 @@ <string name="permission_microphone" msgid="2152206421428732949">"Խոսափող"</string> <string name="permission_call_logs" msgid="5546761417694586041">"Կանչերի ցուցակ"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"Մոտակա սարքեր"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"Փոխել մեդիա արտածումը"</string> <string name="permission_storage" msgid="6831099350839392343">"Լուսանկարներ և մուլտիմեդիա"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Ծանուցումներ"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Հավելվածներ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Հեռարձակում"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Կատարել զանգեր և կառավարել զանգերը"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Դիտել հեռախոսի զանգերի մատյանը և կատարել գրանցում"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Ուղարկել և կարդալ SMS հաղորդագրություններ"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Օգտագործել ձեր կոնտակտները"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Օգտագործել ձեր օրացույցը"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Ձայնագրել"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Գտնել և որոշել մոտակա սարքերի մոտավոր դիրքը և միանալ դրանց"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Կարդալ բոլոր ծանուցումները, ներառյալ տեղեկությունները, օրինակ՝ կոնտակտները, հաղորդագրությունները և լուսանկարները"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Կարդալ բոլոր ծանուցումները, այդ թվում՝ կոնտակտները, հաղորդագրությունները և լուսանկարները<br/>• Ուղարկել ծանուցումներ<br/><br/>Դուք ցանկացած պահի կարող եք կառավարել այս հավելվածի՝ ծանուցումներ կարդալու հնարավորությունը՝ անցնելով Կարգավորումներ > Ծանուցումներ։"</string> <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Բացել հասանելի սարքերի ցանկը և կառավարել, թե որ սարքը աուդիո կամ վիդեո հեռարձակի այլ հավելվածներից"</string> <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 c0b8245abf0c..8f3909ca7a4f 100644 --- a/packages/CompanionDeviceManager/res/values-in/strings.xml +++ b/packages/CompanionDeviceManager/res/values-in/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Perangkat di sekitar"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Mengubah output media"</string> <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notifikasi"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikasi"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Melakukan dan mengelola panggilan telepon"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Membaca dan menulis log panggilan telepon"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Mengirim dan melihat pesan SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Mengakses kontak"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Mengakses kalender"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Merekam audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Menemukan, menghubungkan, dan menentukan posisi relatif dari perangkat di sekitar"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Membaca semua notifikasi, termasuk informasi seperti kontak, pesan, dan foto"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Membaca semua notifikasi, termasuk informasi seperti kontak, pesan, dan foto<br/>• Mengirim notifikasi<br/><br/>Anda dapat mengelola kemampuan aplikasi untuk membaca dan mengirim notifikasi kapan saja di Setelan > Notifikasi."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml index 5951a1de6f7f..baad2cf4676e 100644 --- a/packages/CompanionDeviceManager/res/values-is/strings.xml +++ b/packages/CompanionDeviceManager/res/values-is/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Nálæg tæki"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Breyta margmiðlunarúttaki"</string> <string name="permission_storage" msgid="6831099350839392343">"Myndir og efni"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Tilkynningar"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Forrit"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streymi"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Hringja og stjórna símtölum"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Lesa og skrifa símtalaskrá símans"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Senda og skoða SMS-skilaboð"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Fá aðgang að tengiliðunum þínum"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Fá aðgang að dagatalinu þínu"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Taka upp hljóð"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Finna, tengjast og áætla staðsetningu nálægra tækja"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Lesa allar tilkynningar, þar á meðal upplýsingar á borð við tengiliði, skilaboð og myndir"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Lesa allar tilkynningar, þ.m.t. upplýsingar á borð við tengiliði, skilaboð og myndir<br/>• Senda tilkynningar<br/><br/>Þú getur stjórnað getu forritsins til að lesa og senda tilkynningar hvenær sem er í „Stillingar > Tilkynningar“."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml index 9ce12410e2eb..81f5d62cb7fb 100644 --- a/packages/CompanionDeviceManager/res/values-it/strings.xml +++ b/packages/CompanionDeviceManager/res/values-it/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivi nelle vicinanze"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Cambia uscita conten. multim."</string> <string name="permission_storage" msgid="6831099350839392343">"Foto e contenuti multimediali"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notifiche"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"App"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Esegue e gestisce le telefonate"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Legge e modifica il registro chiamate dello smartphone"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Invia e visualizza SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Accede ai tuoi contatti"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Accede al tuo calendario"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Registra l\'audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Trova e si connette ai dispositivi nelle vicinanze, oltre a stabilire la loro posizione relativa"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Legge tutte le notifiche, incluse informazioni come contatti, messaggi e foto"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Legge tutte le notifiche, incluse informazioni come contatti, messaggi e foto<br/>• Invia notifiche<br/><br/>Puoi gestire la capacità dell\'app di leggere e inviare notifiche in qualsiasi momento in Impostazioni > Notifiche."</string> <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">"Trasmettere in streaming app e altre funzionalità di sistema dal telefono"</string> diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml index 8e2b715e396a..f4367c0acea5 100644 --- a/packages/CompanionDeviceManager/res/values-iw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"מכשירים בקרבת מקום"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"שינוי פלט המדיה"</string> <string name="permission_storage" msgid="6831099350839392343">"תמונות ומדיה"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"התראות"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"אפליקציות"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"סטרימינג"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ביצוע וניהול של שיחות טלפון"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"קריאה וכתיבה של נתוני יומן השיחות בטלפון"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"שליחה של הודעות SMS וצפייה בהן"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"גישה אל אנשי הקשר"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"גישה אל היומן"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"הקלטת אודיו"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"אפשרות למצוא מכשירים בקרבת מקום, להתחבר אליהם ולאתר את המיקום היחסי שלהם"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"אפשרות לקרוא את כל ההתראות, כולל מידע כמו אנשי קשר, הודעות ותמונות"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• קריאה של כל ההתראות, כולל מידע כמו אנשי קשר, הודעות ותמונות<br/>• שליחת התראות<br/><br/>אפשר לשנות את היכולת של האפליקציה לקרוא ולשלוח התראות בכל שלב ב\'הגדרות\' > \'התראות\'."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml index 175ea0fe05bd..2dfb4d1f6354 100644 --- a/packages/CompanionDeviceManager/res/values-ja/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"付近のデバイス"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"メディア出力の変更"</string> <string name="permission_storage" msgid="6831099350839392343">"写真とメディア"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"通知"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"アプリ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ストリーミング"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"電話の発信と管理"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"通話履歴の読み取りと書き込み"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS メッセージの送信と表示"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"連絡先へのアクセス"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"カレンダーへのアクセス"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"録音"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"付近のデバイスの検出、接続、相対位置の特定"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"すべての通知の読み取り(連絡先、メッセージ、写真に関する情報を含む)"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• すべての通知の読み取り(連絡先、メッセージ、写真に関する情報を含む)<br/>• 通知の送信<br/><br/>このアプリの通知読み取り機能と通知送信機能はいつでも [設定] > [通知] で管理できます。"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml index c6553444a21d..f4dcaea08230 100644 --- a/packages/CompanionDeviceManager/res/values-ka/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"ახლომახლო მოწყობილობები"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"გამომავალი მედიის გამოტანის"</string> <string name="permission_storage" msgid="6831099350839392343">"ფოტოები და მედია"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"შეტყობინებები"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"აპები"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"სტრიმინგი"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"სატელეფონო ზარების განხორციელება და მართვა"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"სატელეფონო ზარების ჟურნალის წაკითხვა და მასში ჩაწერა"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS შეტყობინებების გაგზავნა და ნახვა"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"თქვენს კონტაქტებზე წვდომა"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"თქვენს კალენდარზე წვდომა"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"აუდიოს ჩაწერა"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"ახლომახლო მოწყობილობების პოვნა, მათთან დაკავშირება და მათი შედარებითი პოზიციის დადგენა"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"ყველა შეტყობინების, მათ შორის ისეთი ინფორმაციის წაკითხვა, როგორიცაა კონტაქტები, შეტყობინებები და ფოტოები"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• ყველა შეტყობინების, მათ შორის კონტაქტების, შეტყობინებებისა და ფოტოების წაკითხვა<br/>• შეტყობინებების გაგზავნა<br/><br/>შეგიძლიათ, მართოთ ამ აპის შესაძლებლობა, წაიკითხოს და გაგზავნოს შეტყობინებები ნებისმიერ დროს პარამეტრებში > შეტყობინებები."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml index c4928da4c5f7..122e2e60f7ba 100644 --- a/packages/CompanionDeviceManager/res/values-kk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Маңайдағы құрылғылар"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Мультимедиа шығысын өзгерту"</string> <string name="permission_storage" msgid="6831099350839392343">"Фотосуреттер мен медиафайлдар"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Хабарландырулар"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Қолданбалар"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Трансляция"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Қоңырау шалу және телефон қоңырауларын басқару"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Телефонның қоңыраулар журналын оқу және жазу"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS хабарларын жіберу және көру"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Контактілерге кіру"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Күнтізбеге кіру"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Аудио жазу"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Маңайдағы құрылғыларды тауып, олармен байланысып, бір-біріне қатысты локациясын анықтайды."</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Барлық хабарландыруды, соның ішінде контактілер, хабарлар және фотосуреттер сияқты ақпаратты оқиды."</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Барлық хабарландыруды, соның ішінде контактілер, хабарлар және фотосуреттер сияқты ақпаратты оқиды<br/>• Хабарландырулар жібереді<br/><br/>Бұл қолданбаның хабарландыруларды оқу және жіберу мүмкіндігін \"Параметрлер > Хабарландырулар\" тармағында кез келген уақытта басқара аласыз."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml index 28b63404236a..d6f303737ef3 100644 --- a/packages/CompanionDeviceManager/res/values-km/strings.xml +++ b/packages/CompanionDeviceManager/res/values-km/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"ឧបករណ៍នៅជិត"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"ប្ដូរឧបករណ៍មេឌៀ"</string> <string name="permission_storage" msgid="6831099350839392343">"រូបថត និងមេឌៀ"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"ការជូនដំណឹង"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"កម្មវិធី"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ការផ្សាយ"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ហៅទូរសព្ទ និងគ្រប់គ្រងការហៅទូរសព្ទ"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"អាន និងសរសេរកំណត់ហេតុហៅទូរសព្ទ"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"ផ្ញើ និងមើលសារ SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"ចូលប្រើទំនាក់ទំនងរបស់អ្នក"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"ចូលប្រើប្រតិទិនរបស់អ្នក"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ថតសំឡេង"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"ស្វែងរក ភ្ជាប់ និងកំណត់ទីតាំងដែលពាក់ព័ន្ធរបស់ឧបករណ៍នៅជិត"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"អានការជូនដំណឹងទាំងអស់ រួមទាំងព័ត៌មានដូចជា ទំនាក់ទំនង សារ និងរូបថតជាដើម"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• អានការជូនដំណឹងទាំងអស់ រួមទាំងព័ត៌មានដូចជា ទំនាក់ទំនង សារ និងរូបថតជាដើម<br/>• ផ្ញើការជូនដំណឹង<br/><br/>អ្នកអាចគ្រប់គ្រងលទ្ធភាពរបស់កម្មវិធីនេះក្នុងការអាន និងផ្ញើការជូនដំណឹងបានគ្រប់ពេលនៅក្នុងការកំណត់ > ការជូនដំណឹង។"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml index eb9417868e13..661d344e2e6a 100644 --- a/packages/CompanionDeviceManager/res/values-kn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳು"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"ಮೀಡಿಯಾ ಔಟ್ಪುಟ್ ಬದಲಾಯಿಸಿ"</string> <string name="permission_storage" msgid="6831099350839392343">"ಫೋಟೋಗಳು ಮತ್ತು ಮಾಧ್ಯಮ"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"ನೋಟಿಫಿಕೇಶನ್ಗಳು"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ಆ್ಯಪ್ಗಳು"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ಸ್ಟ್ರೀಮಿಂಗ್"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ಫೋನ್ ಕರೆಗಳನ್ನು ಮಾಡಿ ಹಾಗೂ ನಿರ್ವಹಿಸಿ"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ಪೋನ್ ಕರೆಯ ಲಾಗ್ ಅನ್ನು ಓದಿ ಮತ್ತು ಬರೆಯಿರಿ"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಿ ಮತ್ತು ವೀಕ್ಷಿಸಿ"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"ನಿಮ್ಮ ಸಂಪರ್ಕಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಿ"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಅನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಿ"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳನ್ನು ಹುಡುಕಬಹುದು, ಅವುಗಳಿಗೆ ಕನೆಕ್ಟ್ ಆಗಬಹುದು ಮತ್ತು ಅವುಗಳ ಸಂಬಂಧಿತ ಸ್ಥಾನವನ್ನು ನಿರ್ಧರಿಸಬಹುದು"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"ಸಂಪರ್ಕಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು ಓದಬಹುದು"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• ಸಂಪರ್ಕಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು ಓದಿ<br/>• ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು ಕಳುಹಿಸಿ<br/><br/>ಈ ಆ್ಯಪ್ನ ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು ಓದುವ ಮತ್ತು ಕಳುಹಿಸುವ ಸಾಮರ್ಥ್ಯವನ್ನು ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಸೆಟ್ಟಿಂಗ್ಗಳು > ನೋಟಿಫಿಕೇಶನ್ಗಳಲ್ಲಿ ನಿರ್ವಹಿಸಬಹುದು."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml index 468539722141..aefda7c4d6fe 100644 --- a/packages/CompanionDeviceManager/res/values-ko/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"근처 기기"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"미디어 출력 변경"</string> <string name="permission_storage" msgid="6831099350839392343">"사진 및 미디어"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"알림"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"앱"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"스트리밍"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"전화 걸기 및 관리"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"통화 기록 읽고 쓰기"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS 메시지 보내기 및 보기"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"연락처에 액세스"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"캘린더에 액세스"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"오디오 녹음"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"근처 기기를 찾아 연결하고 기기 간 상대 위치를 파악할 수 있습니다."</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"연락처, 메시지, 사진 등의 정보를 포함한 모든 알림을 읽을 수 있습니다."</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• 연락처, 메시지, 사진과 같은 정보를 포함해 모든 알림을 읽습니다.<br/>• 알림을 전송합니다.<br/><br/>언제든지 설정 > 알림에서 알림을 읽고 전송할 수 있는 이 앱의 능력을 관리할 수 있습니다."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml index 76aefe15f0a2..099b5c5b74e1 100644 --- a/packages/CompanionDeviceManager/res/values-ky/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Жакын жердеги түзмөктөр"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Медиа чыгарылышын өзгөртүү"</string> <string name="permission_storage" msgid="6831099350839392343">"Сүрөттөр жана медиафайлдар"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Билдирмелер"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Колдонмолор"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Алып ойнотуу"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Телефон чалуу жана аларды башкаруу"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Телефондогу чалуулар тизмесин окуу жана жазуу"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS билдирүүлөрдү жөнөтүү жана көрсөтүү"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Байланыштарыңызды көрүү"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Жылнаамаңызды пайдалануу"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Аудио жаздыруу"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Жакын жердеги түзмөктөрдү таап, аларга туташып, абалын аныктоо"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Бардык билдирмелерди, анын ичинде байланыштар, билдирүүлөр жана сүрөттөр сыяктуу маалыматты окуу"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Бардык билдирмелерди, анын ичинде байланыштар, билдирүүлөр жана сүрөттөр сыяктуу маалыматты окуу<br/>• Билдирмелерди жөнөтүү<br/><br/>Бул колдонмонун билдирмелерди окуу жана жөнөтүү мүмкүнчүлүгүн каалаган убакта Параметрлер > Билдирмелер бөлүмүнөн тескей аласыз."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml index bbf0be3f3dd7..fa378ca0640f 100644 --- a/packages/CompanionDeviceManager/res/values-lo/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"ປ່ຽນເອົ້າພຸດສື່"</string> <string name="permission_storage" msgid="6831099350839392343">"ຮູບພາບ ແລະ ມີເດຍ"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"ການແຈ້ງເຕືອນ"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ແອັບ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ກຳລັງສະຕຣີມ"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ໂທອອກ ແລະ ຈັດການການໂທ"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ອ່ານ ແລະ ຂຽນບັນທຶກການໂທຂອງໂທລະສັບ"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"ສົ່ງ ແລະ ເບິ່ງຂໍ້ຄວາມ SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"ເຂົ້າເຖິງລາຍຊື່ຜູ້ຕິດຕໍ່ຂອງທ່ານ"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"ເຂົ້າເຖິງປະຕິທິນຂອງທ່ານ"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ບັນທຶກສຽງ"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"ຊອກຫາ, ເຊື່ອມຕໍ່ ແລະ ລະບຸສະຖານທີ່ທີ່ກ່ຽວຂ້ອງກັນຂອງອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"ອ່ານການແຈ້ງເຕືອນທັງໝົດ, ຮວມທັງຂໍ້ມູນ ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່, ຂໍ້ຄວາມ ແລະ ຮູບພາບ"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• ອ່ານການແຈ້ງເຕືອນທັງໝົດ, ຮວມທັງຂໍ້ມູນ ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່, ຂໍ້ຄວາມ ແລະ ຮູບພາບ<br/>• ສົ່ງການແຈ້ງເຕືອນ<br/><br/>ທ່ານສາມາດຈັດການຄວາມສາມາດຂອງແອັບນີ້ໃນການອ່ານ ແລະ ສົ່ງການແຈ້ງເຕືອນໄດ້ທຸກເວລາໃນການຕັ້ງຄ່າ> ການແຈ້ງເຕືອນ."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml index 1c28f1487803..54f840863f22 100644 --- a/packages/CompanionDeviceManager/res/values-lt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Įrenginiai netoliese"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Keisti medijos išvestį"</string> <string name="permission_storage" msgid="6831099350839392343">"Nuotraukos ir medija"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Pranešimai"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Programos"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Srautinis perdavimas"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Skambinti ir tvarkyti telefonų skambučius"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Skaityti ir rašyti telefono skambučių žurnalą"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Siųsti ir peržiūrėti SMS pranešimus"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Pasiekti kontaktus"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Pasiekti kalendorių"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Įrašyti garsą"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Rasti apytikslę netoliese esančių įrenginių poziciją, aptikti juos ir prisijungti prie jų"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Skaityti visus pranešimus, įskaitant tokią informaciją kaip kontaktai, pranešimai ir nuotraukos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Skaityti visus pranešimus, įskaitant tokią informaciją kaip kontaktai, pranešimai ir nuotraukos<br/>• Siųsti pranešimus<br/><br/>Galite bet kada tvarkyti šios programos leidimą skaityti ir siųsti pranešimus skiltyje „Nustatymai“ > „Pranešimai“."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml index 5126812c78f4..390d54428de2 100644 --- a/packages/CompanionDeviceManager/res/values-lv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Tuvumā esošas ierīces"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Mainīt multivides izvadi"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotoattēli un multivides faili"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Paziņojumi"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Lietotnes"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Straumēšana"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Veikt un pārvaldīt tālruņa zvanus"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Lasīt un rakstīt tālruņa zvanu žurnālu"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Sūtīt un skatīt īsziņas"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Piekļūt jūsu kontaktpersonu datiem"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Piekļūt jūsu kalendāram"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Ierakstīt audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Atrast tuvumā esošas ierīces, izveidot ar tām savienojumu un noteikt to relatīvo atrašanās vietu"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Lasīt visus paziņojumus, tostarp tādu informāciju kā kontaktpersonas, ziņojumi un fotoattēli"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Lasīt visus paziņojumus, tostarp tādu informāciju kā kontaktpersonas, ziņojumi un fotoattēli<br/>• Sūtīt paziņojumus<br/><br/>Jebkurā brīdī sadaļā “Iestatījumi un paziņojumi” varat pārvaldīt šīs lietotnes atļauju lasīt un sūtīt paziņojumus."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml index 24fbaa7e8485..dc15899c328c 100644 --- a/packages/CompanionDeviceManager/res/values-mk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Уреди во близина"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Промена на излезот за аудио"</string> <string name="permission_storage" msgid="6831099350839392343">"Аудиовизуелни содржини"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Известувања"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Апликации"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Стриминг"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Упатува и управува со телефонски повици"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Чита и пишува евиденција на повици во телефонот"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Испраќа и прикажува SMS-пораки"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Пристапува до контактите"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Пристапува до календарот"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Снима аудио"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Наоѓа и се поврзува со уреди во близина и да ја утврдува нивната релативна положба"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Ги чита сите известувања, меѓу кои и податоци како контакти, пораки и фотографии"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Ги чита сите известувања, меѓу кои и податоци како контакти, пораки и фотографии<br/>• Испраќа известувања<br/><br/>Може да управувате со способноста на апликацијава да чита и испраќа известувања кога било во „Поставки > Известувања“."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml index a3e07ca5eea9..6c09e6383e44 100644 --- a/packages/CompanionDeviceManager/res/values-ml/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"സമീപമുള്ള ഉപകരണങ്ങൾ"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"മീഡിയ ഔട്ട്പുട്ട് മാറ്റുക"</string> <string name="permission_storage" msgid="6831099350839392343">"ഫോട്ടോകളും മീഡിയയും"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"അറിയിപ്പുകൾ"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ആപ്പുകൾ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"സ്ട്രീമിംഗ്"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ഫോൺ കോളുകൾ വിളിക്കുക, മാനേജ് ചെയ്യുക"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ഫോൺ കോൾ ചരിത്രം എഴുതുകയും വായിക്കുകയും ചെയ്യുക"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS സന്ദേശങ്ങൾ അയയ്ക്കുക, കാണുക"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്സസ് ചെയ്യുക"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"നിങ്ങളുടെ കലണ്ടർ ആക്സസ് ചെയ്യുക"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"സമീപമുള്ള ഉപകരണങ്ങൾ കണ്ടെത്താനും അവയിലേക്ക് കണക്റ്റ് ചെയ്യാനും അവയുടെ ആപേക്ഷിക സ്ഥാനം നിർണ്ണയിക്കാനും കഴിയും"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"കോൺടാക്റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഉൾപ്പെടെ എല്ലാ അറിയിപ്പുകളും വായിക്കുക"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• കോൺടാക്റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഉൾപ്പെടെ എല്ലാ അറിയിപ്പുകളും വായിക്കുക<br/>• അറിയിപ്പുകൾ അയയ്ക്കുക<br/><br/>അറിയിപ്പുകൾ വായിക്കാനും അയയ്ക്കാനുമുള്ള ഈ ആപ്പിന്റെ ശേഷി ക്രമീകരണവും അറിയിപ്പുകളും എന്നതിൽ ഏതുസമയത്തും മാനേജ് ചെയ്യാം."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml index 584185e520d6..4cbccb48cae4 100644 --- a/packages/CompanionDeviceManager/res/values-mn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Ойролцоох төхөөрөмжүүд"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Медиа гаралтыг өөрчлөх"</string> <string name="permission_storage" msgid="6831099350839392343">"Зураг болон медиа"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Мэдэгдэл"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Аппууд"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Дамжуулах"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Утасны дуудлага хийх болон удирдах"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Утасны дуудлагын жагсаалтыг унших болон бичих"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS мессеж илгээх болон харах"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Таны харилцагчдад хандах"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Таны календарьт хандах"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Аудио бичих"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Ойролцоох төхөөрөмжүүдийн харьцангуй байрлалыг олох, тодорхойлох болон тэдгээрт холбогдох"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Харилцагчид, мессеж болон зургууд зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Харилцагчид, мессеж болон зургууд зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших<br/>• Мэдэгдлүүдийг илгээх<br/><br/>Та энэ аппын мэдэгдлүүдийг унших болон илгээх чадамжийг Тохиргоо > мэдэгдлүүдэд хүссэн үедээ удирдах боломжтой."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml index de4f7fda1f6c..a01759b4511d 100644 --- a/packages/CompanionDeviceManager/res/values-mr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"जवळपासची डिव्हाइस"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"मीडिया आउटपुट बदला"</string> <string name="permission_storage" msgid="6831099350839392343">"फोटो आणि मीडिया"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"सूचना"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ॲप्स"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"स्ट्रीमिंग"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"फोन कॉल करणे आणि ते व्यवस्थापित करणे"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"फोन कॉल लॉग रीड अँड राइट करणे"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"एसएमएस पाठवणे आणि पाहणे"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"तुमचे संपर्क ॲक्सेस करणे"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"तुमचे कॅलेंडर अॅक्सेस करणे"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ऑडिओ रेकॉर्ड करणे"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"जवळपासची डिव्हाइस शोधणे, त्यांच्याशी कनेक्ट करणे आणि त्यांचे संबंधित स्थान निर्धारित करणे"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"संपर्क, मेसेज आणि फोटो यांसारख्या माहितीसह सर्व सूचना वाचणे"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• संपर्क, मेसेज आणि फोटोसारख्या माहितीसह सर्व सूचना वाचणे<br/>• सूचना पाठवणे<br/><br/>तुम्ही या अॅपची सूचना वाचण्याची आणि पाठवण्याची क्षमता सेटिंग्ज > सूचना मध्ये कधीही व्यवस्थापित करू शकता."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml index 62b68f3d2ed8..008535b7711d 100644 --- a/packages/CompanionDeviceManager/res/values-ms/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Peranti berdekatan"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Tukar output media"</string> <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Pemberitahuan"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apl"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Penstriman"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Membuat dan mengurus panggilan telefon"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Baca dan tulis log panggilan telefon"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Menghantar dan melihat mesej SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Akses kenalan anda"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Akses kalendar anda"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Rakam audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Mencari, menyambung dan menentukan kedudukan relatif peranti berdekatan"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto<br/>• Menghantar pemberitahuan<br/><br/>Anda boleh mengurus keupayaan apl ini untuk membaca dan menghantar pemberitahuan pada bila-bila masa dalam Tetapan > Pemberitahuan."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml index f99009c7056c..05a3e88fcf98 100644 --- a/packages/CompanionDeviceManager/res/values-my/strings.xml +++ b/packages/CompanionDeviceManager/res/values-my/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"အနီးတစ်ဝိုက်ရှိ စက်များ"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"မီဒီယာအထွက် ပြောင်းခြင်း"</string> <string name="permission_storage" msgid="6831099350839392343">"ဓာတ်ပုံနှင့် မီဒီယာများ"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"အကြောင်းကြားချက်များ"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"အက်ပ်များ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"တိုက်ရိုက်ဖွင့်ခြင်း"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ဖုန်းခေါ်ဆိုမှုများ ပြုလုပ်နိုင်၊ စီမံနိုင်သည်"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ဖုန်းခေါ်ဆိုမှတ်တမ်းကို ဖတ်နိုင်၊ ရေးနိုင်သည်"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS မက်ဆေ့ဂျ်များ ပို့နိုင်၊ ကြည့်နိုင်သည်"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"သင့်အဆက်အသွယ်များကို ဝင်ကြည့်နိုင်သည်"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"သင့်ပြက္ခဒိန်ကို ဝင်ကြည့်နိုင်သည်"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"အသံသွင်းနိုင်သည်"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"အနီးတစ်ဝိုက်ရှိ စက်များ၏ ဆက်စပ်နေရာကို ရှာခြင်း၊ ချိတ်ဆက်ခြင်းနှင့် သတ်မှတ်ခြင်းတို့ လုပ်နိုင်သည်"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံများကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်နိုင်သည်"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံများကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်ခြင်း<br/>• အကြောင်းကြားချက်များ ပို့ခြင်း<br/><br/>ဆက်တင်များ > အကြောင်းကြားချက်များ တွင် အကြောင်းကြားချက်များအား ဤအက်ပ်၏ ဖတ်ခွင့်နှင့် ပို့ခွင့်ကို အချိန်မရွေး စီမံနိုင်သည်။"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml index 7f091490d8c0..d910f2fc9904 100644 --- a/packages/CompanionDeviceManager/res/values-nb/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Enheter i nærheten"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Bytt medieutgang"</string> <string name="permission_storage" msgid="6831099350839392343">"Bilder og medier"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Varsler"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apper"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Strømming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Ring og administrer anrop"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Les og skriv samtalelogg"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Send og les SMS-meldinger"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Se kontaktene dine"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Åpne kalenderen din"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Ta opp lyd"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Finn, koble til og fastslå den relative posisjonen til enheter i nærheten"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Les alle varsler, inkludert informasjon som kontakter, meldinger og bilder"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Les alle varsler, inkludert informasjon som kontakter, meldinger og bilder<br/>• Send varsler<br/><br/>Du kan når som helst administrere om denne appen kan lese og sende varsler, i Innstillinger > Varsler."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml index 38facb9ab518..2001af20dd6d 100644 --- a/packages/CompanionDeviceManager/res/values-ne/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"नजिकैका डिभाइसहरू"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"मिडिया आउटपुट बदल्नुहोस्"</string> <string name="permission_storage" msgid="6831099350839392343">"फोटो र मिडिया"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"सूचनाहरू"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"एपहरू"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"स्ट्रिमिङ"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"फोन कल गर्ने र व्यवस्थापन गर्ने"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"फोन कलको लग रिड र राइट गर्ने"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS म्यासेज पठाउने र हेर्ने"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"तपाईंका कन्ट्याक्टहरू हेर्ने"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"तपाईंको पात्रो प्रयोग गर्ने"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"अडियो रेकर्ड गर्ने"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"नजिकैका डिभाइसहरू भेट्टाउने, ती डिभाइससँग कनेक्ट गर्ने र तिनको सापेक्ष स्थिति निर्धारण गर्ने"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"कन्ट्याक्ट, म्यासेज र फोटो जस्ता जानकारीलगायतका सबै सूचनाहरू रिड गर्ने"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• कन्ट्याक्ट, म्यासेज र फोटो जस्ता जानकारीलगायतका सबै सूचनाहरू रिड गर्ने<br/>• सूचनाहरू पठाउने<br/><br/>तपाईं जुनसुकै बेला सेटिङ > सूचनाहरू खण्डमा गई यो एपलाई सूचनाहरू रिड गर्न र पठाउन दिने कि नदिने भन्ने कुरा व्यवस्थापन गर्न सक्नुहुन्छ।"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml index 38c92e5c4a47..e8ccb58e0361 100644 --- a/packages/CompanionDeviceManager/res/values-nl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Apparaten in de buurt"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Media-uitvoer wijzigen"</string> <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Meldingen"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Bellen en gesprekken beheren"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Telefoongesprekslijst lezen en schrijven"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Sms-berichten sturen en bekijken"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Toegang tot je contacten"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Toegang tot je agenda"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Audio opnemen"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Apparaten in de buurt vinden, er verbinding mee maken en de relatieve positie ervan bepalen"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s<br/>• Meldingen sturen<br/><br/>Je kunt de mogelijkheden van deze app om meldingen te lezen en te sturen, beheren wanneer je wilt via Instellingen > Meldingen."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml index 16985fa394f4..0bb47b8b249d 100644 --- a/packages/CompanionDeviceManager/res/values-or/strings.xml +++ b/packages/CompanionDeviceManager/res/values-or/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"ଆଖପାଖର ଡିଭାଇସଗୁଡ଼ିକ"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"ମିଡିଆ ଆଉଟପୁଟ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string> <string name="permission_storage" msgid="6831099350839392343">"ଫଟୋ ଏବଂ ମିଡିଆ"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ଆପ୍ସ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ଷ୍ଟ୍ରିମିଂ"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ଫୋନ କଲଗୁଡ଼ିକ କରିବା ଏବଂ ସେଗୁଡ଼ିକୁ ପରିଚାଳନା କରିବା"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ଫୋନ କଲ ଲଗକୁ ପଢ଼ିବା ଏବଂ ଲେଖିବା"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS ମେସେଜ ପଠାଇବା ଏବଂ ଭ୍ୟୁ କରିବା"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"ଆପଣଙ୍କ କଣ୍ଟାକ୍ଟଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"ଆପଣଙ୍କ କେଲେଣ୍ଡରକୁ ଆକ୍ସେସ କରିବା"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ଅଡିଓ ରେକର୍ଡ କରିବା"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"ଆଖପାଖର ଡିଭାଇସଗୁଡ଼ିକୁ ଖୋଜିବା, କନେକ୍ଟ କରିବା ଏବଂ ସେଗୁଡ଼ିକର ଆପେକ୍ଷିକ ଅବସ୍ଥିତିକୁ ନିର୍ଦ୍ଧାରଣ କରିବା"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"କଣ୍ଟାକ୍ଟ, ମେସେଜ ଏବଂ ଫଟୋଗୁଡ଼ିକ ପରି ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତିକୁ ପଢ଼ନ୍ତୁ"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• କଣ୍ଟାକ୍ଟ, ମେସେଜ ଏବଂ ଫଟୋ ପରି ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତିକୁ ପଢ଼ନ୍ତୁ<br/>• ବିଜ୍ଞପ୍ତି ପଠାନ୍ତୁ<br/><br/>ଆପଣ ସେଟିଂସ > ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକରେ ଯେ କୌଣସି ସମୟରେ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପଢିବା ଏବଂ ପଠାଇବା ପାଇଁ ଏହି ଆପର କ୍ଷମତାକୁ ପରିଚାଳନା କରିପାରିବେ।"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml index 31f9ec9dd9f8..445afa363e5d 100644 --- a/packages/CompanionDeviceManager/res/values-pa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸ"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"ਮੀਡੀਆ ਆਊਟਪੁੱਟ ਬਦਲੋ"</string> <string name="permission_storage" msgid="6831099350839392343">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"ਸੂਚਨਾਵਾਂ"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ਐਪਾਂ"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ਸਟ੍ਰੀਮਿੰਗ"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ਫ਼ੋਨ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ਫ਼ੋਨ ਦੇ ਕਾਲ ਲੌਗ ਨੂੰ ਪੜ੍ਹਣ ਅਤੇ ਲਿਖਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS ਸੁਨੇਹੇ ਭੇਜਣ ਅਤੇ ਦੇਖਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"ਆਪਣੇ ਸੰਪਰਕਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"ਆਪਣੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ਆਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਨੂੰ ਲੱਭਣ, ਉਨ੍ਹਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰਨ ਅਤੇ ਸੰਬੰਧਿਤ ਸਥਿਤੀ ਨਿਰਧਾਰਿਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਪੜ੍ਹਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ, ਜਿਵੇਂ ਕਿ ਸੰਪਰਕਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਫ਼ੋਟੋਆਂ ਦੀ ਜਾਣਕਾਰੀ"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਪੜ੍ਹਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ, ਜਿਵੇਂ ਕਿ ਸੰਪਰਕਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਫ਼ੋਟੋਆਂ ਦੀ ਜਾਣਕਾਰੀ<br/>• ਸੂਚਨਾਵਾਂ ਭੇਜਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ<br/><br/>ਤੁਸੀਂ ਸੈਟਿੰਗਾਂ > ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਜਾ ਕੇ ਕਿਸੇ ਵੀ ਵੇਲੇ ਸੂਚਨਾਵਾਂ ਨੂੰ ਪੜ੍ਹਨ ਅਤੇ ਭੇਜਣ ਦੀ ਇਸ ਐਪ ਦੀ ਯੋਗਤਾ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦੇ ਹੋ।"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml index abffff18ffaa..aec7b68504ff 100644 --- a/packages/CompanionDeviceManager/res/values-pl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Urządzenia w pobliżu"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Zmień wyjście multimediów"</string> <string name="permission_storage" msgid="6831099350839392343">"Zdjęcia i multimedia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Powiadomienia"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacje"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Strumieniowanie"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Nawiązywanie połączeń telefonicznych i zarządzanie nimi"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Odczytywanie i zapisywanie rejestru połączeń telefonicznych"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Wysyłanie i wyświetlanie SMS‑ów"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Dostęp do kontaktów"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Dostęp do kalendarza"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Nagrywanie dźwięku"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Znajdowanie urządzeń w pobliżu, określanie ich względnego położenia oraz łączenie się z nimi"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Odczytywanie wszystkich powiadomień, w tym informacji takich jak kontakty, wiadomości i zdjęcia"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Odczytywanie wszystkich powiadomień, w tym informacji takich jak kontakty, wiadomości i zdjęcia<br/>• Wysyłanie powiadomień<br/><br/>W każdej chwili możesz zmienić uprawnienia tej aplikacji do odczytywania i wysyłania powiadomień, klikając Ustawienia > Powiadomienia."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml index a95dcb689be7..ef1d6cdd2bb5 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos por perto"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Mudar saída de mídia"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notificações"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Fazer e gerenciar ligações telefônicas"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Ler e gravar o registro de chamadas telefônicas"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Enviar e visualizar mensagens SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Acessar seus contatos"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Acessar sua agenda"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Gravar áudio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Encontrar, determinar o posicionamento relativo e se conectar a dispositivos por perto"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Ler todas as notificações, incluindo informações como, por exemplo, contatos, mensagens e fotos<br/>• Enviar notificações<br/><br/>Você pode gerenciar a capacidade deste app de ler e enviar notificações a qualquer momento em \"Configurações\" e \"Notificações\"."</string> <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">"Fazer streaming de apps e outros recursos do sistema pelo smartphone"</string> diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml index a95dcb689be7..ef1d6cdd2bb5 100644 --- a/packages/CompanionDeviceManager/res/values-pt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos por perto"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Mudar saída de mídia"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notificações"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Fazer e gerenciar ligações telefônicas"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Ler e gravar o registro de chamadas telefônicas"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Enviar e visualizar mensagens SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Acessar seus contatos"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Acessar sua agenda"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Gravar áudio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Encontrar, determinar o posicionamento relativo e se conectar a dispositivos por perto"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Ler todas as notificações, incluindo informações como, por exemplo, contatos, mensagens e fotos<br/>• Enviar notificações<br/><br/>Você pode gerenciar a capacidade deste app de ler e enviar notificações a qualquer momento em \"Configurações\" e \"Notificações\"."</string> <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">"Fazer streaming de apps e outros recursos do sistema pelo smartphone"</string> diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml index a89da9dc355c..d2c3099ee2b7 100644 --- a/packages/CompanionDeviceManager/res/values-ro/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispozitive din apropiere"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Schimbă ieșirea media"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotografii și media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Notificări"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplicații"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Să inițieze și să gestioneze apeluri telefonice"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Să citească și să scrie jurnalul de apeluri telefonice"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Să trimită și să vadă SMS-urile"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Să acceseze agenda"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Să acceseze calendarul"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Să înregistreze conținut audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Să găsească, să se conecteze la dispozitivele apropiate și să determine poziția relativă a acestora"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Să citească toate notificările, inclusiv informații cum ar fi agenda, mesajele și fotografiile"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Să citească toate notificările, inclusiv informații cum ar fi agenda, mesajele și fotografiile<br/>• Să trimită notificări<br/><br/>Poți să gestionezi oricând permisiunea acestei aplicații de a citi și trimite notificări în Setări > Notificări."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml index 9cd823fe5ce7..77a2c46503d0 100644 --- a/packages/CompanionDeviceManager/res/values-ru/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Устройства поблизости"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Смена источника вывода медиа"</string> <string name="permission_storage" msgid="6831099350839392343">"Фотографии и медиафайлы"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Уведомления"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Приложения"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Потоковая передача"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Совершение телефонных звонков и управление ими"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Просмотр списка телефонных вызовов и создание записей в нем"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Отправка и просмотр SMS-сообщений"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Доступ к контактам"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Доступ к календарю"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Запись аудио"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Поиск устройств поблизости, подключение к ним и определение их относительного местоположения"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Чтение всех уведомлений, в том числе сведений о контактах, сообщениях и фотографиях"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Чтение всех уведомлений, в том числе сведений о контактах, сообщениях и фотографиях<br/>• Отправка уведомлений<br/><br/>В разделе \"Настройки > Уведомления\" вы можете в любое время разрешить или запретить этому приложению читать и отправлять уведомления."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml index d83c1f11e214..1ba83fdff6ba 100644 --- a/packages/CompanionDeviceManager/res/values-si/strings.xml +++ b/packages/CompanionDeviceManager/res/values-si/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"අවට උපාංග"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"මාධ්ය ප්රතිදානය වෙනස් කරන්න"</string> <string name="permission_storage" msgid="6831099350839392343">"ඡායාරූප සහ මාධ්ය"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"දැනුම්දීම්"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"යෙදුම්"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ප්රවාහ කිරීම"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"දුරකථන ඇමතුම් ගැනීම සහ කළමනාකරණය කිරීම"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"දුරකථන ඇමතුම් ලොගය කියවන්න සහ ලියන්න"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS පණිවිඩ යැවීම සහ බැලීම"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"ඔබේ සම්බන්ධතා වෙත ප්රවේශ වන්න"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"ඔබේ දින දර්ශනයට ප්රවේශ වන්න"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ශ්රව්ය පටිගත කරන්න"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"අවට උපාංගවල සාපේක්ෂ පිහිටීම සොයා ගන්න, සම්බන්ධ වන්න, සහ තීරණය කරන්න"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"සම්බන්ධතා, පණිවිඩ, සහ ඡායාරූප වැනි තොරතුරු ඇතුළුව, සියලු දැනුම්දීම් කියවන්න"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• සම්බන්ධතා, පණිවිඩ, සහ ඡායාරූප වැනි තතු ඇතුළුව, සියලු දැනුම්දීම් කියවන්න<br/>• දැනුම්දීම් යවන්න<br/><br/>ඔබට සැකසීම් > දැනුම්දීම් තුළ ඕනෑම වේලාවක මෙම යෙදුමට දැනුම්දීම් කියවීමට සහ යැවීමට ඇති හැකියාව කළමනාකරණය කළ හැක."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml index 55e6daf8b78d..637a24018759 100644 --- a/packages/CompanionDeviceManager/res/values-sk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Zariadenia v okolí"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Zmena výstupu médií"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotky a médiá"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Upozornenia"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikácie"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Volanie a správa telefonických hovorov"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Čítanie a zapisovanie do zoznamu telefonických hovorov"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Posielanie a zobrazovanie správ SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Prístup ku kontaktom"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Prístup ku kalendáru"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Nahrávanie zvuku"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Vyhľadajte zariadenia v okolí, pripojte sa k nim a určite ich relatívnu polohu"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Čítajte všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Čítajte všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky<br/>• Odosielajte upozornenia<br/><br/>Schopnosť tejto aplikácie čítať a odosielať upozornenia môžete kedykoľvek spravovať v sekcii Nastavenia > Upozornenia."</string> <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">"Streaming aplikácii a ďalších systémových funkcií zo zariadenia"</string> diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml index 097b7b6abbf1..b03c27a9849f 100644 --- a/packages/CompanionDeviceManager/res/values-sl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Naprave v bližini"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Spreminjanje izhoda za predstavnost"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotografije in predstavnost"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Obvestila"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Pretočno predvajanje"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Opravljanje in upravljanje telefonskih klicev"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Branje in zapisovanje dnevnika klicev v telefonu"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Pošiljanje in ogled sporočil SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Dostop do stikov"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Dostop do koledarja"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Snemanje zvoka"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Iskanje naprav v bližini, povezovanje z njimi in določanje njihovega relativnega položaja"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Branje vseh obvestil, vključno s podatki, kot so stiki, sporočila in fotografije"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Branje vseh obvestil, vključno s podatki, kot so stiki, sporočila in fotografije<br/>• Pošiljanje obvestil<br/><br/>Zmožnost branja in pošiljanja obvestil za to aplikacijo lahko kadar koli upravljate v meniju »Nastavitve« > »Obvestila«."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml index 416de583e394..5eeeeb81ddf5 100644 --- a/packages/CompanionDeviceManager/res/values-sq/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml @@ -54,36 +54,24 @@ <string name="permission_microphone" msgid="2152206421428732949">"Mikrofoni"</string> <string name="permission_call_logs" msgid="5546761417694586041">"Evidencat e telefonatave"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"Pajisjet në afërsi"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"Të ndryshojë daljen e medias"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotografitë dhe media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Njoftimet"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacionet"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Transmetimi"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Të kryejë dhe të menaxhojë telefonatat"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Të lexojë dhe shkruajë në evidencën e telefonatave"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Të dërgojë dhe të shikojë mesazhet SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Të qaset te kontaktet e tua"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Të qaset te kalendari yt"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Të regjistrojë audion"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Të gjejë, të lidhet dhe të përcaktojë pozicionin e përafërt të pajisjeve në afërsi"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Të lexojë të gjitha njoftimet, duke përfshirë informacione si kontaktet, mesazhet dhe fotografitë"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Të lexojë të gjitha njoftimet, duke përfshirë informacione si kontaktet, mesazhet dhe fotografitë<br/>• Të dërgojë njoftime<br/><br/>Mund ta menaxhosh aftësinë e këtij aplikacioni që të lexojë dhe të dërgojë njoftime në çdo kohë te Cilësimet > Njoftimet."</string> <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Të qaset te një listë e pajisjeve të disponueshme dhe të kontrollojë se cila transmeton audion ose videon nga aplikacionet e tjera"</string> <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 9b957694ba99..2271092fc804 100644 --- a/packages/CompanionDeviceManager/res/values-sr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Уређаји у близини"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Промена медијског излаза"</string> <string name="permission_storage" msgid="6831099350839392343">"Слике и медији"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Обавештења"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Апликације"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Стриминг"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Упућивање телефонских позива и управљање њима"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Читање и писање евиденције позива на телефону"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Слање и преглед SMS порука"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Приступ контактима"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Приступ календару"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Снимање звука"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Проналажење уређаја у близини, утврђивање њихове релативне позиције и повезивање са њима"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Читање свих обавештења, укључујући информација попут контаката, порука и слика"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Читање свих обавештења, укључујући информација попут контаката, порука и слика<br/>• Слање обавештења<br/><br/>Да бисте управљали дозволама ове апликације за читање и слање обавештења, идите у Подешавања > Обавештења."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml index e17fb0487441..a8934768d1fb 100644 --- a/packages/CompanionDeviceManager/res/values-sv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Enheter i närheten"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Ändra uppspelning av media"</string> <string name="permission_storage" msgid="6831099350839392343">"Foton och media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Aviseringar"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Appar"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Ringa och hantera telefonsamtal"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Läsa och skriva samtalshistorik"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Skicka och se sms"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Få tillgång till dina kontakter"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Få tillgång till din kalender"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Spela in ljud"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Hitta, ansluta till och avgöra den relativa positionen för enheter i närheten"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Läsa alla aviseringar, inklusive information som kontakter, meddelanden och foton"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Läsa alla aviseringar, inklusive sådant som kontakter, meddelanden och foton<br/>• Skicka aviseringar<br/><br/>Du kan hantera appens möjlighet att läsa och skicka aviseringar när du vill i Inställningar > Aviseringar."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml index 59a6a0e76676..c35c407fcbd2 100644 --- a/packages/CompanionDeviceManager/res/values-sw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml @@ -54,36 +54,24 @@ <string name="permission_microphone" msgid="2152206421428732949">"Maikrofoni"</string> <string name="permission_call_logs" msgid="5546761417694586041">"Rekodi za namba za simu"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"Vifaa vilivyo karibu"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"Badilisha tokeo la maudhui"</string> <string name="permission_storage" msgid="6831099350839392343">"Picha na maudhui"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Arifa"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Programu"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Kutiririsha maudhui"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Kupiga na kudhibiti simu"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Kusoma na kuandika rekodi ya namba za simu"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Kutuma na kuona ujumbe wa SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Kufikia anwani zako"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Kufikia kalenda yako"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Kurekodi sauti"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Kutafuta, kuunganisha na kubaini nafasi ya makadirio ya vifaa vilivyo karibu"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Kusoma arifa zote, ikiwa ni pamoja na maelezo kama vile anwani, ujumbe na picha"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Soma arifa zote, ikiwa ni pamoja na maelezo kama vile anwani, ujumbe na picha<br/>• Tuma arifa<br/><br/>Unaweza kudhibiti uwezo wa programu hii wa kusoma na kutuma arifa wakati wowote katika Mipangilio > Arifa."</string> <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Fikia orodha ya vifaa vinavyopatikana na udhibiti unavyotumia kutiririsha au kutuma maudhui ya sauti au video kutoka kwenye programu nyingine`"</string> <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 97d59fd39c9f..1efdca48be81 100644 --- a/packages/CompanionDeviceManager/res/values-ta/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml @@ -54,36 +54,24 @@ <string name="permission_microphone" msgid="2152206421428732949">"மைக்ரோஃபோன்"</string> <string name="permission_call_logs" msgid="5546761417694586041">"அழைப்புப் பதிவுகள்"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"அருகிலுள்ள சாதனங்கள்"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"மீடியா அவுட்புட்டை மாற்றுதல்"</string> <string name="permission_storage" msgid="6831099350839392343">"படங்கள் மற்றும் மீடியா"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"அறிவிப்புகள்"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ஆப்ஸ்"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"ஸ்ட்ரீமிங்"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"மொபைல் அழைப்புகளைச் செய்யலாம் நிர்வகிக்கலாம்"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"மொபைல் அழைப்புப் பதிவைப் படிக்கலாம் எழுதலாம்"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS செய்திகளை அனுப்பலாம் பார்க்கலாம்"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"தொடர்புகளை அணுகலாம்"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"கேலெண்டரை அணுகலாம்"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ஆடியோவை ரெக்கார்டு செய்யலாம்"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"அருகிலுள்ள சாதனங்களைக் கண்டறியலாம், அவற்றுடன் இணையலாம், அவற்றின் தூரத்தைத் தீர்மானிக்கலாம்"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"தொடர்புகள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்கலாம்"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• தொடர்புகள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்கலாம்<br/>• அறிவிப்புகளை அனுப்பலாம்<br/><br/>இந்த ஆப்ஸின், அறிவிப்புகளைப் படிக்கும் மற்றும் அனுப்பும் திறனை எப்போது வேண்டுமானாலும் அமைப்புகள் > அறிவிப்புகள் என்பதில் நிர்வகிக்கலாம்."</string> <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"கிடைக்கக்கூடிய சாதனங்களின் பட்டியலை அணுகி, அவற்றில் எது பிற ஆப்ஸின் ஆடியோ/வீடியோவைப் பிளே செய்யலாம் அல்லது அலைபரப்பலாம் என்பதைக் கட்டுப்படுத்தும்"</string> <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 c6af6edecbc7..3dd183e6acfc 100644 --- a/packages/CompanionDeviceManager/res/values-te/strings.xml +++ b/packages/CompanionDeviceManager/res/values-te/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"సమీపంలోని పరికరాలు"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"మీడియా అవుట్పుట్ను మార్చండి"</string> <string name="permission_storage" msgid="6831099350839392343">"ఫోటోలు, మీడియా"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"నోటిఫికేషన్లు"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"యాప్లు"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"స్ట్రీమింగ్"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"ఫోన్ కాల్స్ను చేయగలదు, మేనేజ్ చేయగలదు"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"ఫోన్ కాల్ లాగ్ను చదవగలదు, రాయగలదు"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS మెసేజ్లను పంపగలదు, చూడగలదు"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"మీ కాంటాక్ట్లను యాక్సెస్ చేయగలదు"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"మీ క్యాలెండర్ను యాక్సెస్ చేయగలదు"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"ఆడియోను రికార్డ్ చేయగలదు"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"సమీపంలోని పరికరాలను కనుగొనగలదు, వాటికి కనెక్ట్ అవ్వగలదు, అవి ఎంత దూరంలో ఉన్నాయో తెలుసుకోగలదు"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"కాంటాక్ట్లు, మెసేజ్లు, ఫోటోల వంటి సమాచారంతో సహా అన్ని నోటిఫికేషన్లను చదవగలదు"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• కాంటాక్ట్లు, మెసేజ్లు, ఫోటోల వంటి సమాచారంతో సహా నోటిఫికేషన్లన్నింటిని చదవగలదు<br/>• నోటిఫికేషన్లను పంపగలదు<br/><br/>నోటిఫికేషన్లను చదవగల, పంపగల ఈ యాప్ సామర్థ్యాన్ని మీరు సెట్టింగ్లు > నోటిఫికేషన్లలో ఎప్పుడైనా మేనేజ్ చేయవచ్చు."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml index 3925747df3dc..1ed5abf60da5 100644 --- a/packages/CompanionDeviceManager/res/values-th/strings.xml +++ b/packages/CompanionDeviceManager/res/values-th/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"อุปกรณ์ที่อยู่ใกล้เคียง"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"เปลี่ยนเอาต์พุตสื่อ"</string> <string name="permission_storage" msgid="6831099350839392343">"รูปภาพและสื่อ"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"การแจ้งเตือน"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"แอป"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"สตรีมมิง"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"โทรและจัดการการโทร"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"อ่านและเขียนบันทึกการโทรของโทรศัพท์"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"ส่งและดูข้อความ SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"เข้าถึงรายชื่อติดต่อ"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"เข้าถึงปฏิทิน"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"บันทึกเสียง"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"ค้นหา เชื่อมต่อ และระบุตำแหน่งซึ่งสัมพันธ์กับอุปกรณ์ที่อยู่ใกล้เคียง"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"อ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่างรายชื่อติดต่อ ข้อความ และรูปภาพ"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• อ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่างรายชื่อติดต่อ ข้อความ และรูปภาพ<br/>• ส่งการแจ้งเตือน<br/><br/>คุณจัดการความสามารถในการอ่านและส่งการแจ้งเตือนของแอปนี้ได้ทุกเมื่อในการตั้งค่า > การแจ้งเตือน"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml index f4677700ff28..1b82d91836ea 100644 --- a/packages/CompanionDeviceManager/res/values-tl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Mga kalapit na device"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Palitan ang media output"</string> <string name="permission_storage" msgid="6831099350839392343">"Mga larawan at media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Mga Notification"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Mga App"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Streaming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Tumawag at mamahala ng mga tawag sa telepono"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"I-read at i-write ang log ng tawag sa telepono"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Magpadala at tumingin ng mga mensaheng SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"I-access ang iyong mga contact"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"I-access ang iyong kalendaryo"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Mag-record ng audio"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Maghanap ng, kumonekta sa, at tukuyin ang relatibong posisyon ng mga kalapit na device"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Basahin ang lahat ng notification, kabilang ang impormasyon tulad ng mga contact, mensahe, at larawan"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Basahin ang lahat ng notification, kabilang ang impormasyon tulad ng mga contact, mensahe, at larawan<br/>• Magpadala ng mga notification<br/><br/>Puwede mong pamahalaan ang kakayahan ng app na ito na magbasa at magpadala ng mga notification kahit kailan sa Mga Setting > Mga Notification."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml index cc8e8983962a..392e1585a6ac 100644 --- a/packages/CompanionDeviceManager/res/values-tr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Yakındaki cihazlar"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Medya çıkışını değiştirin"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotoğraflar ve medya"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Bildirimler"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Uygulamalar"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Yayınlama"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Telefon aramaları yapma ve yönetme"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Telefon arama kaydını okuma ve yazma"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS mesajları gönderme ve görüntüleme"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Kişilerinize erişme"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Takviminize erişme"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Ses kaydetme"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Yakındaki cihazları keşfedip bağlanma ve bu cihazların göreli konumunu belirleme"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Kişiler, mesajlar ve fotoğraflar da dahil olmak üzere tüm bildirimleri okuma"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Kişiler, mesajlar ve fotoğraflar gibi bilgiler dahil tüm bildirimleri okuma<br/>• Bildirim gönderme<br/><br/>Dilediğiniz zaman bu uygulamanın bildirim okuma ve gönderme iznini Ayarlar > Bildirimler bölümünden yönetebilirsiniz."</string> <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefonunuzun uygulamalarını yayınlayabilir"</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ınlayabilir"</string> diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml index f0433ae5de44..9f88d9f3f852 100644 --- a/packages/CompanionDeviceManager/res/values-uk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml @@ -54,36 +54,24 @@ <string name="permission_microphone" msgid="2152206421428732949">"Мікрофон"</string> <string name="permission_call_logs" msgid="5546761417694586041">"Журнали викликів"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"Пристрої поблизу"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"Змін. пристр. для відтв. медіа"</string> <string name="permission_storage" msgid="6831099350839392343">"Фотографії та медіафайли"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Сповіщення"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Додатки"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Потокове передавання"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Телефонувати й керувати дзвінками"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Переглядати й записувати дані в журналі викликів телефона"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Надсилати й переглядати SMS-повідомлення"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Отримувати доступ до контактів"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Отримувати доступ до календаря"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Записувати аудіо"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Знаходити пристрої поблизу, підключатися до них і визначати їх відносне розташування"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Читати всі сповіщення, зокрема таку інформацію, як контакти, повідомлення й фотографії"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Читати всі сповіщення, зокрема таку інформацію, як контакти, повідомлення й фотографії<br/>• Надсилати сповіщення<br/><br/>Ви можете будь-коли змінити дозвіл цього додатка на перегляд і надсилання сповіщень, вибравши \"Налаштування\" > \"Сповіщення\"."</string> <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Отримувати доступ до списку доступних пристроїв і вибирати, з якого з них транслюватиметься аудіо або відео з інших додатків"</string> <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 58c1ab623ac2..36f8b4f8b5f1 100644 --- a/packages/CompanionDeviceManager/res/values-ur/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"قریبی آلات"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"میڈیا آؤٹ پٹ کو تبدیل کریں"</string> <string name="permission_storage" msgid="6831099350839392343">"تصاویر اور میڈیا"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"اطلاعات"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"ایپس"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"سلسلہ بندی"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"فون کالز کریں اور ان کا نظم کریں"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"فون کال لاگز پڑھیں اور لکھیں"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS پیغامات بھیجیں اور دیکھیں"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"اپنے رابطوں تک رسائی حاصل کریں"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"اپنے کیلنڈر تک رسائی حاصل کریں"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"آڈیو ریکارڈ کریں"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"قریبی آلات کی متعلقہ پوزیشن تلاش کریں، ان سے منسلک کریں اور اس کا تعین کریں"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"رابطوں، پیغامات اور تصاویر جیسی معلومات سمیت تمام اطلاعات پڑھیں"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• تمام اطلاعات کو پڑھیں، بشمول رابطے، پیغامات اور تصاویر<br/>• اطلاعات بھیجیں<br/><br/>آپ ترتیبات > اطلاعات میں کسی بھی وقت اس ایپ کی اطلاعات کو پڑھنے اور بھیجنے کی اہلیت کا نظم کر سکتے ہیں۔"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml index 16a7d1d10c10..8defcbc82e53 100644 --- a/packages/CompanionDeviceManager/res/values-uz/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Atrofdagi qurilmalar"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Media chiqishini tanlash"</string> <string name="permission_storage" msgid="6831099350839392343">"Suratlar va media"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Bildirishnomalar"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Ilovalar"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Striming"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Telefon qilish va chaqiruvlarni boshqarish"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Telefon chaqiruvlari jurnalini koʻrish va oʻzgartirish"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"SMS yuborish va ularni oʻqish"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Kontaktlar bilan ishlash"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Taqvim bilan ishlash"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Audio yozib olish"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Atrofdagi qurilmalarni qidirish, joylashuvini aniqlash va ularga ulanish"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqish"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqish<br/>• Bildirishnoma yuborish<br/><br/>Ilovaning bildirishnomalarga ruxsatini istalgan vaqt Sozlamalar > Bildirishnomalar orqali boshqarish mumkin."</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml index a080a5c02b4c..779700824fbf 100644 --- a/packages/CompanionDeviceManager/res/values-vi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml @@ -54,36 +54,24 @@ <string name="permission_microphone" msgid="2152206421428732949">"Micrô"</string> <string name="permission_call_logs" msgid="5546761417694586041">"Nhật ký cuộc gọi"</string> <string name="permission_nearby_devices" msgid="7530973297737123481">"Thiết bị ở gần"</string> - <!-- no translation found for permission_media_routing_control (5498639511586715253) --> - <skip /> + <string name="permission_media_routing_control" msgid="5498639511586715253">"Thay đổi đầu ra đa phương tiện"</string> <string name="permission_storage" msgid="6831099350839392343">"Ảnh và nội dung nghe nhìn"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Thông báo"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Ứng dụng"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Truyền trực tuyến"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Gọi và quản lý cuộc gọi điện thoại"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Đọc và ghi nhật ký cuộc gọi điện thoại"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Gửi và xem tin nhắn SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Truy cập vào danh bạ của bạn"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Truy cập lịch của bạn"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Ghi âm"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Tìm, kết nối và xác định vị trí tương đối của các thiết bị ở gần"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Đọc tất cả thông báo, kể cả những thông tin như danh bạ, tin nhắn và ảnh"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Đọc tất cả thông báo, kể cả những thông tin như danh bạ, tin nhắn và ảnh<br/>• Gửi thông báo<br/><br/>Bạn có thể quản lý tính năng đọc và gửi thông báo của ứng dụng này bất cứ lúc nào trong phần Cài đặt > Thông báo."</string> <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 permission_media_routing_control_summary (2714631092321412250) --> - <skip /> + <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Truy cập danh sách thiết bị hiện có và kiểm soát việc thiết bị nào sẽ phát trực tuyến hoặc truyền âm thanh hoặc video từ các ứng dụng khác"</string> <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 aaa5bef42798..11e3332f2758 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"附近的设备"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"更改媒体输出"</string> <string name="permission_storage" msgid="6831099350839392343">"照片和媒体内容"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"通知"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"应用"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"流式传输"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"拨打电话和管理通话"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"读取和写入手机通话记录"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"发送和查看短信"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"访问您的通讯录"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"访问您的日历"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"录音"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"查找、连接附近的设备以及确定附近设备的相对位置"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"读取所有通知,包括通讯录、消息和照片等信息"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• 读取所有通知,包括通讯录、消息和照片等信息<br/>• 发送通知<br/><br/>您随时可以依次前往“设置”>“通知”并在其中管理此应用读取和发送通知的权限。"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml index 7c286230ade3..e340d5a91c13 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"附近的裝置"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"變更媒體輸出"</string> <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"通知"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"應用程式"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"串流"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"撥打及管理通話"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"讀取及寫入手機通話記錄"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"傳送和查看短訊"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"存取你的通訊錄"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"存取你的日曆"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"錄音"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"尋找、連接及判斷附近裝置的相對位置"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"讀取所有通知,包括聯絡人、訊息和相片等資訊"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• 讀取所有通知,包括聯絡人、訊息和相片等資訊<br/>• 傳送通知<br/><br/>你隨時可前往 [設定] > [通知],管理此應用程式讀取和傳送通知的功能。"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml index fa2d60ce76a7..82ad021a082b 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"鄰近裝置"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"變更媒體輸出"</string> <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"通知"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"應用程式"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"串流"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"撥打電話及管理通話"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"讀取及寫入通話記錄"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"傳送及查看簡訊"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"存取你的聯絡人"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"存取你的日曆"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"錄音"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"尋找、連線及判斷鄰近裝置的相對位置"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"讀取所有通知,包括聯絡人、訊息和相片等資訊"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• 讀取所有通知,包括聯絡人、訊息和相片等資訊<br/>• 傳送通知<br/><br/>你隨時可以前往「設定」>「通知」,管理這個應用程式讀取和傳送通知的功能。"</string> <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> diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml index 2d9087206b33..c35ff6aaa3bf 100644 --- a/packages/CompanionDeviceManager/res/values-zu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml @@ -56,28 +56,18 @@ <string name="permission_nearby_devices" msgid="7530973297737123481">"Amadivayisi aseduze"</string> <string name="permission_media_routing_control" msgid="5498639511586715253">"Shintsha umphumela wemidiya"</string> <string name="permission_storage" msgid="6831099350839392343">"Izithombe nemidiya"</string> - <!-- no translation found for permission_notifications (4099418516590632909) --> - <skip /> + <string name="permission_notifications" msgid="4099418516590632909">"Izaziso"</string> <string name="permission_app_streaming" msgid="6009695219091526422">"Ama-app"</string> <string name="permission_nearby_device_streaming" msgid="1023325519477349499">"Iyasakaza"</string> - <!-- no translation found for permission_phone_summary (8246321093970051702) --> - <skip /> - <!-- no translation found for permission_call_logs_summary (7545243592757693321) --> - <skip /> - <!-- no translation found for permission_sms_summary (8499509535410068616) --> - <skip /> - <!-- no translation found for permission_contacts_summary (2840800622763086808) --> - <skip /> - <!-- no translation found for permission_calendar_summary (8430353935747336165) --> - <skip /> - <!-- no translation found for permission_microphone_summary (4862628553869973259) --> - <skip /> - <!-- no translation found for permission_nearby_devices_summary (1306752848196464817) --> - <skip /> - <!-- no translation found for permission_notification_listener_access_summary (7856071768185367749) --> - <skip /> - <!-- no translation found for permission_notifications_summary (2272810466047367030) --> - <skip /> + <string name="permission_phone_summary" msgid="8246321093970051702">"Yenza futhi ulawule amakholi efoni"</string> + <string name="permission_call_logs_summary" msgid="7545243592757693321">"Funda futhi ubhale irekhodi lamakholi efoni"</string> + <string name="permission_sms_summary" msgid="8499509535410068616">"Thumela futhi ubuke imiyalezo ye-SMS"</string> + <string name="permission_contacts_summary" msgid="2840800622763086808">"Finyelela koxhumana nabo"</string> + <string name="permission_calendar_summary" msgid="8430353935747336165">"Finyelela ikhalenda lakho"</string> + <string name="permission_microphone_summary" msgid="4862628553869973259">"Rekhoda umsindo"</string> + <string name="permission_nearby_devices_summary" msgid="1306752848196464817">"Thola, uxhume, futhi unqume indawo yamadivayisi aseduze"</string> + <string name="permission_notification_listener_access_summary" msgid="7856071768185367749">"Funda zonke izaziso, okuhlanganisa ulwazi loxhumana nabo, imiyalezo, nezithombe"</string> + <string name="permission_notifications_summary" msgid="2272810466047367030">"• Funda zonke izaziso, okuhlanganisa ulwazi loxhumana nabo, imiyalezo, nezithombe<br/>•Thumela izaziso<br/><br/>Ungakwazi ukulawula ikhono lale app lokufunda nokuthumela izaziso noma nini kokuthi Amasethingi Nezaziso."</string> <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> diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index a78509d897aa..c0d71494e020 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -53,6 +53,7 @@ class CredentialManagerRepo( isNewActivity: Boolean, ) { val requestInfo: RequestInfo? + var isReqForAllOptions: Boolean = false private val providerEnabledList: List<ProviderData> private val providerDisabledList: List<DisabledProviderData>? val resultReceiver: ResultReceiver? @@ -102,6 +103,11 @@ class CredentialManagerRepo( ResultReceiver::class.java ) + isReqForAllOptions = intent.getBooleanExtra( + Constants.EXTRA_REQ_FOR_ALL_OPTIONS, + /*defaultValue=*/ false + ) + val cancellationRequest = getCancelUiRequest(intent) val cancelUiRequestState = cancellationRequest?.let { CancelUiRequestState(getAppLabel(context.getPackageManager(), it.appPackageName)) @@ -141,7 +147,8 @@ class CredentialManagerRepo( ) } RequestInfo.TYPE_GET -> { - val getCredentialInitialUiState = getCredentialInitialUiState(originName)!! + val getCredentialInitialUiState = getCredentialInitialUiState(originName, + isReqForAllOptions)!! val autoSelectEntry = findAutoSelectEntry(getCredentialInitialUiState.providerDisplayInfo) UiState( @@ -216,14 +223,18 @@ class CredentialManagerRepo( } // IMPORTANT: new invocation should be mindful that this method can throw. - private fun getCredentialInitialUiState(originName: String?): GetCredentialUiState? { + private fun getCredentialInitialUiState( + originName: String?, + isReqForAllOptions: Boolean + ): GetCredentialUiState? { val providerEnabledList = GetFlowUtils.toProviderList( providerEnabledList as List<GetCredentialProviderData>, context ) val requestDisplayInfo = GetFlowUtils.toRequestDisplayInfo(requestInfo, context, originName) return GetCredentialUiState( - providerEnabledList, - requestDisplayInfo ?: return null, + isReqForAllOptions, + providerEnabledList, + requestDisplayInfo ?: return null ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt index 0ff1c7fd8953..dfa5735fcaec 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt @@ -19,16 +19,18 @@ package com.android.credentialmanager.autofill import android.R import android.app.assist.AssistStructure import android.content.Context -import android.credentials.CredentialManager -import android.credentials.CredentialOption -import android.credentials.GetCandidateCredentialsException -import android.credentials.GetCandidateCredentialsResponse +import android.app.PendingIntent +import android.credentials.GetCredentialResponse import android.credentials.GetCredentialRequest -import android.credentials.ui.GetCredentialProviderData +import android.credentials.GetCandidateCredentialsResponse +import android.credentials.GetCandidateCredentialsException +import android.credentials.CredentialOption import android.graphics.drawable.Icon +import android.credentials.ui.GetCredentialProviderData import android.os.Bundle import android.os.CancellationSignal import android.os.OutcomeReceiver +import android.credentials.Credential import android.service.autofill.AutofillService import android.service.autofill.Dataset import android.service.autofill.Field @@ -41,8 +43,11 @@ import android.service.autofill.SaveCallback import android.service.autofill.SaveRequest import android.service.credentials.CredentialProviderService import android.util.Log +import android.view.autofill.AutofillValue +import android.view.autofill.IAutoFillManagerClient import android.view.autofill.AutofillId import android.widget.inline.InlinePresentationSpec +import android.credentials.CredentialManager import androidx.autofill.inline.v1.InlineSuggestionUi import androidx.credentials.provider.CustomCredentialEntry import androidx.credentials.provider.PasswordCredentialEntry @@ -58,11 +63,13 @@ import org.json.JSONException import org.json.JSONObject import java.util.concurrent.Executors + class CredentialAutofillService : AutofillService() { companion object { private const val TAG = "CredAutofill" + private const val SESSION_ID_KEY = "session_id" private const val CRED_HINT_PREFIX = "credential=" private const val REQUEST_DATA_KEY = "requestData" private const val CANDIDATE_DATA_KEY = "candidateQueryData" @@ -77,10 +84,27 @@ class CredentialAutofillService : AutofillService() { cancellationSignal: CancellationSignal, callback: FillCallback ) { + } + + override fun onFillCredentialRequest( + request: FillRequest, + cancellationSignal: CancellationSignal, + callback: FillCallback, + autofillCallback: IAutoFillManagerClient + ) { val context = request.fillContexts val structure = context[context.size - 1].structure val callingPackage = structure.activityComponent.packageName - Log.i(TAG, "onFillRequest called for $callingPackage") + Log.i(TAG, "onFillCredentialRequest called for $callingPackage") + + var sessionId = request.clientState?.getInt(SESSION_ID_KEY) + + Log.i(TAG, "Autofill sessionId: " + sessionId) + if (sessionId == null) { + Log.i(TAG, "Session Id not found") + callback.onFailure("Session Id not found") + return + } val getCredRequest: GetCredentialRequest? = getCredManRequest(structure) if (getCredRequest == null) { @@ -95,7 +119,31 @@ class CredentialAutofillService : AutofillService() { GetCandidateCredentialsException> { override fun onResult(result: GetCandidateCredentialsResponse) { Log.i(TAG, "getCandidateCredentials onResponse") - val fillResponse = convertToFillResponse(result, request) + + if (result.getCredentialResponse != null) { + val autofillId: AutofillId? = result.getCredentialResponse + .credential.data.getParcelable( + CredentialProviderService.EXTRA_AUTOFILL_ID, + AutofillId::class.java) + Log.i(TAG, "getCandidateCredentials final response, autofillId: " + + autofillId) + + if (autofillId != null) { + autofillCallback.autofill( + sessionId, + mutableListOf(autofillId), + mutableListOf( + AutofillValue.forText( + convertResponseToJson(result.getCredentialResponse) + ) + ), + false) + } + return + } + + val fillResponse = convertToFillResponse(result, request, + this@CredentialAutofillService) if (fillResponse != null) { callback.onSuccess(fillResponse) } else { @@ -115,10 +163,62 @@ class CredentialAutofillService : AutofillService() { callingPackage, CancellationSignal(), Executors.newSingleThreadExecutor(), - outcome + outcome, + autofillCallback ) } + // TODO(b/318118018): Use from Jetpack + private fun convertResponseToJson(response: GetCredentialResponse): String? { + try { + val jsonObject = JSONObject() + jsonObject.put("type", "get") + val jsonCred = JSONObject() + jsonCred.put("type", response.credential.type) + jsonCred.put("data", credentialToJSON( + response.credential)) + jsonObject.put("credential", jsonCred) + return jsonObject.toString() + } catch (e: JSONException) { + Log.i( + TAG, "Exception while constructing response JSON: " + + e.message + ) + } + return null + } + + // TODO(b/318118018): Replace with calls to Jetpack + private fun credentialToJSON(credential: Credential): JSONObject? { + Log.i(TAG, "credentialToJSON") + try { + if (credential.type == "android.credentials.TYPE_PASSWORD_CREDENTIAL") { + Log.i(TAG, "toJSON PasswordCredential") + + val json = JSONObject() + val id = credential.data.getString("androidx.credentials.BUNDLE_KEY_ID") + val pass = credential.data.getString("androidx.credentials.BUNDLE_KEY_PASSWORD") + json.put("androidx.credentials.BUNDLE_KEY_ID", id) + json.put("androidx.credentials.BUNDLE_KEY_PASSWORD", pass) + return json + } else if (credential.type == "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL") { + Log.i(TAG, "toJSON PublicKeyCredential") + + val json = JSONObject() + val responseJson = credential + .data + .getString("androidx.credentials.BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON") + json.put("androidx.credentials.BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON", + responseJson) + return json + } + } catch (e: JSONException) { + Log.i(TAG, "issue while converting credential response to JSON") + } + Log.i(TAG, "Unsupported credential type") + return null + } + private fun getEntryToIconMap( candidateProviderDataList: MutableList<GetCredentialProviderData> ): Map<String, Icon> { @@ -150,14 +250,16 @@ class CredentialAutofillService : AutofillService() { private fun convertToFillResponse( getCredResponse: GetCandidateCredentialsResponse, - filLRequest: FillRequest + filLRequest: FillRequest, + context: Context ): FillResponse? { val providerList = GetFlowUtils.toProviderList( getCredResponse.candidateProviderDataList, - this@CredentialAutofillService) + context) if (providerList.isEmpty()) { return null } + val entryIconMap: Map<String, Icon> = getEntryToIconMap(getCredResponse.candidateProviderDataList) val autofillIdToProvidersMap: Map<AutofillId, List<ProviderInfo>> = @@ -166,7 +268,8 @@ class CredentialAutofillService : AutofillService() { var validFillResponse = false autofillIdToProvidersMap.forEach { (autofillId, providers) -> validFillResponse = processProvidersForAutofillId( - filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder) + filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder, + getCredResponse.pendingIntent) .or(validFillResponse) } if (!validFillResponse) { @@ -180,7 +283,8 @@ class CredentialAutofillService : AutofillService() { autofillId: AutofillId, providerList: List<ProviderInfo>, entryIconMap: Map<String, Icon>, - fillResponseBuilder: FillResponse.Builder + fillResponseBuilder: FillResponse.Builder, + bottomSheetPendingIntent: PendingIntent? ): Boolean { if (providerList.isEmpty()) { return false @@ -227,9 +331,9 @@ class CredentialAutofillService : AutofillService() { ?: getDefaultIcon() } // Create inline presentation - var inlinePresentation: InlinePresentation? = null; + var inlinePresentation: InlinePresentation? = null + var spec: InlinePresentationSpec? if (inlinePresentationSpecs != null) { - val spec: InlinePresentationSpec if (i < inlinePresentationSpecsCount) { spec = inlinePresentationSpecs[i] } else { @@ -265,9 +369,52 @@ class CredentialAutofillService : AutofillService() { .build()) datasetAdded = true } + val pinnedSpec = getLastInlinePresentationSpec(inlinePresentationSpecs, + inlinePresentationSpecsCount) + if (datasetAdded && bottomSheetPendingIntent != null && pinnedSpec != null) { + addPinnedInlineSuggestion(bottomSheetPendingIntent, pinnedSpec, autofillId, + fillResponseBuilder) + } return datasetAdded } + private fun getLastInlinePresentationSpec( + inlinePresentationSpecs: List<InlinePresentationSpec>?, + inlinePresentationSpecsCount: Int + ): InlinePresentationSpec? { + if (inlinePresentationSpecs != null) { + return inlinePresentationSpecs[inlinePresentationSpecsCount - 1] + } + return null + } + + private fun addPinnedInlineSuggestion( + bottomSheetPendingIntent: PendingIntent, + spec: InlinePresentationSpec, + autofillId: AutofillId, + fillResponseBuilder: FillResponse.Builder + ) { + val dataSetBuilder = Dataset.Builder() + val sliceBuilder = InlineSuggestionUi + .newContentBuilder(bottomSheetPendingIntent) + .setStartIcon(Icon.createWithResource(this, + com.android.credentialmanager.R.drawable.ic_other_sign_in_24)) + val presentationBuilder = Presentations.Builder() + .setInlinePresentation(InlinePresentation( + sliceBuilder.build().slice, spec, /* pinned= */ true)) + + fillResponseBuilder.addDataset( + dataSetBuilder + .setField( + autofillId, + Field.Builder().setPresentations( + presentationBuilder.build()) + .build()) + .setAuthentication(bottomSheetPendingIntent.intentSender) + .build() + ) + } + /** * Maps Autofill Id to provider list. For example, passing in a provider info * diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt index 46bebc4073ab..a291f59021f0 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt @@ -26,10 +26,12 @@ import com.android.credentialmanager.model.get.RemoteEntryInfo import com.android.internal.util.Preconditions data class GetCredentialUiState( + val isRequestForAllOptions: Boolean, val providerInfoList: List<ProviderInfo>, val requestDisplayInfo: RequestDisplayInfo, val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList), - val currentScreenState: GetScreenState = toGetScreenState(providerDisplayInfo), + val currentScreenState: GetScreenState = toGetScreenState( + providerDisplayInfo, isRequestForAllOptions), val activeEntry: EntryInfo? = toActiveEntry(providerDisplayInfo), val isNoAccount: Boolean = false, ) @@ -184,7 +186,8 @@ private fun toActiveEntry( } private fun toGetScreenState( - providerDisplayInfo: ProviderDisplayInfo + providerDisplayInfo: ProviderDisplayInfo, + isRequestForAllOptions: Boolean ): GetScreenState { return if (providerDisplayInfo.sortedUserNameToCredentialEntryList.isEmpty() && providerDisplayInfo.remoteEntry == null && @@ -194,6 +197,8 @@ private fun toGetScreenState( providerDisplayInfo.authenticationEntryList.isEmpty() && providerDisplayInfo.remoteEntry != null) GetScreenState.REMOTE_ONLY + else if (isRequestForAllOptions) + GetScreenState.ALL_SIGN_IN_OPTIONS else GetScreenState.PRIMARY_SELECTION } diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml index 25afe999b406..acd16b948152 100644 --- a/packages/PackageInstaller/res/values-af/strings.xml +++ b/packages/PackageInstaller/res/values-af/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Hierdie gebruiker kan nie onbekende programme installeer nie"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Hierdie gebruiker word nie toegelaat om programme te installeer nie"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Argiveer"</string> <string name="update_anyway" msgid="8792432341346261969">"Dateer in elk geval op"</string> <string name="manage_applications" msgid="5400164782453975580">"Bestuur programme"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Geen spasie oor nie"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Deïnstalleer opdatering"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> is deel van die volgende program:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Wil jy hierdie program deïnstalleer?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Jou persoonlike data sal gestoor word"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Argiveer hierdie app vir alle gebruikers? Jou persoonlike data sal gestoor word"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Argiveer hierdie app op jou werkprofiel? Jou persoonlike data sal gestoor word"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Argiveer hierdie app vir <xliff:g id="USERNAME">%1$s</xliff:g>? Jou persoonlike data sal gestoor word"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Wil jy hierdie app wat in jou privaat ruimte is, argiveer? Jou persoonlike data sal gestoor word"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Wil jy hierdie program vir "<b>"alle"</b>" gebruikers deïnstalleer? Die program en sy data sal van "<b>"alle"</b>" gebruikers op hierdie toestel verwyder word."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Wil jy hierdie program vir die gebruiker <xliff:g id="USERNAME">%1$s</xliff:g> deïnstalleer?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Wil jy hierdie program op jou werkprofiel deïnstalleer?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Jou tablet en persoonlike data is meer kwesbaar vir aanvalle deur onbekende programme. Deur hierdie program te installeer, stem jy in dat jy verantwoordelik is vir enige skade aan jou tablet of verlies van data wat uit sy gebruik kan spruit."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Jou TV en persoonlike data is meer kwesbaar vir aanvalle deur onbekende programme. Deur hierdie program te installeer, stem jy in dat jy verantwoordelik is vir enige skade aan jou TV of verlies van data wat uit sy gebruik kan spruit."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-kloon"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Argiveer <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Gaan voort"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Instellings"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Installeer/deïnstalleer Wear-programme"</string> diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml index f47ec6a22a0d..d2e8400ee489 100644 --- a/packages/PackageInstaller/res/values-am/strings.xml +++ b/packages/PackageInstaller/res/values-am/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ያልታወቁ መተግበሪያዎች በዚህ ተጠቃሚ ሊጫኑ አይችሉም"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ይህ ተጠቃሚ መተግበሪያዎችን እንዲጭን አልተፈቀደለትም"</string> <string name="ok" msgid="7871959885003339302">"እሺ"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"በማህደር አስቀምጥ"</string> <string name="update_anyway" msgid="8792432341346261969">"የሆነው ሆኖ አዘምን"</string> <string name="manage_applications" msgid="5400164782453975580">"መተግበሪያዎችን ያቀናብሩ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ቦታ ሞልቷል"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"ዝማኔን አራግፍ"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> የሚከተለው መተግበሪያ አካል ነው፦"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ይህን መተግበሪያ ማራገፍ ይፈልጋሉ?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"የግል ውሂብዎ ይቀመጣል"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"ይህ መተግበሪያ ለሁሉም ተጠቃሚዎች በማህደር ይቀመጥ? የግል ውሂብዎ ይቀመጣል"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ይህ መተግበሪያ በስራ መገለጫዎ ላይ በማህደር ይቀመጥ? የግል ውሂብዎ ይቀመጣል"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"ይህ መተግበሪያ ለ<xliff:g id="USERNAME">%1$s</xliff:g> በማህደር ይቀመጥ? የግል ውሂብዎ ይቀመጣል"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ይህን መተግበሪያ ከግል ቦታዎ በማህደር ማስቀመጥ ይፈልጋሉ? የግል ውሂብዎ ይቀመጣል"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"ይህን መተግበሪያ "<b>"ለሁሉም"</b>" ተጠቃሚዎች መጫን ይፈልጋሉ? መተግበሪያው እና ውሂቡ በመሣሪያው ላይ ካሉ "<b>"ሁሉም"</b>" ተጠቃሚዎች ይሰረዛሉ።"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"ይህን መተግበሪያ ለተጠቃሚ <xliff:g id="USERNAME">%1$s</xliff:g> ማራገፍ ይፈልጋሉ?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ይህን መተግበሪያ ከስራ መገለጫዎ ማራገፍ ይፈልጋሉ?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"የእርስዎ ጡባዊ እና የግል ውሂብ በማይታወቁ መተግበሪያዎች ለሚደርሱ ጥቃቶች በይበልጥ ተጋላጭ ናቸው። ይህን መተግበሪያ በመጫንዎ በእርስዎ ጡባዊ ላይ ለሚደርስ ማናቸውም ጉዳት ወይም መተግበሪያውን በመጠቀም ለሚከሰት የውሂብ መጥፋት ኃላፊነቱን እንደሚወስዱ ተስማምተዋል።"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"የእርስዎ ቴሌቪዥን እና የግል ውሂብ በማይታወቁ መተግበሪያዎች ለሚደርሱ ጥቃቶች በይበልጥ ተጋላጭ ናቸው። ይህን መተግበሪያ በመጫንዎ በእርስዎ ቴሌቪዥን ላይ ለሚደርስ ማናቸውም ጉዳት ወይም መተግበሪያውን በመጠቀም ለሚከሰት የውሂብ መጥፋት ኃላፊነቱን እንደሚወስዱ ተስማምተዋል።"</string> <string name="cloned_app_label" msgid="7503612829833756160">"የተባዛ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> በማህደር ይቀመጥ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ቀጥል"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ቅንብሮች"</string> <string name="wear_app_channel" msgid="1960809674709107850">"የWear መተግበሪያዎችን መጫን/ማራገፍ"</string> diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml index 62a55dce3002..8a253a317a64 100644 --- a/packages/PackageInstaller/res/values-as/strings.xml +++ b/packages/PackageInstaller/res/values-as/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"এই ব্যৱহাৰকাৰীয়ে অজ্ঞাত উৎসৰপৰা পোৱা এপ্সমূহ ইনষ্টল কৰিব নোৱাৰে"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"এই ব্যৱহাৰকাৰীজনৰ এপ্ ইনষ্টল কৰাৰ অনুমতি নাই"</string> <string name="ok" msgid="7871959885003339302">"ঠিক আছে"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"আৰ্কাইভ কৰক"</string> <string name="update_anyway" msgid="8792432341346261969">"যিকোনো প্ৰকাৰে আপডে’ট কৰক"</string> <string name="manage_applications" msgid="5400164782453975580">"এপ্ পৰিচালনা"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"খালী ঠাই নাই"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"আপডে’ট আনইনষ্টল কৰক"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> হৈছে তলৰ এপ্টোৰ এটা অংশ:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"আপুনি এই এপ্টো আনইনষ্টল কৰিব বিচাৰে নেকি?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"আপোনাৰ ব্যক্তিগত ডেটা ছেভ কৰা হ’ব"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"সকলো ব্যৱহাৰকাৰীৰ বাবে এই এপ্টো আৰ্কাইভ কৰিবনে? আপোনাৰ ব্যক্তিগত ডেটা ছেভ কৰা হ’ব"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইলত এই এপ্টো আৰ্কাইভ কৰিবনে? আপোনাৰ ব্যক্তিগত ডেটা ছেভ কৰা হ’ব"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g>ৰ বাবে এই এপ্টো আৰ্কাইভ কৰিবনে? আপোনাৰ ব্যক্তিগত ডেটা ছেভ কৰা হ’ব"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"আপুনি আপোনাৰ ব্যক্তিগত স্পেচৰ পৰা এই এপ্টো আৰ্কাইভ কৰিব বিচাৰেনে? আপোনাৰ ব্যক্তিগত ডেটা ছেভ কৰা হ’ব"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"আপুনি "<b>"সকলো"</b>" ব্যৱহাৰকাৰীৰ বাবে এই এপ্টো আনইনষ্টল কৰিব বিচাৰেনে? এপ্লিকেশ্বন আৰু ইয়াৰ ডেটা ডিভাইচটোত থকা "<b>"সকলো"</b>" ব্যৱহাৰকাৰীৰ পৰা আঁতৰোৱা হ\'ব৷"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"আপুনি ব্যৱহাৰকাৰীৰ <xliff:g id="USERNAME">%1$s</xliff:g> বাবে এই এপ্টো আনইনষ্টল কৰিব বিচাৰেনে?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"আপুনি নিজৰ কৰ্মস্থানৰ প্ৰ’ফাইলৰ পৰা এই এপ্টো আনইনষ্টল কৰিব বিচাৰেনে?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"আপোনাৰ টেবলেট আৰু ব্যক্তিগত ডেটা অজ্ঞাত এপৰ আক্ৰমণৰ বলি হোৱাৰ সম্ভাৱনা অধিক। আপুনি এই এপ্টো ইনষ্টল কৰি এপ্টোৰ ব্যৱহাৰৰ ফলত আপোনাৰ টিভিত হ\'ব পৰা যিকোনো ক্ষতি বা ডেটা ক্ষয়ৰ বাবে আপুনি নিজে দায়ী হ\'ব বুলি সন্মতি দিয়ে।"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"আপোনাৰ টিভি আৰু ব্যক্তিগত ডেটা অজ্ঞাত এপৰ আক্ৰমণৰ বলি হোৱাৰ সম্ভাৱনা অধিক। আপুনি এই এপ্টো ইনষ্টল কৰি এপ্টোৰ ব্যৱহাৰৰ ফলত আপোনাৰ টিভিত হ\'ব পৰা যিকোনো ক্ষতি বা ডেটা ক্ষয়ৰ বাবে আপুনি নিজে দায়ী হ\'ব বুলি সন্মতি দিয়ে।"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>ৰ ক্ল’ন"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> আৰ্কাইভ কৰিবনে?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"অব্যাহত ৰাখক"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ছেটিং"</string> <string name="wear_app_channel" msgid="1960809674709107850">"ৱেৰ এপ্সমূহ ইনষ্টল/আনইনষ্টল কৰি থকা হৈছে"</string> diff --git a/packages/PackageInstaller/res/values-az/strings.xml b/packages/PackageInstaller/res/values-az/strings.xml index f5e3974abf9c..e946326bc08c 100644 --- a/packages/PackageInstaller/res/values-az/strings.xml +++ b/packages/PackageInstaller/res/values-az/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Naməlum tətbiqlər bu istifadəçi tərəfindən quraşdırıla bilməz"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Bu istifadəçinin tətbiqi quraşdırmaq üçün icazəsi yoxdur"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arxivə atın"</string> <string name="update_anyway" msgid="8792432341346261969">"İstənilən halda güncəlləyin"</string> <string name="manage_applications" msgid="5400164782453975580">"Tətbiqi idarə edin"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Boş yer yoxdur"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Güncəlləməni silin"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> bu tətbiqin hissəsidir:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Bu tətbiqi sistemdən silmək istəyirsiniz?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Şəxsi məlumatlarınız yadda saxlanacaq"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Bu tətbiq bütün istifadəçilər üçün arxivə atılsın? Şəxsi məlumatlarınız yadda saxlanacaq"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Bu tətbiq iş profilində arxivə atılsın? Şəxsi məlumatlarınız yadda saxlanacaq"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Bu tətbiq <xliff:g id="USERNAME">%1$s</xliff:g> üçün arxivə atılsın? Şəxsi məlumatlarınız yadda saxlanacaq"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Bu tətbiqi şəxsi sahədən arxivə atmaq istəyirsiniz? Şəxsi məlumatlarınız yadda saxlanacaq"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bu tətbiqi "<b>"bütün"</b>" istifadəçilər üçün silmək istəyirsiz? Tətbiq və onun datası cihazdakı "<b>"bütün"</b>" istifadəçilər üçün silinəcək."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> adlı istifadəçi üçün bu tətbiqi sistemdən silmək istəyirsiniz?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu tətbiqi iş profilinizdən silmək istəyirsiniz?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Planşet və şəxsi data naməlum tətbiqlərin hücumuna qarşı daha həssasdır. Bu tətbiqi quraşdırmaqla planşetə dəyə biləcək zərər və ya onun istifadəsi nəticəsində baş verə biləcək data itkisinə görə məsuliyyət daşıdığınızı qəbul edirsiniz."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Tv və şəxsi data naməlum tətbiqlərin hücumuna qarşı daha həssasdır. Bu tətbiqi quraşdırmaqla Tv-yə dəyə biləcək zərər və ya onun istifadəsi nəticəsində baş verən data itkisinə görə məsuliyyət daşıdığınızı qəbul edirsiniz."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> Kopyalayın"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> arxivə atılsın?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Davam edin"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Ayarlar"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear tətbiqləri quraşdırılır/sistemdən silinir"</string> diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml index 111d90bb9578..562732412a11 100644 --- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml +++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ovaj korisnik ne može da instalira nepoznate aplikacije"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ovom korisniku nije dozvoljeno da instalira aplikacije"</string> <string name="ok" msgid="7871959885003339302">"Potvrdi"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arhiviraj"</string> <string name="update_anyway" msgid="8792432341346261969">"Ipak ažuriraj"</string> <string name="manage_applications" msgid="5400164782453975580">"Upravljajte apl."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nema više prostora"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Deinstaliraj ažuriranje"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> je deo sledeće aplikacije:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Želite da deinstalirate ovu aplikaciju?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Lični podaci će biti sačuvani"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Želite li da arhivirate ovu aplikaciju za sve korisnike? Lični podaci će biti sačuvani"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Želite li da arhivirate ovu aplikaciju sa poslovnog profila? Lični podaci će biti sačuvani"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Želite li da arhivirate ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>? Lični podaci će biti sačuvani"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Želite li da arhivirate ovu aplikaciju iz privatnog prostora? Lični podaci će biti sačuvani"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Da li želite da deinstalirate ovu aplikaciju za "<b>"sve"</b>" korisnike? Aplikacija i podaci uz nje biće uklonjeni za "<b>"sve"</b>" korisnike ovog uređaja."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li da deinstalirate ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Da li želite da deinstalirate ovu aplikaciju sa poslovnog profila?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tablet i lični podaci su podložniji napadu nepoznatih aplikacija. Ako instalirate ovu aplikaciju, prihvatate da ste odgovorni za eventualna oštećenja tableta ili gubitak podataka do kojih može da dođe zbog njenog korišćenja."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV i lični podaci su podložniji napadu nepoznatih aplikacija. Ako instalirate ovu aplikaciju, prihvatate da ste odgovorni za eventualna oštećenja TV-a ili gubitak podataka do kojih može da dođe zbog njenog korišćenja."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon aplikacije <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Želite li da arhivirate <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Nastavi"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Podešavanja"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instaliranje/deinstaliranje Wear aplikac."</string> diff --git a/packages/PackageInstaller/res/values-be/strings.xml b/packages/PackageInstaller/res/values-be/strings.xml index d34ecb6c9665..dcf3ad7fb31b 100644 --- a/packages/PackageInstaller/res/values-be/strings.xml +++ b/packages/PackageInstaller/res/values-be/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Гэты карыстальнік не можа ўсталёўваць невядомыя праграмы"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Гэты карыстальнік не можа ўсталёўваць праграмы"</string> <string name="ok" msgid="7871959885003339302">"ОК"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Архіваваць"</string> <string name="update_anyway" msgid="8792432341346261969">"Усё роўна абнавіць"</string> <string name="manage_applications" msgid="5400164782453975580">"Кіраваць"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Не хапае месца"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Выдаліць абнаўленне"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> з\'яўляецца часткай наступнай праграмы:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Выдаліць гэту праграму?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Вашы асабістыя даныя будуць захаваны"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Архіваваць гэту праграму для ўсіх карыстальнікаў? Вашы асабістыя даныя будуць захаваны."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Архіваваць гэту праграму з вашага працоўнага профілю? Вашы асабістыя даныя будуць захаваны."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Архіваваць гэту праграму для карыстальніка <xliff:g id="USERNAME">%1$s</xliff:g>? Вашы асабістыя даныя будуць захаваны."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Архіваваць гэту праграму з вашай прыватнай прасторы? Вашы асабістыя даныя будуць захаваны."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Выдаліць гэту праграму для "<b>"ўсіх"</b>" карыстальнікаў? Праграма і яе даныя будуць выдалены для "<b>"ўсіх"</b>" карыстальнікаў прылады."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Хочаце выдаліць гэту праграму для карыстальніка <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Хочаце выдаліць гэту праграму з працоўнага профілю?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Ваш планшэт і асабістыя даныя больш прыступныя для атак невядомых праграм. Усталёўваючы гэту праграму, вы згаджаецеся з тым, што несяце адказнасць за любыя пашкоджанні планшэта ці страту даных, якія могуць адбыцца ў выніку выкарыстання гэтай праграмы."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Ваш тэлевізар і асабістыя даныя больш прыступныя для атак невядомых праграм. Усталёўваючы гэту праграму, вы згаджаецеся з тым, што несяце адказнасць за любыя пашкоджанні тэлевізара ці страту даных, якія могуць адбыцца ў выніку выкарыстання гэтай праграмы."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Клон \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\""</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Архіваваць праграму \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\"?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Далей"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Налады"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Усталяванне і выдаленне праграм Wear"</string> diff --git a/packages/PackageInstaller/res/values-bg/strings.xml b/packages/PackageInstaller/res/values-bg/strings.xml index e0cd7a0d4855..1d1607482653 100644 --- a/packages/PackageInstaller/res/values-bg/strings.xml +++ b/packages/PackageInstaller/res/values-bg/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Този потребител не може да инсталира неизвестни приложения"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Този потребител няма разрешение да инсталира приложения"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Архив"</string> <string name="update_anyway" msgid="8792432341346261969">"Актуализиране въпреки това"</string> <string name="manage_applications" msgid="5400164782453975580">"Прил.: Управл."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Няма място"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Деинст. на актуализацията"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> е част от следното приложение:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Искате ли да деинсталирате това приложение?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Личните ви данни ще бъдат запазени"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Да се архивира ли това приложение за всички потребители? Личните ви данни ще бъдат запазени"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Да се архивира ли това приложение в служебния ви потребителски профил? Личните ви данни ще бъдат запазени"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Да се архивира ли това приложение за <xliff:g id="USERNAME">%1$s</xliff:g>? Личните ви данни ще бъдат запазени"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Искате ли да архивирате това приложение от личното си пространство? Личните ви данни ще бъдат запазени"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Искате ли да деинсталирате това приложение за "<b>"всички"</b>" потребители? Приложението и данните му ще бъдат премахнати от "<b>"всички"</b>" потребители на устройството."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Искате ли да деинсталирате това приложение за потребителя <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Искате ли да деинсталирате това приложение от служебния си потребителски профил?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Таблетът и личните ви данни са по-уязвими към атаки от неизвестни приложения. С инсталирането на това приложение приемате, че носите отговорност при евентуална повреда на таблета или загуба на информация вследствие на използването на приложението."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Телевизорът и личните ви данни са по-уязвими към атаки от неизвестни приложения. С инсталирането на това приложение приемате, че носите отговорност при евентуална повреда на телевизора или загуба на информация вследствие на използването на приложението."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Копие на <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Да се архивира ли <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Напред"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Настройки"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Инсталир./деинсталир. на прилож. за Wear"</string> diff --git a/packages/PackageInstaller/res/values-bn/strings.xml b/packages/PackageInstaller/res/values-bn/strings.xml index bab2d08e7576..b6a36d27724f 100644 --- a/packages/PackageInstaller/res/values-bn/strings.xml +++ b/packages/PackageInstaller/res/values-bn/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"এই ব্যবহারকারী অজানা অ্যাপ ইনস্টল করতে পারেন না"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"এই ব্যবহারকারীর অ্যাপ ইনস্টল করার অনুমতি নেই"</string> <string name="ok" msgid="7871959885003339302">"ঠিক আছে"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"আর্কাইভ করুন"</string> <string name="update_anyway" msgid="8792432341346261969">"তবুও আপডেট করতে চাই"</string> <string name="manage_applications" msgid="5400164782453975580">"অ্যাপ পরিচালনা"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"জায়গা খালি নেই"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"আপডেট আনইনস্টল করুন"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> এই অ্যাপটির অংশ:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"আপনি কি এই অ্যাপটি আনইনস্টল করতে চান?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"আপনার ব্যক্তিগত ডেটা সেভ করা হবে"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"সব ব্যবহারকারীর জন্য এই অ্যাপ আর্কাইভ করতে চান? আপনার ব্যক্তিগত ডেটা সেভ করা হবে"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"আপনার অফিস প্রোফাইলে এই অ্যাপ আর্কাইভ করতে চান? আপনার ব্যক্তিগত ডেটা সেভ করা হবে"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g>-এর জন্য এই অ্যাপ আর্কাইভ করতে চান? আপনার ব্যক্তিগত ডেটা সেভ করা হবে"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"আপনার ব্যক্তিগত স্পেস থেকে এই অ্যাপ আর্কাইভ করতে চান? আপনার ব্যক্তিগত ডেটা সেভ করা হবে"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"আপনি কি "<b>"সব"</b>" ব্যবহারকারীর জন্য এই অ্যাপটিকে আনইনস্টল করতে চান? এই ডিভাইসের "<b>"সব"</b>" ব্যবহারকারীর ডেটা সহ এই অ্যাপ্লিকেশনটি সরিয়ে দেওয়া হবে।"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"আপনি কি <xliff:g id="USERNAME">%1$s</xliff:g>-এর জন্য এই অ্যাপটি আনইনস্টল করতে চান?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"আপনার অফিস প্রোফাইল থেকে এই অ্যাপ আনইনস্টল করতে চান?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"অজানা অ্যাপের দ্বারা আপনার ট্যাবলেট এবং ব্যক্তিগত ডেটা আক্রান্ত হওয়ার সম্ভাবনা বেশি থাকে। এই অ্যাপটি ইনস্টল করার মাধ্যমে আপনি সম্মত হচ্ছেন যে এটি ব্যবহারের ফলে আপনার ট্যাবলেটের বা ডেটার কোনও ক্ষতি হলে তার জন্য আপনিই দায়ী থাকবেন।"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"অজানা অ্যাপের দ্বারা আপনার টিভি এবং ব্যক্তিগত ডেটা আক্রান্ত হওয়ার সম্ভাবনা বেশি থাকে। এই অ্যাপটি ইনস্টল করার মাধ্যমে আপনি সম্মত হচ্ছেন যে এটি ব্যবহারের ফলে আপনার টিভি বা ডেটার কোনও ক্ষতি হলে তার জন্য আপনিই দায়ী থাকবেন।"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ক্লোন"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> আর্কাইভ করতে চান?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"চালিয়ে যান"</string> <string name="external_sources_settings" msgid="4046964413071713807">"সেটিংস"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear অ্যাপ ইনস্টল/আনইনস্টল করা হচ্ছে"</string> diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml index defb388a792b..9801e07fbac0 100644 --- a/packages/PackageInstaller/res/values-bs/strings.xml +++ b/packages/PackageInstaller/res/values-bs/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ovaj korisnik ne može instalirati nepoznate aplikacije"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ovom korisniku nije dozvoljeno instaliranje aplikacija"</string> <string name="ok" msgid="7871959885003339302">"Uredu"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arhiviraj"</string> <string name="update_anyway" msgid="8792432341346261969">"Ipak ažuriraj"</string> <string name="manage_applications" msgid="5400164782453975580">"Uprav. aplik."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nedostatak prostora"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Deinstaliraj ažuriranje"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> je dio sljedeće aplikacije:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Želite li deinstalirati ovu aplikaciju?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Vaši lični podaci će se sačuvati"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Arhivirati ovu aplikaciju za sve korisnike? Vaši lični podaci će se sačuvati"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arhivirati ovu aplikaciju na radni profil? Vaši lični podaci će se sačuvati"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Arhivirati ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>? Vaši lični podaci će se sačuvati"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Želite li arhivirati ovu aplikaciju iz privatnog prostora? Vaši lični podaci će se sačuvati"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Želite li deinstalirati ovu aplikaciju za "<b>" sve "</b>" korisnike? Aplikacija i njeni podaci će biti uklonjeni iz "<b>" svih "</b>" korisničkih računa na uređaju."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li deinstalirati ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Želite li deinstalirati ovu aplikaciju s radnog profila?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Vaši podaci na tabletu i vaši lični podaci izloženiji su napadima nepoznatih aplikacija. Instaliranjem ove aplikacije, prihvatate odgovornost za bilo kakvu štetu na tabletu ili gubitak podataka do kojih može doći korištenjem aplikacije."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Vaši podaci na TV-u i vaši lični podaci izloženiji su napadima nepoznatih aplikacija. Instaliranjem ove aplikacije, prihvatate odgovornost za bilo kakvu štetu na TV-u ili gubitak podataka do kojih može doći korištenjem aplikacije."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon aplikacije <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Arhivirati aplikaciju <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Nastavi"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Postavke"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instaliranje/deinstaliranje Wear aplik."</string> diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml index 50e105cade20..e4da2080e317 100644 --- a/packages/PackageInstaller/res/values-ca/strings.xml +++ b/packages/PackageInstaller/res/values-ca/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Aquest usuari no pot instal·lar aplicacions desconegudes"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Aquest usuari no té permís per instal·lar aplicacions"</string> <string name="ok" msgid="7871959885003339302">"D\'acord"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arxiva"</string> <string name="update_anyway" msgid="8792432341346261969">"Actualitza de tota manera"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestiona apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Espai esgotat"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Desinstal·la l\'actualització"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> forma part de l\'aplicació següent:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Vols desinstal·lar aquesta aplicació?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Les teves dades personals es desaran"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Vols arxivar aquesta aplicació per a tots els usuaris? Les teves dades personals es desaran."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Vols arxivar aquesta aplicació al teu perfil de treball? Les teves dades personals es desaran."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Vols arxivar aquesta aplicació per a <xliff:g id="USERNAME">%1$s</xliff:g>? Les teves dades personals es desaran."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Vols arxivar aquesta aplicació del teu espai privat? Les teves dades personals es desaran."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vols desinstal·lar aquesta aplicació per a "<b>"tots"</b>" els usuaris? L\'aplicació i les seves dades se suprimiran per a "<b>"tots"</b>" els usuaris del dispositiu."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Vols desinstal·lar aquesta aplicació per a l\'usuari <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vols desinstal·lar aquesta aplicació del teu perfil de treball?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"La tauleta i les dades personals són més vulnerables als atacs d\'aplicacions desconegudes. En instal·lar aquesta aplicació, acceptes que ets responsable de qualsevol dany que es produeixi a la tauleta o de la pèrdua de dades que pugui resultar del seu ús."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"El televisor i les dades personals són més vulnerables als atacs d\'aplicacions desconegudes. En instal·lar aquesta aplicació, acceptes que ets responsable de qualsevol dany que es produeixi al televisor o de la pèrdua de dades que pugui resultar del seu ús."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Vols arxivar <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continua"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Configuració"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instal·lant o desinstal·lant apps de Wear"</string> diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml index 3b204bee0643..5bdc12d63af0 100644 --- a/packages/PackageInstaller/res/values-cs/strings.xml +++ b/packages/PackageInstaller/res/values-cs/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Tento uživatel nemůže instalovat neznámé aplikace"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Tento uživatel nesmí instalovat aplikace"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archivovat"</string> <string name="update_anyway" msgid="8792432341346261969">"Přesto aktualizovat"</string> <string name="manage_applications" msgid="5400164782453975580">"Správa aplikací"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nedostatek místa"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Odinstalovat aktualizaci"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"Činnost <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> je součástí následující aplikace:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Chcete tuto aplikaci odinstalovat?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Vaše osobní údaje budou uloženy"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Archivovat tuto aplikaci pro všechny uživatele? Vaše osobní údaje budou uloženy"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Archivovat tuto aplikaci v pracovním profilu? Vaše osobní údaje budou uloženy"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Archivovat tuto aplikaci pro uživatele <xliff:g id="USERNAME">%1$s</xliff:g>? Vaše osobní údaje budou uloženy"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Chcete tuto aplikaci archivovat ze soukromého prostoru? Vaše osobní údaje budou uloženy"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcete tuto aplikaci odinstalovat "<b>"všem"</b>" uživatelům? Aplikace a její údaje budou odstraněny "<b>"všem"</b>" uživatelům tohoto zařízení."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Chcete tuto aplikaci pro uživatele <xliff:g id="USERNAME">%1$s</xliff:g> odinstalovat?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Chcete tuto aplikaci odinstalovat ze svého pracovního profilu?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tablet a osobní údaje jsou zranitelnější vůči útoku ze strany neznámých aplikací. Instalací této aplikace přijímáte odpovědnost za případné škody na tabletu nebo ztrátu dat, která může být používáním aplikace způsobena."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Televize a osobní údaje jsou zranitelnější vůči útoku ze strany neznámých aplikací. Instalací této aplikace přijímáte odpovědnost za případné škody na televizi nebo ztrátu dat, která může být používáním aplikace způsobena."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Archivovat aplikaci <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Pokračovat"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Nastavení"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instalace/odinstalace aplikací pro Wear"</string> diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml index d7819c77ed65..fb4a1d22e7d4 100644 --- a/packages/PackageInstaller/res/values-da/strings.xml +++ b/packages/PackageInstaller/res/values-da/strings.xml @@ -26,9 +26,9 @@ <string name="install_done" msgid="5987363587661783896">"Appen er installeret."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Vil du installere denne app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Vil du opdatere denne app?"</string> - <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Vil du opdatere denne app via <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Denne app modtager normalt opdateriner fra <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på din tablet fremover. Dette kan påvirke appfunktionaliteten.</p>"</string> - <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Vil du opdatere denne app via <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Denne app modtager normalt opdateriner fra <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på dit fjernsyn fremover. Dette kan påvirke appfunktionaliteten.</p>"</string> - <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Vil du opdatere denne app via <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Denne app modtager normalt opdateriner fra <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på din telefon fremover. Dette kan påvirke appfunktionaliteten.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Vil du opdatere denne app via <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Denne app modtager normalt opdateringer fra <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på din tablet fremover. Dette kan påvirke appfunktionaliteten.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Vil du opdatere denne app via <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Denne app modtager normalt opdateringer fra <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på dit fjernsyn fremover. Dette kan påvirke appfunktionaliteten.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Vil du opdatere denne app via <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Denne app modtager normalt opdateringer fra <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Hvis du opdaterer fra en anden kilde, vil du kunne modtage opdateringer fra en hvilken som helst kilde på din telefon fremover. Dette kan påvirke appfunktionaliteten.</p>"</string> <string name="install_failed" msgid="5777824004474125469">"Appen blev ikke installeret."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Pakken blev forhindret i at blive installeret."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"Appen blev ikke installeret, da pakken er i strid med en eksisterende pakke."</string> @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Denne bruger kan ikke installere ukendte apps"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Denne bruger har ikke tilladelse til at installere apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arkivér"</string> <string name="update_anyway" msgid="8792432341346261969">"Opdater alligevel"</string> <string name="manage_applications" msgid="5400164782453975580">"Administrer apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Der er ikke mere plads"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Afinstaller opdatering"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> er en del af følgende app:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Vil du afinstallere denne app?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Dine private data gemmes"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Vil du arkivere denne app for alle brugere? Dine private data gemmes"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Vil du arkivere denne app fra din arbejdsprofil? Dine private data gemmes"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Vil du arkivere denne app for <xliff:g id="USERNAME">%1$s</xliff:g>? Dine private data gemmes"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Vil du arkivere denne app fra dit private område? Dine private data gemmes"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vil du afinstallere denne app for "<b>"alle"</b>" brugere? Appen og dens data fjernes fra "<b>"alle"</b>" brugere på denne enhed."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Vil du afinstallere denne app for brugeren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vil du afinstallere denne app fra din arbejdsprofil?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Din tablet og dine personlige data er mere sårbare over for angreb fra ukendte apps. Når du installerer denne app, accepterer du, at du er ansvarlig for skader på din tablet eller tab af data, der kan skyldes brug af appen."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Dit fjernsyn og dine personlige data er mere sårbare over for angreb fra ukendte apps. Når du installerer denne app, accepterer du, at du er ansvarlig for skader på dit fjernsyn eller tab af data, der kan skyldes brug af appen."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon af <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Vil du arkivere <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Fortsæt"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Indstillinger"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Installerer/afinstallerer Wear-apps"</string> diff --git a/packages/PackageInstaller/res/values-de/strings.xml b/packages/PackageInstaller/res/values-de/strings.xml index 666ef4536f78..675000892024 100644 --- a/packages/PackageInstaller/res/values-de/strings.xml +++ b/packages/PackageInstaller/res/values-de/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Dieser Nutzer darf keine unbekannten Apps installieren"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Dieser Nutzer darf keine Apps installieren"</string> <string name="ok" msgid="7871959885003339302">"Ok"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archivieren"</string> <string name="update_anyway" msgid="8792432341346261969">"Trotzdem aktualisieren"</string> <string name="manage_applications" msgid="5400164782453975580">"Apps verwalten"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Kein freier Speicher vorhanden"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Update deinstallieren"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> gehört zu folgender App:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Möchtest du diese App deinstallieren?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Deine personenbezogenen Daten werden gespeichert"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Diese App für alle Nutzer archivieren? Deine personenbezogenen Daten werden gespeichert."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Diese in deinem Arbeitsprofil befindliche App archivieren? Deine personenbezogenen Daten werden gespeichert."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Diese App für <xliff:g id="USERNAME">%1$s</xliff:g> archivieren? Deine personenbezogenen Daten werden gespeichert."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Möchtest du diese in deinem privaten Bereich befindliche App archivieren? Deine personenbezogenen Daten werden gespeichert."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Möchtest du diese App für "<b>"alle"</b>" Nutzer entfernen? Die App und alle zugehörigen Daten werden für "<b>"alle"</b>" Nutzer des Geräts entfernt."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Möchtest du diese App für den Nutzer <xliff:g id="USERNAME">%1$s</xliff:g> deinstallieren?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Möchtest du diese App aus deinem Arbeitsprofil deinstallieren?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Unbekannte Apps können gefährlich für dein Tablet und deine personenbezogenen Daten sein. Wenn du diese App installierst, erklärst du dich damit einverstanden, dass du die Verantwortung für alle Schäden an deinem Tablet und jegliche Datenverluste trägst, die aus der Verwendung dieser App entstehen können."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Unbekannte Apps können gefährlich für deinen Fernseher und deine personenbezogenen Daten sein. Wenn du diese App installierst, erklärst du dich damit einverstanden, dass du die Verantwortung für alle Schäden an deinem Fernseher und jegliche Datenverluste trägst, die aus der Verwendung dieser App entstehen können."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-Klon"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> archivieren?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Weiter"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Einstellungen"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear-Apps installieren/deinstallieren"</string> diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml index 94e50b18f606..6f0db208882c 100644 --- a/packages/PackageInstaller/res/values-el/strings.xml +++ b/packages/PackageInstaller/res/values-el/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Δεν είναι δυνατή η εγκατάσταση άγνωστων εφαρμογών από αυτόν τον χρήστη"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Δεν επιτρέπεται η εγκατάσταση εφαρμογών σε αυτόν τον χρήστη"</string> <string name="ok" msgid="7871959885003339302">"ΟΚ"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Αρχειοθέτηση"</string> <string name="update_anyway" msgid="8792432341346261969">"Να ενημερωθεί ούτως ή άλλως"</string> <string name="manage_applications" msgid="5400164782453975580">"Διαχ. εφαρμογών"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Δεν υπάρχει χώρος"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Απεγκατάσταση ενημέρωσης"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"Η δραστηριότητα <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> αποτελεί τμήμα της ακόλουθης εφαρμογής:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή;"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Αρχειοθέτηση αυτής της εφαρμογής για όλους τους χρήστες; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Αρχειοθέτηση αυτής της εφαρμογής στο προφίλ εργασίας σας; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Αρχειοθέτηση αυτής της εφαρμογής για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Θέλετε να αρχειοθετήσετε αυτή την εφαρμογή από τον απόρρητο χώρο σας; Τα προσωπικά δεδομένα σας θα αποθηκευτούν"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή για "<b>"όλους"</b>" τους χρήστες; Η εφαρμογή και τα δεδομένα της θα καταργηθούν από "<b>"όλους"</b>" τους χρήστες στη συσκευή."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>;"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Θέλετε να καταργήσετε την εγκατάσταση αυτής της εφαρμογής από το προφίλ εργασίας σας;"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Το tablet σας και τα προσωπικά δεδομένα σας είναι πιο ευάλωτα σε επιθέσεις από άγνωστες εφαρμογές. Με την εγκατάσταση αυτής της εφαρμογής, συμφωνείτε ότι είστε υπεύθυνοι για τυχόν βλάβη που μπορεί να προκληθεί στο tablet ή απώλεια δεδομένων που μπορεί να προκύψει από τη χρήση τους."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Η τηλεόρασή σας και τα προσωπικά δεδομένα σας είναι πιο ευάλωτα σε επιθέσεις από άγνωστες εφαρμογές. Με την εγκατάσταση αυτής της εφαρμογής, συμφωνείτε ότι είστε υπεύθυνοι για τυχόν βλάβη που μπορεί να προκληθεί στην τηλεόρασή ή απώλεια δεδομένων που μπορεί να προκύψει από τη χρήση τους."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Διπλότυπο <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Αρχειοθέτηση <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>;"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Συνέχεια"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Ρυθμίσεις"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Εγκατάσταση/απεγκατάσταση εφαρμογών Wear"</string> diff --git a/packages/PackageInstaller/res/values-es-rUS/strings.xml b/packages/PackageInstaller/res/values-es-rUS/strings.xml index b66976a98aec..75370082471a 100644 --- a/packages/PackageInstaller/res/values-es-rUS/strings.xml +++ b/packages/PackageInstaller/res/values-es-rUS/strings.xml @@ -26,9 +26,9 @@ <string name="install_done" msgid="5987363587661783896">"Se instaló la app."</string> <string name="install_confirm_question" msgid="7663733664476363311">"¿Deseas instalar esta app?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"¿Deseas actualizar esta app?"</string> - <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Actualiza esta app desde <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Esta app normalmente recibe actualizaciones desde <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en la tablet. Las funciones de la app puede cambiar.</p>"</string> - <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Actualiza esta app desde <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Esta app normalmente recibe actualizaciones desde <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en la TV. Las funciones de la app puede cambiar.</p>"</string> - <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Actualiza esta app desde <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Esta app normalmente recibe actualizaciones desde <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en el teléfono. Las funciones de la app puede cambiar.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>¿Actualizar esta app desde <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Esta app normalmente recibe actualizaciones desde <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en la tablet. Las funciones de la app pueden cambiar.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>¿Actualizar esta app desde <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Esta app normalmente recibe actualizaciones desde <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en la TV. Las funciones de la app pueden cambiar.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>¿Actualizar esta app desde <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Esta app normalmente recibe actualizaciones desde <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si actualizas a través de otra fuente, es posible que recibas las próximas actualizaciones de cualquier fuente en el teléfono. Las funciones de la app pueden cambiar.</p>"</string> <string name="install_failed" msgid="5777824004474125469">"No se instaló la app."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"Se bloqueó el paquete para impedir la instalación."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"No se instaló la app debido a un conflicto con un paquete."</string> @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Este usuario no puede instalar apps desconocidas"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuario no puede instalar apps"</string> <string name="ok" msgid="7871959885003339302">"Aceptar"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archivar"</string> <string name="update_anyway" msgid="8792432341346261969">"Actualizar de todas formas"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestionar apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sin espacio"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar actualización"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> es parte de la siguiente app:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"¿Quieres desinstalar esta app?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Se guardarán tus datos personales"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"¿Quieres archivar esta app para todos los usuarios? Se guardarán tus datos personales"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"¿Quieres archivar esta app en tu perfil de trabajo? Se guardarán tus datos personales"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"¿Quieres archivar esta app para <xliff:g id="USERNAME">%1$s</xliff:g>? Se guardarán tus datos personales"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"¿Quieres archivar esta app de tu espacio privado? Se guardarán tus datos personales"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"¿Quieres desinstalar esta app para "<b>"todos"</b>" los usuarios? Se quitarán la aplicación y sus datos de "<b>"todos"</b>" los usuarios del dispositivo."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"¿Quieres desinstalar esta app para el usuario <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"¿Deseas desinstalar esta app de tu perfil de trabajo?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"La tablet y tus datos personales son más vulnerables a los ataques de apps desconocidas. Si instalas esta app, serás responsable de los daños que sufra la tablet y de la pérdida de datos que pueda ocasionar su uso."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"La TV y tus datos personales son más vulnerables a los ataques de apps desconocidas. Si instalas esta app, serás responsable de los daños que sufra la TV y de la pérdida de datos que pueda ocasionar su uso."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"¿Quieres archivar <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuar"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Configuración"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instalando/desinstalando apps para Wear"</string> diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml index 2a0d0637bc03..9a7e523e74f8 100644 --- a/packages/PackageInstaller/res/values-es/strings.xml +++ b/packages/PackageInstaller/res/values-es/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Este usuario no puede instalar aplicaciones desconocidas"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuario no tiene permiso para instalar aplicaciones"</string> <string name="ok" msgid="7871959885003339302">"Aceptar"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archivar"</string> <string name="update_anyway" msgid="8792432341346261969">"Actualizar igualmente"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestionar aplicaciones"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sin espacio"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar actualización"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> forma parte de esta aplicación:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"¿Quieres desinstalar esta aplicación?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Tus datos personales se guardarán."</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"¿Archivar esta aplicación para todos los usuarios? Tus datos personales se guardarán."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"¿Archivar esta aplicación en tu perfil de trabajo? Tus datos personales se guardarán."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"¿Archivar esta aplicación para <xliff:g id="USERNAME">%1$s</xliff:g>? Tus datos personales se guardarán."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"¿Quieres archivar esta aplicación de tu espacio privado? Tus datos personales se guardarán."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"¿Quieres desinstalar esta aplicación para "<b>"todos"</b>" los usuarios? La aplicación y sus datos se borrarán de "<b>"todos"</b>" los usuarios del dispositivo."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"¿Quieres desinstalar esta aplicación para el usuario <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"¿Quieres desinstalar esta aplicación de tu perfil de trabajo?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tu tablet y tus datos personales son más vulnerables a los ataques de aplicaciones desconocidas. Al instalar esta aplicación, aceptas ser responsable de cualquier daño que sufra tu tablet o la pérdida de datos que se pueda derivar de su uso."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Tu TV y tus datos personales son más vulnerables a los ataques de aplicaciones desconocidas. Al instalar esta aplicación, aceptas ser responsable de cualquier daño que sufra tu TV o la pérdida de datos que se pueda derivar de su uso."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"¿Archivar <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuar"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Ajustes"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instalando/desinstalando apps para Wear"</string> diff --git a/packages/PackageInstaller/res/values-et/strings.xml b/packages/PackageInstaller/res/values-et/strings.xml index 5d5914e4f590..b08393297d1a 100644 --- a/packages/PackageInstaller/res/values-et/strings.xml +++ b/packages/PackageInstaller/res/values-et/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"See kasutaja ei saa installida tundmatuid rakendusi"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Kasutajal ei ole lubatud rakendusi installida"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arhiiv"</string> <string name="update_anyway" msgid="8792432341346261969">"Värskenda ikkagi"</string> <string name="manage_applications" msgid="5400164782453975580">"Rakend. haldam."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Pole ruumi"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Värskenduse desinstallimine"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> on osa järgmisest rakendusest:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Kas soovite selle rakenduse desinstallida?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Teie isiklikud andmed salvestatakse"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Kas arhiivida see rakendus kõigi kasutajate puhul? Teie isiklikud andmed salvestatakse"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Kas arhiivida see rakendus teie tööprofiilil? Teie isiklikud andmed salvestatakse"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Kas arhiivida see rakendus kasutaja <xliff:g id="USERNAME">%1$s</xliff:g> puhul? Teie isiklikud andmed salvestatakse"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Kas soovite selle rakenduse oma privaatsest ruumist arhiivida? Teie isiklikud andmed salvestatakse"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Kas soovite selle rakenduse "<b>"kõikide"</b>" kasutajate kontodelt desinstallida? Rakendus ja selle andmed eemaldatakse "<b>"kõikide"</b>" seadme kasutajate kontodelt."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Kas soovite selle rakenduse kasutaja <xliff:g id="USERNAME">%1$s</xliff:g> kontolt desinstallida?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Kas soovite selle rakenduse oma tööprofiililt desinstallida?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Teie tahvelarvuti ja isiklikud andmed on tundmatute rakenduste rünnakute suhtes haavatavamad. Selle rakenduse installimisel nõustute, et vastutate tahvelarvuti kahjude ja andmekao eest, mis võivad tuleneda selliste rakenduste kasutamisest."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Teie teler ja isiklikud andmed on tundmatute rakenduste rünnakute suhtes haavatavamad. Selle rakenduse installimisel nõustute, et vastutate teleri kahjude ja andmekao eest, mis võivad tuleneda selliste rakenduste kasutamisest."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Rakenduse <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> kloon"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Kas arhiivida <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Jätka"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Seaded"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Weari rak. installimine/desinstallimine"</string> diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml index af25e528d8a0..9d1d536944ec 100644 --- a/packages/PackageInstaller/res/values-eu/strings.xml +++ b/packages/PackageInstaller/res/values-eu/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Erabiltzaile honek ezin ditu instalatu aplikazio ezezagunak"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Erabiltzaile honek ez du baimenik aplikazioak instalatzeko"</string> <string name="ok" msgid="7871959885003339302">"Ados"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Artxibatu"</string> <string name="update_anyway" msgid="8792432341346261969">"Eguneratu halere"</string> <string name="manage_applications" msgid="5400164782453975580">"Kudeatu aplikazioak"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Ez dago behar adina toki"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Desinstalatu eguneratzea"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> aplikazio honen zati da:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Aplikazioa desinstalatu nahi duzu?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Zure datu pertsonalak gorde egingo dira"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Aplikazio hau erabiltzaile guztientzat artxibatu nahi duzu? Zure datu pertsonalak gorde egingo dira."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Aplikazio hau laneko profiletik artxibatu nahi duzu? Zure datu pertsonalak gorde egingo dira."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Aplikazio hau <xliff:g id="USERNAME">%1$s</xliff:g> erabiltzailearentzat artxibatu nahi duzu? Zure datu pertsonalak gorde egingo dira."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Aplikazio hau eremu pribatutik artxibatu nahi duzu? Zure datu pertsonalak gorde egingo dira."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Erabiltzaile "<b>"guztiei"</b>" desinstalatu nahi diezu aplikazioa? Aplikazioa eta haren datu guztiak ezabatuko zaizkie gailuko erabiltzaile "<b>"guztiei"</b>"."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> erabiltzaileari desinstalatu nahi diozu aplikazioa?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Aplikazioa laneko profiletik desinstalatu nahi duzu?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Baliteke tabletak eta datu pertsonalek aplikazio ezezagunen erasoak jasatea. Aplikazio hau instalatzen baduzu, onartu egingo duzu hura erabiltzeagatik tabletari agian gertatuko zaizkion kalteen edo datu-galeren erantzulea zeu izango zarela."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Baliteke telebistak eta datu pertsonalek aplikazio ezezagunen erasoak jasatea. Aplikazio hau instalatzen baduzu, onartu egingo duzu hura erabiltzeagatik telebistari agian gertatuko zaizkion kalteen edo datu-galeren erantzulea zeu izango zarela."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> aplikazioaren klona"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> artxibatu nahi duzu?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Egin aurrera"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Ezarpenak"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear aplikazioak instalatzea/desinstalatzea"</string> diff --git a/packages/PackageInstaller/res/values-fa/strings.xml b/packages/PackageInstaller/res/values-fa/strings.xml index a7dc36a2ff87..53bfd27b8938 100644 --- a/packages/PackageInstaller/res/values-fa/strings.xml +++ b/packages/PackageInstaller/res/values-fa/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"این کاربر نمیتواند برنامههای ناشناس نصب کند"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"این کاربر مجاز به نصب برنامه نیست"</string> <string name="ok" msgid="7871959885003339302">"بسیار خوب"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"بایگانی"</string> <string name="update_anyway" msgid="8792432341346261969">"درهرصورت بهروز شود"</string> <string name="manage_applications" msgid="5400164782453975580">"مدیریت برنامهها"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"فضا کافی نیست"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"حذف نصب بهروزرسانی"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> قسمتی از برنامه زیر است:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"میخواهید این برنامه را حذف نصب کنید؟"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"دادههای شخصیتان ذخیره خواهد شد"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"این برنامه برای همه کاربران بایگانی شود؟ دادههای شخصیتان ذخیره خواهد شد"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"این برنامه در نمایه کاری بایگانی شود؟ دادههای شخصیتان ذخیره خواهد شد"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"این برنامه برای <xliff:g id="USERNAME">%1$s</xliff:g> بایگانی شود؟ دادههای شخصیتان ذخیره خواهد شد"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"میخواهید این برنامه از فضای خصوصیتان را بایگانی کنید؟ دادههای شخصیتان ذخیره خواهد شد"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"آیا میخواهید این برنامه را برای "<b>"همه"</b>" کاربران حذف کنید؟ این برنامه و دادههای آن برای "<b>"همه"</b>" کاربران این دستگاه حذف خواهد شد."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"آیا میخواهید این برنامه را برای این کاربر <xliff:g id="USERNAME">%1$s</xliff:g> حذف نصب کنید؟"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"میخواهید این برنامه را از نمایه کاریتان حذف نصب کنید؟"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"رایانه لوحی و دادههای شخصیتان دربرابر حمله برنامههای ناشناس آسیبپذیرتر هستند. با نصب این برنامه، موافقت میکنید که مسئول هرگونه آسیب به رایانه لوحی یا از دست رفتن دادهای هستید که ممکن است درنتیجه استفاده از آن به وجود آید."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"تلویزیون و دادههای شخصیتان دربرابر حمله برنامههای ناشناس آسیبپذیرتر هستند. با نصب این برنامه، موافقت میکنید که مسئول هرگونه آسیب به تلویزیون یا از دست رفتن دادهای هستید که ممکن است درنتیجه استفاده از آن به وجود آید."</string> <string name="cloned_app_label" msgid="7503612829833756160">"همسانه <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> بایگانی شود؟"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ادامه"</string> <string name="external_sources_settings" msgid="4046964413071713807">"تنظیمات"</string> <string name="wear_app_channel" msgid="1960809674709107850">"نصب/حذف نصب برنامههای پوشیدنی"</string> diff --git a/packages/PackageInstaller/res/values-fi/strings.xml b/packages/PackageInstaller/res/values-fi/strings.xml index 3ef9807aad11..c5bb5017a1a1 100644 --- a/packages/PackageInstaller/res/values-fi/strings.xml +++ b/packages/PackageInstaller/res/values-fi/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Tämä käyttäjä ei voi asentaa tuntemattomia sovelluksia."</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Tämä käyttäjä ei voi asentaa sovelluksia."</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arkistoi"</string> <string name="update_anyway" msgid="8792432341346261969">"Päivitä silti"</string> <string name="manage_applications" msgid="5400164782453975580">"Sovellusvalinnat"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Tallennustila ei riitä"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Poista päivitys"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> on osa seuraavaa sovellusta:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Haluatko poistaa tämän sovelluksen?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Henkilökohtainen datasi tallennetaan"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Arkistoidaanko tämä sovellus kaikilta käyttäjiltä? Henkilökohtainen datasi tallennetaan"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arkistoidaanko tämä sovellus työprofiilistasi? Henkilökohtainen datasi tallennetaan"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Arkistoidaanko tämä sovellus käyttäjältä: <xliff:g id="USERNAME">%1$s</xliff:g>? Henkilökohtainen datasi tallennetaan"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Haluatko arkistoida tämän sovelluksen yksityisestä tilasta? Henkilökohtainen datasi tallennetaan"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Haluatko poistaa tämän sovelluksen "<b>"kaikilta"</b>" käyttäjiltä? Sovellus ja sen data poistetaan "<b>"kaikilta"</b>" laitteen käyttäjiltä."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Haluatko poistaa tämän sovelluksen käyttäjältä <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Haluatko poistaa sovelluksen työprofiilistasi?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tuntemattomat sovellukset voivat helpommin kaapata tablettisi ja henkilökohtaiset tietosi. Lataamalla sovelluksia tästä lähteestä hyväksyt, että olet itse vastuussa tabletillesi aiheutuvista vahingoista tai tietojen menetyksestä, jotka voivat johtua sovellusten käytöstä."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Tuntemattomat sovellukset voivat helpommin kaapata televisiosi ja henkilökohtaiset tietosi. Lataamalla sovelluksen hyväksyt, että olet itse vastuussa mahdollisista televisiolle aiheutuvista vahingoista tai tietojen menetyksestä, jotka voivat johtua sovellusten käytöstä."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klooni: <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Arkistoidaanko <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Jatka"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Asetukset"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear-sovellusten asennus/poistaminen"</string> diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml index 0bd5026a1e47..86ba34cd121e 100644 --- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml +++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Cet utilisateur ne peut pas installer d\'applications inconnues"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Cet utilisateur n\'est pas autorisé à installer des applications"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archiver"</string> <string name="update_anyway" msgid="8792432341346261969">"Mettre à jour malgré tout"</string> <string name="manage_applications" msgid="5400164782453975580">"Gérer les applis"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Espace insuffisant"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Désinstaller mise à jour"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> fait partie de l\'application suivante :"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Voulez-vous désinstaller cette application?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Vos données personnelles seront enregistrées"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Archiver cette application pour tous les utilisateurs? Vos données personnelles seront enregistrées"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Archiver cette application sur votre profil professionnel? Vos données personnelles seront enregistrées"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Archiver cette application pour <xliff:g id="USERNAME">%1$s</xliff:g>? Vos données personnelles seront enregistrées"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Voulez-vous archiver cette application de votre Espace privé? Vos données personnelles seront enregistrées"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Voulez-vous désinstaller cette application pour "<b>"tous"</b>" les utilisateurs? L\'application et ses données seront supprimées pour "<b>"tous"</b>" les utilisateurs de l\'appareil."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Voulez-vous désinstaller cette application pour l\'utilisateur <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Voulez-vous désinstaller cette application de votre profil professionnel?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Votre tablette et vos données personnelles sont plus vulnérables aux attaques provenant d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre tablette ou de toute perte de données pouvant découler de l\'utilisation de telles applications."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Votre téléviseur et vos données personnelles sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre téléviseur ou de toute perte de données pouvant découler de son utilisation."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Archiver <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuer"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Paramètres"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Installer/désinstaller applis Google Wear"</string> diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml index 1c64613d474f..0b74e198058b 100644 --- a/packages/PackageInstaller/res/values-fr/strings.xml +++ b/packages/PackageInstaller/res/values-fr/strings.xml @@ -26,9 +26,9 @@ <string name="install_done" msgid="5987363587661783896">"Application installée."</string> <string name="install_confirm_question" msgid="7663733664476363311">"Voulez-vous installer cette appli ?"</string> <string name="install_confirm_question_update" msgid="3348888852318388584">"Voulez-vous mettre à jour cette appli ?"</string> - <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Mettez à jour cette appli depuis <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Elle reçoit normalement des mises à jour depuis <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre tablette. Le fonctionnement de l\'application peut changer.</p>"</string> - <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Mettez à jour cette appli depuis <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Elle reçoit normalement des mises à jour depuis <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre téléviseur. Le fonctionnement de l\'application peut changer.</p>"</string> - <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Mettez à jour cette appli depuis <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Elle reçoit normalement des mises à jour depuis <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application peut changer.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Mettre à jour cette appli depuis <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> ?</p><p>Elle reçoit normalement des mises à jour depuis <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre tablette. Le fonctionnement de l\'application peut changer.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Mettre à jour cette appli depuis <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> ?</p><p>Elle reçoit normalement des mises à jour depuis <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre téléviseur. Le fonctionnement de l\'application peut changer.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Mettre à jour cette appli depuis <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b> ?</p><p>Elle reçoit normalement des mises à jour depuis <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Si vous effectuez la mise à jour à partir d\'une autre source, vous recevrez peut-être les prochaines mises à jour depuis n\'importe quelle source sur votre téléphone. Le fonctionnement de l\'application peut changer.</p>"</string> <string name="install_failed" msgid="5777824004474125469">"Application non installée."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"L\'installation du package a été bloquée."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"L\'application n\'a pas été installée, car le package est en conflit avec un package déjà présent."</string> @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Cet utilisateur ne peut pas installer d\'applications inconnues"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Cet utilisateur n\'est pas autorisé à installer des applications"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archiver"</string> <string name="update_anyway" msgid="8792432341346261969">"Mettre à jour quand même"</string> <string name="manage_applications" msgid="5400164782453975580">"Gérer applis"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Mémoire insuffisante"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Désinstaller la mise à jour"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> fait partie de l\'application suivante :"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Voulez-vous désinstaller cette application ?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Vos données personnelles seront enregistrées."</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Archiver cette appli pour tous les utilisateurs ? Vos données personnelles seront enregistrées."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Archiver cette appli sur votre profil professionnel ? Vos données personnelles seront enregistrées."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Archiver cette appli pour <xliff:g id="USERNAME">%1$s</xliff:g> ? Vos données personnelles seront enregistrées."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Souhaitez-vous archiver cette application de votre espace privé ? Vos données personnelles seront enregistrées."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Voulez-vous désinstaller cette application pour "<b>"tous"</b>" les utilisateurs ? L\'application et ses données seront supprimées pour "<b>"tous"</b>" les utilisateurs de l\'appareil."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Voulez-vous désinstaller cette application pour l\'utilisateur <xliff:g id="USERNAME">%1$s</xliff:g> ?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Voulez-vous désinstaller cette appli de votre profil professionnel ?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Votre tablette et vos données à caractère personnel sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre tablette ou de toute perte de données pouvant découler de son utilisation."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Votre téléviseur et vos données à caractère personnel sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre téléviseur ou de toute perte de données pouvant découler de son utilisation."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Archiver <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuer"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Paramètres"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Installer/Désinstaller les applis Wear"</string> diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml index 38e79ba669e4..96f0fdbab4c2 100644 --- a/packages/PackageInstaller/res/values-gl/strings.xml +++ b/packages/PackageInstaller/res/values-gl/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Este usuario non pode instalar aplicacións descoñecidas"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuario non ten permiso para instalar aplicacións"</string> <string name="ok" msgid="7871959885003339302">"Aceptar"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arquivar"</string> <string name="update_anyway" msgid="8792432341346261969">"Actualizar de todas formas"</string> <string name="manage_applications" msgid="5400164782453975580">"Xestionar apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Esgotouse o espazo"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar actualización"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> forma parte da seguinte aplicación:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Queres desinstalar esta aplicación?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Gardaranse os teus datos persoais"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Queres arquivar esta aplicación para todos os usuarios? Gardaranse os teus datos persoais"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Queres arquivar esta aplicación no teu perfil de traballo? Gardaranse os teus datos persoais"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Queres arquivar esta aplicación para <xliff:g id="USERNAME">%1$s</xliff:g>? Gardaranse os teus datos persoais"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Queres arquivar esta aplicación do teu espazo privado? Gardaranse os teus datos persoais"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Queres desinstalar esta aplicación para "<b>"todos"</b>" os usuarios? A aplicación e os seus datos quitaranse de "<b>"todos"</b>" os usuarios do dispositivo."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Queres desinstalar esta aplicación para o usuario que se chama <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Queres desinstalar esta aplicación do perfil de traballo?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"A tableta e os datos persoais son máis vulnerables aos ataques de aplicacións descoñecidas. Ao instalar esta aplicación, aceptas que es responsable dos danos ocasionados na tableta ou da perda dos datos que se poidan derivar do seu uso."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"A televisión e os datos persoais son máis vulnerables aos ataques de aplicacións descoñecidas. Ao instalar esta aplicación, aceptas que es responsable dos danos ocasionados na televisión ou da perda dos datos que se poidan derivar do seu uso."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Queres arquivar <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuar"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Configuración"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instalando/desinstalando apps para Wear"</string> diff --git a/packages/PackageInstaller/res/values-gu/strings.xml b/packages/PackageInstaller/res/values-gu/strings.xml index 3362a16ac1a0..18db939bc653 100644 --- a/packages/PackageInstaller/res/values-gu/strings.xml +++ b/packages/PackageInstaller/res/values-gu/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"આ વપરાશકર્તા અજાણી ઍપ્લિકેશનોને ઇન્સ્ટૉલ કરી શકતા નથી"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"આ વપરાશકર્તાને ઍપ્લિકેશનો ઇન્સ્ટૉલ કરવાની મંજૂરી નથી"</string> <string name="ok" msgid="7871959885003339302">"ઓકે"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"આર્કાઇવ કરો"</string> <string name="update_anyway" msgid="8792432341346261969">"તો પણ અપડેટ કરો"</string> <string name="manage_applications" msgid="5400164782453975580">"ઍપને મેનેજ કરો"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"સ્પેસ નથી"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"અપડેટ અનઇન્સ્ટૉલ કરો"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>, નીચેની ઍપ્લિકેશનનો ભાગ છે:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"શું તમે આ ઍપને અનઇન્સ્ટૉલ કરવા માંગો છો?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"તમારો વ્યક્તિગત ડેટા સાચવવામાં આવશે"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"શું આ ઍપને તમામ વપરાશકર્તાઓ માટે આર્કાઇવ કરીએ? તમારો વ્યક્તિગત ડેટા સાચવવામાં આવશે"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"શું આ ઍપને તમારી ઑફિસની પ્રોફાઇલ પર આર્કાઇવ કરીએ? તમારો વ્યક્તિગત ડેટા સાચવવામાં આવશે"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"શું આ ઍપને <xliff:g id="USERNAME">%1$s</xliff:g> માટે આર્કાઇવ કરીએ? તમારો વ્યક્તિગત ડેટા સાચવવામાં આવશે"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"શું તમે તમારી ખાનગી સ્પેસમાંથી આ ઍપને આર્કાઇવ કરવા માગો છો? તમારો વ્યક્તિગત ડેટા સાચવવામાં આવશે"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"શું તમે "<b>"બધા"</b>" વપરાશકર્તાઓ માટે આ ઍપ્લિકેશનને અનઇન્સ્ટૉલ કરવા માગો છો? ડિવાઇસ પરના "<b>"બધા"</b>" વપરાશકર્તાઓની ઍપ્લિકેશન અને તેનો ડેટા કાઢી નાખવામાં આવશે."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"શું તમે <xliff:g id="USERNAME">%1$s</xliff:g> વપરાશકર્તા માટે આ ઍપ્લિકેશનને અનઇન્સ્ટૉલ કરવા માગો છો?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"શું તમે તમારી ઑફિસની પ્રોફાઇલમાંથી આ ઍપને અનઇન્સ્ટૉલ કરવા માગો છો?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"તમારું ટૅબ્લેટ અને વ્યક્તિગત ડેટા અજાણી ઍપ્લિકેશનો દ્વારા હુમલા માટે વધુ સંવેદનશીલ છે. આ ઍપ્લિકેશન ઇન્સ્ટૉલ કરીને તમે સંમત થાઓ છો કે આનો ઉપયોગ કરવાથી તમારા ટૅબ્લેટને થતી કોઈપણ હાનિ અથવા ડેટાના નુકસાન માટે તમે જવાબદાર છો."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"તમારું ટીવી અને વ્યક્તિગત ડેટા અજાણી ઍપ્લિકેશનો દ્વારા હુમલા માટે વધુ સંવેદનશીલ છે. આ ઍપ્લિકેશન ઇન્સ્ટૉલ કરીને તમે સંમત થાઓ છો કે આનો ઉપયોગ કરવાથી તમારા ટીવીને થતી કોઈપણ હાનિ અથવા ડેટાના નુકસાન માટે તમે જવાબદાર છો."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>ની ક્લોન"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> આર્કાઇવ કરીએ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"આગળ વધો"</string> <string name="external_sources_settings" msgid="4046964413071713807">"સેટિંગ"</string> <string name="wear_app_channel" msgid="1960809674709107850">"એમ્બેડ ઍપ્લિકેશનો ઇન્સ્ટૉલ/અનઇન્સ્ટૉલ"</string> diff --git a/packages/PackageInstaller/res/values-hi/strings.xml b/packages/PackageInstaller/res/values-hi/strings.xml index e774291ac0a0..73cbc3381305 100644 --- a/packages/PackageInstaller/res/values-hi/strings.xml +++ b/packages/PackageInstaller/res/values-hi/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"यह उपयोगकर्ता अनजान ऐप्लिकेशन इंस्टॉल नहीं कर सकता"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"इस उपयोगकर्ता को ऐप्लिकेशन इंस्टॉल करने की अनुमति नहीं है"</string> <string name="ok" msgid="7871959885003339302">"ठीक है"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"संग्रहित करें"</string> <string name="update_anyway" msgid="8792432341346261969">"फिर भी अपडेट करें"</string> <string name="manage_applications" msgid="5400164782453975580">"ऐप्लिकेशन प्रबंधित करें"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"जगह नहीं है"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"अपडेट अनइंस्टॉल करें"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> इस ऐप्लिकेशन का भाग है:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"क्या आपको इस ऐप्लिकेशन को अनइंस्टॉल करना है?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"आपका निजी डेटा सेव किया जाएगा"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"क्या इस ऐप्लिकेशन को सभी के लिए संग्रहित करना है? आपका निजी डेटा सेव किया जाएगा"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"क्या आपको अपनी वर्क प्रोफ़ाइल से यह ऐप्लिकेशन संग्रहित करना है? आपका निजी डेटा सेव किया जाएगा"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"क्या <xliff:g id="USERNAME">%1$s</xliff:g> के लिए यह ऐप्लिकेशन संग्रहित करना है? आपका निजी डेटा सेव किया जाएगा"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"क्या आपको अपने प्राइवेट स्पेस से यह ऐप्लिकेशन संग्रहित करना है? आपका निजी डेटा सेव किया जाएगा"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"क्या आप इस ऐप्लिकेशन को "<b>"सभी"</b>" उपयोगकर्ताओं के लिए अनइंस्टॉल करना चाहते हैं? ऐप्लिकेशन और उसके डेटा को डिवाइस पर "<b>"सभी"</b>" उपयोगकर्ताओं से हटा दिया जाएगा."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"क्या आप उपयोगकर्ता <xliff:g id="USERNAME">%1$s</xliff:g> के लिए इस ऐप्लिकेशन को अनइंस्टॉल करना चाहते हैं?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"क्या अपनी वर्क प्रोफ़ाइल से इस ऐप्लिकेशन को अनइंस्टॉल करना है?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"आपका टैबलेट और निजी डेटा अनजान ऐप्लिकेशन के हमले को लेकर ज़्यादा संवेदनशील हैं. इस ऐप्लिकेशन को इंस्टॉल करके, आप सहमति देते हैं कि इसके इस्तेमाल के चलते आपके टैबलेट को होने वाले किसी भी नुकसान या डेटा के मिट जाने पर, आप ज़िम्मेदार होंगे."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"आपका टीवी और निजी डेटा अनजान ऐप्लिकेशन के हमले को लेकर ज़्यादा संवेदनशील हैं. इस ऐप्लिकेशन को इंस्टॉल करके, आप सहमति देते हैं कि इसके इस्तेमाल के चलते आपके टीवी को होने वाले किसी भी नुकसान या डेटा के मिट जाने पर, आप ज़िम्मेदार होंगे."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> का क्लोन"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"क्या <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> संग्रहित करना है?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"जारी रखें"</string> <string name="external_sources_settings" msgid="4046964413071713807">"सेटिंग"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear ऐप्लिकेशन इंस्टॉल/अनइंस्टॉल हो रहे हैं"</string> diff --git a/packages/PackageInstaller/res/values-hr/strings.xml b/packages/PackageInstaller/res/values-hr/strings.xml index 5df276e62b7a..27ba153f0f79 100644 --- a/packages/PackageInstaller/res/values-hr/strings.xml +++ b/packages/PackageInstaller/res/values-hr/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ovaj korisnik ne može instalirati nepoznate aplikacije"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ovaj korisnik nema dopuštenje za instaliranje aplikacija"</string> <string name="ok" msgid="7871959885003339302">"U redu"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arhiviraj"</string> <string name="update_anyway" msgid="8792432341346261969">"Ipak ažuriraj"</string> <string name="manage_applications" msgid="5400164782453975580">"Upravljanje apl."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nema dovoljno mjesta"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Deinstalacija ažuriranja"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"Aktivnost <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> dio je sljedeće aplikacije:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Želite li deinstalirati ovu aplikaciju?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Vaši će se osobni podaci spremiti"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Želite li arhivirati ovu aplikaciju za sve korisnike? Vaši će se osobni podaci spremiti"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Želite li arhivirati ovu aplikaciju na poslovnom profilu? Vaši će se osobni podaci spremiti"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Želite li arhivirati ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>? Vaši će se osobni podaci spremiti"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Želite li arhivirati ovu aplikaciju iz svojeg privatnog prostora? Vaši će se osobni podaci spremiti"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Želite li deinstalirati tu aplikaciju za "<b>"sve"</b>" korisnike? Aplikacija i njezini podaci bit će uklonjeni sa "<b>"svih"</b>" korisnika na uređaju."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li deinstalirati tu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Želite li deinstalirati tu aplikaciju s poslovnog profila?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Vaš tablet i osobni podaci podložniji su napadima nepoznatih aplikacija. Instaliranjem te aplikacije prihvaćate odgovornost za oštećenje tableta ili gubitak podataka do kojih može doći uslijed njezine upotrebe."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Vaš TV i osobni podaci podložniji su napadima nepoznatih aplikacija. Instaliranjem te aplikacije prihvaćate odgovornost za oštećenje televizora ili gubitak podataka do kojih može doći uslijed njezine upotrebe."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Želite li arhivirati aplikaciju <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Nastavi"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Postavke"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instaliranje/deinstaliranje Wear apl."</string> diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml index 6de5bace662f..b2c7c1aadd1c 100644 --- a/packages/PackageInstaller/res/values-hu/strings.xml +++ b/packages/PackageInstaller/res/values-hu/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ez a felhasználó nem telepíthet ismeretlen alkalmazásokat"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ez a felhasználó nem telepíthet alkalmazásokat"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archiválás"</string> <string name="update_anyway" msgid="8792432341346261969">"Frissítés"</string> <string name="manage_applications" msgid="5400164782453975580">"Alkalmazáskezelés"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nincs elég hely"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Frissítés eltávolítása"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"A(z) <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> a következő alkalmazás része:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Eltávolítja ezt az alkalmazást?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Személyes adatait menteni fogja a rendszer."</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Valamennyi felhasználó számára archiválja az alkalmazást? Személyes adatait menteni fogja a rendszer."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Archiválja ezt az alkalmazást a munkaprofilján? Személyes adatait menteni fogja a rendszer."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Archiválja ezt az alkalmazást <xliff:g id="USERNAME">%1$s</xliff:g> számára? Személyes adatait menteni fogja a rendszer."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Archiválja ezt az alkalmazást a privát területről? Személyes adatait menteni fogja a rendszer."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Szeretné eltávolítani ezt az alkalmazást "<b>"minden"</b>" felhasználónál? Az alkalmazást és adatait az eszköz "<b>"minden"</b>" felhasználójánál töröljük."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Eltávolítja ezt az alkalmazást <xliff:g id="USERNAME">%1$s</xliff:g> felhasználó esetében?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Biztosan eltávolítja ezt az alkalmazást a munkaprofiljából?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Táblagépe és személyes adatai fokozott kockázatnak vannak kitéve az ismeretlen alkalmazások támadásaival szemben. Az alkalmazás telepítésével elfogadja, hogy Ön a felelős az alkalmazás használatából eredő esetleges adatvesztésért és a táblagépet ért károkért."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Tévéje és személyes adatai fokozott kockázatnak vannak kitéve az ismeretlen alkalmazások támadásaival szemben. Az alkalmazás telepítésével elfogadja, hogy Ön a felelős az alkalmazás használatából eredő esetleges adatvesztésért és a tévét ért károkért."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klónozott <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Archiválja ezt: <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Tovább"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Beállítások"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear-alkalmazások telepítése/törlése"</string> diff --git a/packages/PackageInstaller/res/values-hy/strings.xml b/packages/PackageInstaller/res/values-hy/strings.xml index 4bb3915b705b..bbc1974d6b3c 100644 --- a/packages/PackageInstaller/res/values-hy/strings.xml +++ b/packages/PackageInstaller/res/values-hy/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Այս օգտատերը չի կարող անհայտ հավելվածներ տեղադրել"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Այս օգտատիրոջը չի թույլատրվում տեղադրել հավելվածներ"</string> <string name="ok" msgid="7871959885003339302">"Եղավ"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Արխիվացնել"</string> <string name="update_anyway" msgid="8792432341346261969">"Թարմացնել"</string> <string name="manage_applications" msgid="5400164782453975580">"Կառավարել հավելվածները"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Բավարար տարածք չկա"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Ապատեղադրել թարմացումը"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> գործողությունը հետևյալ հավելվածի մասն է`"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Ուզո՞ւմ եք ապատեղադրել այս հավելվածը։"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Ձեր անձնական տվյալները կպահվեն"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Արխիվացնե՞լ այս հավելվածը բոլոր օգտատերերի համար։ Ձեր անձնական տվյալները կպահվեն"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Արխիվացնե՞լ այս հավելվածը ձեր աշխատանքային պրոֆիլում։ Ձեր անձնական տվյալները կպահվեն"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Արխիվացնե՞լ այս հավելվածը <xliff:g id="USERNAME">%1$s</xliff:g> օգտատիրոջ համար։ Ձեր անձնական տվյալները կպահվեն"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Արխիվացնե՞լ այս հավելվածը ձեր անձնական տարածքից։ Ձեր անձնական տվյալները կպահվեն"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ապատեղադրե՞լ այս հավելվածը "<b>"բոլոր"</b>" օգտատերերի համար: Հավելվածը և դրա տվյալները կհեռացվեն սարքի "<b>"բոլոր"</b>" օգտատերերից:"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Ապատեղադրե՞լ այս հավելվածը <xliff:g id="USERNAME">%1$s</xliff:g> օգտատիրոջ համար:"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Հեռացնե՞լ այս հավելվածը ձեր աշխատանքային պրոֆիլից"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Ձեր պլանշետը և անձնական տվյալներն առավել խոցելի են անհայտ հավելվածների գրոհների նկատմամբ: Տեղադրելով այս հավելվածը՝ դուք ընդունում եք, որ պատասխանատվություն եք կրում հավելվածի օգտագործման հետևանքով ձեր պլանշետին հասցված ցանկացած վնասի կամ տվյալների կորստի համար:"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Ձեր հեռուստացույցը և անձնական տվյալներն առավել խոցելի են անհայտ հավելվածների գրոհների նկատմամբ: Տեղադրելով այս հավելվածը՝ դուք ընդունում եք, որ պատասխանատվություն եք կրում հավելվածի օգտագործման հետևանքով ձեր հեռուստացույցին հասցված ցանկացած վնասի կամ տվյալների կորստի համար:"</string> <string name="cloned_app_label" msgid="7503612829833756160">"«<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>» հավելվածի կլոն"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Արխիվացնե՞լ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> հավելվածը"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Շարունակել"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Կարգավորումներ"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear հավելվածների տեղադրում/ապատեղադրում"</string> diff --git a/packages/PackageInstaller/res/values-in/strings.xml b/packages/PackageInstaller/res/values-in/strings.xml index 58db084aeb95..d4f3e76fd4b7 100644 --- a/packages/PackageInstaller/res/values-in/strings.xml +++ b/packages/PackageInstaller/res/values-in/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Aplikasi yang tidak dikenal tidak dapat diinstal oleh pengguna ini"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Pengguna ini tidak diizinkan menginstal aplikasi"</string> <string name="ok" msgid="7871959885003339302">"Oke"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Mengarsipkan"</string> <string name="update_anyway" msgid="8792432341346261969">"Tetap update"</string> <string name="manage_applications" msgid="5400164782453975580">"Kelola aplikasi"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Kehabisan ruang penyimpanan"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Uninstal update"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> adalah bagian dari aplikasi berikut:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Apakah Anda ingin meng-uninstal aplikasi ini?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Data pribadi Anda akan disimpan"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Arsipkan aplikasi ini untuk semua pengguna? Data pribadi Anda akan disimpan"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arsipkan aplikasi ini di profil kerja? Data pribadi Anda akan disimpan"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Arsipkan aplikasi untuk <xliff:g id="USERNAME">%1$s</xliff:g>? Data pribadi Anda akan disimpan"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Ingin mengarsipkan aplikasi ini dari ruang pribadi? Data pribadi Anda akan disimpan"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Apakah Anda ingin meng-uninstal aplikasi ini untuk "<b>"semua"</b>" pengguna? Aplikasi dan datanya akan dihapus dari "<b>"semua"</b>" pengguna pada perangkat."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Apakah Anda ingin meng-uninstal aplikasi ini untuk pengguna <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ingin meng-uninstal aplikasi ini dari profil kerja Anda?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tablet dan data pribadi Anda lebih rentan terhadap serangan oleh aplikasi yang tidak dikenal. Dengan menginstal aplikasi ini, Anda setuju bahwa Anda bertanggung jawab atas kerusakan tablet atau kehilangan data yang mungkin diakibatkan oleh penggunaannya."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV dan data pribadi Anda lebih rentan terhadap serangan oleh aplikasi yang tidak dikenal. Dengan menginstal aplikasi ini, Anda setuju bahwa Anda bertanggung jawab atas kerusakan TV atau kehilangan data yang mungkin diakibatkan oleh penggunaannya."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clone <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Arsipkan <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Lanjutkan"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Setelan"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Melakukan instal/uninstal aplikasi Wear"</string> diff --git a/packages/PackageInstaller/res/values-is/strings.xml b/packages/PackageInstaller/res/values-is/strings.xml index 44fc20820ce7..32b686e1a2b5 100644 --- a/packages/PackageInstaller/res/values-is/strings.xml +++ b/packages/PackageInstaller/res/values-is/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Þessi notandi getur ekki sett upp óþekkt forrit"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Þessi notandi hefur ekki leyfi til að setja upp forrit"</string> <string name="ok" msgid="7871959885003339302">"Í lagi"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Setja í geymslu"</string> <string name="update_anyway" msgid="8792432341346261969">"Uppfæra samt"</string> <string name="manage_applications" msgid="5400164782453975580">"Stj. forritum"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Ekkert pláss eftir"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Fjarlægja uppfærslu"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> er hluti af þessu forriti:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Viltu fjarlægja þetta forrit?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Persónuupplýsingarnar þínar verða vistaðar"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Setja þetta forrit í geymslu fyrir alla notendur? Persónuupplýsingarnar þínar verða vistaðar"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Setja þetta forrit á geymslu á vinnusniðinu þínu? Persónuupplýsingarnar þínar verða vistaðar"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Setja þetta forrit í geymslu fyrir <xliff:g id="USERNAME">%1$s</xliff:g>? Persónuupplýsingarnar þínar verða vistaðar"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Viltu setja þetta forrit úr einkarýminu í geymslu? Persónuupplýsingarnar þínar verða vistaðar"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Viltu fjarlægja þetta forrit hjá "<b>"öllum"</b>" notendum? Forritið og gögn þess verða fjarlægð hjá "<b>"öllum"</b>" notendum tækisins."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Viltu fjarlægja þetta forrit fyrir notandann <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Viltu fjarlægja þetta forrit af vinnuprófílnum þínum?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Spjaldtölvan þín og persónuleg gögn eru berskjaldaðri fyrir árásum forrita af óþekktum uppruna. Með uppsetningu þessa forrits samþykkirðu að bera fulla ábyrgð á hverju því tjóni sem verða kann á spjaldtölvunni eða gagnatapi sem leiða kann af notkun þess."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Sjónvarpið þitt og persónuleg gögn eru berskjaldaðri fyrir árásum forrita af óþekktum uppruna. Með uppsetningu þessa forrits samþykkirðu að bera fulla ábyrgð á hverju því tjóni sem verða kann á sjónvarpinu eða gagnatapi sem leiða kann af notkun þess."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Afrit af <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Setja <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> í geymslu?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Áfram"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Stillingar"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Uppsetning/fjarlæging Wear forrita"</string> diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml index 136a537df7e6..3fb38462eacc 100644 --- a/packages/PackageInstaller/res/values-it/strings.xml +++ b/packages/PackageInstaller/res/values-it/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Questo utente non può installare app sconosciute"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"L\'utente non è autorizzato a installare app"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archivia"</string> <string name="update_anyway" msgid="8792432341346261969">"Aggiorna comunque"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestisci app"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Spazio esaurito"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Disinstalla aggiornamento"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> fa parte della seguente applicazione:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Vuoi disinstallare questa app?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"I tuoi dati personali verranno salvati"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Vuoi archiviare questa app per tutti gli utenti? I tuoi dati personali verranno salvati"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Vuoi archiviare questa app che si trova nel tuo profilo di lavoro? I tuoi dati personali verranno salvati"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Vuoi archiviare questa app per <xliff:g id="USERNAME">%1$s</xliff:g>? I tuoi dati personali verranno salvati"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Vuoi archiviare questa app che si trova nel tuo spazio privato? I tuoi dati personali verranno salvati"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vuoi disinstallare questa applicazione per "<b>"tutti"</b>" gli utenti? L\'applicazione e i relativi dati verranno rimossi da "<b>"tutti"</b>" gli utenti configurati sul dispositivo."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Disinstallare l\'app per l\'utente <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vuoi disinstallare questa app dal tuo profilo di lavoro?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"I dati del tablet e i dati personali sono più vulnerabili agli attacchi di app sconosciute. Se installi questa app, accetti di essere responsabile degli eventuali danni al tablet o dell\'eventuale perdita di dati derivanti dall\'uso dell\'app."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"I dati della TV e i dati personali sono più vulnerabili agli attacchi di app sconosciute. Se installi questa app, accetti di essere responsabile degli eventuali danni alla TV o dell\'eventuale perdita di dati derivanti dall\'uso dell\'app."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clone di <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Vuoi archiviare <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continua"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Impostazioni"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Installazione/disinstallazione app Wear"</string> diff --git a/packages/PackageInstaller/res/values-iw/strings.xml b/packages/PackageInstaller/res/values-iw/strings.xml index 2c6f12722ac3..dcec0e02f781 100644 --- a/packages/PackageInstaller/res/values-iw/strings.xml +++ b/packages/PackageInstaller/res/values-iw/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"למשתמש הזה אין הרשאה להתקין אפליקציות שאינן מוכרות"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"למשתמש הזה אין הרשאה להתקין אפליקציות"</string> <string name="ok" msgid="7871959885003339302">"אישור"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"העברה לארכיון"</string> <string name="update_anyway" msgid="8792432341346261969">"אני רוצה לעדכן בכל זאת"</string> <string name="manage_applications" msgid="5400164782453975580">"ניהול אפליקציות"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"אין מספיק מקום"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"הסרת התקנה של עדכון"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"הפעילות <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> היא חלק מהאפליקציה הבאה:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"להסיר את ההתקנה של האפליקציה הזו?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"המידע האישי שלך יישמר"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"להעביר לארכיון את האפליקציה הזו לכל המשתמשים? המידע האישי שלך יישמר"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"להעביר את האפליקציה הזו מפרופיל העבודה לארכיון? המידע האישי שלך יישמר"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"להעביר את האפליקציה הזו של <xliff:g id="USERNAME">%1$s</xliff:g> לארכיון? המידע האישי שלך יישמר"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"להעביר את האפליקציה הזו מהמרחב הפרטי לארכיון? המידע האישי שלך יישמר"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"להסיר את האפליקציה הזו עבור "<b>"כל"</b>" המשתמשים? האפליקציה והנתונים שלה יוסרו עבור "<b>"כל"</b>" המשתמשים במכשיר."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"להסיר את ההתקנה של האפליקציה הזו עבור <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"רוצה להסיר את האפליקציה הזו מפרופיל העבודה?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"נתוני הטאבלט והנתונים האישיים שלך חשופים יותר בפני התקפות על ידי אפליקציות ממקורות לא ידועים. התקנת האפליקציה הזו מהווה את הסכמתך לכך שהאחריות הבלעדית היא שלך במקרה של אובדן נתונים או גרימת נזק לטאבלט בעקבות השימוש באפליקציה."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"נתוני הטלוויזיה והנתונים האישיים שלך חשופים יותר בפני התקפות על ידי אפליקציות ממקורות לא ידועים. התקנת האפליקציה הזו מהווה את הסכמתך לכך שהאחריות הבלעדית היא שלך במקרה של אובדן נתונים או גרימת נזק לטלוויזיה שלך בעקבות השימוש באפליקציה."</string> <string name="cloned_app_label" msgid="7503612829833756160">"שכפול של <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"להעביר את <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> לארכיון?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"המשך"</string> <string name="external_sources_settings" msgid="4046964413071713807">"הגדרות"</string> <string name="wear_app_channel" msgid="1960809674709107850">"תהליך התקנה/הסרת התקנה של אפליקציות Wear"</string> diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml index dd0d00ea9e8b..4d16b1a19dfc 100644 --- a/packages/PackageInstaller/res/values-ja/strings.xml +++ b/packages/PackageInstaller/res/values-ja/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"このユーザーは不明なアプリをインストールできません"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"このユーザーはアプリをインストールできません"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"アーカイブ"</string> <string name="update_anyway" msgid="8792432341346261969">"更新する"</string> <string name="manage_applications" msgid="5400164782453975580">"アプリの管理"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"容量不足"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"アップデートのアンインストール"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> は次のアプリの一部です。"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"このアプリをアンインストールしますか?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"個人データが保存されます"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"すべてのユーザーに対しこのアプリをアーカイブしますか?個人データが保存されます"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"仕事用プロファイルでこのアプリをアーカイブしますか?個人データが保存されます"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g> に対しこのアプリをアーカイブしますか?個人データが保存されます"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"プライベート スペースからこのアプリをアーカイブしますか?個人データが保存されます"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"このアプリを"<b>"すべての"</b>"ユーザーからアンインストールしますか?このアプリとそのデータはデバイスの"<b>"すべての"</b>"ユーザーから削除されます。"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> さんのアプリをアンインストールしますか?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"このアプリを仕事用プロファイルからアンインストールしますか?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"不明なアプリをインストールするとタブレットや個人データの侵害に対する安全性が低下します。このアプリをインストールすることで、アプリの使用により生じる可能性があるタブレットへの侵害やデータの損失について、ユーザーご自身が単独で責任を負うことに同意することになります。"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"不明なアプリをインストールするとテレビや個人データの侵害に対する安全性が低下します。このアプリをインストールすることで、アプリの使用により生じる可能性があるテレビへの侵害やデータの損失について、ユーザーご自身が単独で責任を負うことに同意することになります。"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> のクローン"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> をアーカイブしますか?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"次へ"</string> <string name="external_sources_settings" msgid="4046964413071713807">"設定"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wearアプリ インストール/アンインストール"</string> diff --git a/packages/PackageInstaller/res/values-ka/strings.xml b/packages/PackageInstaller/res/values-ka/strings.xml index 7d4c1fd7f837..1a459af93c0e 100644 --- a/packages/PackageInstaller/res/values-ka/strings.xml +++ b/packages/PackageInstaller/res/values-ka/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ამ მომხმარებელს არ შეუძლია უცნობი აპების ინსტალაცია"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ამ მომხმარებელს არ აქვს აპების ინსტალაციის უფლება"</string> <string name="ok" msgid="7871959885003339302">"კარგი"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"არქივი"</string> <string name="update_anyway" msgid="8792432341346261969">"მაინც განახლდეს"</string> <string name="manage_applications" msgid="5400164782453975580">"აპების მართვა"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"მეხსიერება არასაკმარისია"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"განახლების დეინსტალაცია"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> არის შემდეგი აპის ნაწილი:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"გსურთ ამ აპის დეინსტალაცია?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"თქვენი პერსონალური მონაცემები შეინახება"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"გსურთ ამ აპის ყველა მომხმარებლისთვის დაარქივება? თქვენი პერსონალური მონაცემები შეინახება"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"გსურთ ამ აპის დაარქივება თქვენს სამსახურის პროფილში? თქვენი პერსონალური მონაცემები შეინახება"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"გსურთ ამ აპის დაარქივება <xliff:g id="USERNAME">%1$s</xliff:g>-ისთვის? თქვენი პერსონალური მონაცემები შეინახება"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"გსურთ ამ აპის დაარქივება თქვენი კერძო სივრციდან? თქვენი პერსონალური მონაცემები შეინახება"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"გსურთ ამ აპის დეინსტალაცია "<b>"ყველა"</b>" მომხმარებლისთვის? აპლიკაცია და მისი მონაცემები ამოიშლება "<b>"ყველა"</b>" მომხმარებლის პროფილიდან მოწყობილობაზე."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"გსურთ ამ აპის დეინსტალაცია <xliff:g id="USERNAME">%1$s</xliff:g>-ისთვის?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"გსურთ ამ აპის დეინსტალაცია თქვენი სამსახურის პროფილიდან?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"თქვენი ტაბლეტი და პერსონალური მონაცემები მეტად დაუცველია უცნობი აპების მხრიდან შეტევების წინაშე. ამ აპის ინსტალაციის შემთხვევაში, თქვენ თანახმა ხართ, პასუხისმგებელი იყოთ მისი გამოყენების შედეგად ტაბლეტისთვის მიყენებულ ზიანსა თუ მონაცემების დაკარგვაზე."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"თქვენი ტელევიზორი და პერსონალური მონაცემები მეტად დაუცველია უცნობი აპების მხრიდან შეტევების წინაშე. ამ აპის ინსტალაციის შემთხვევაში, თქვენ თანახმა ხართ, პასუხისმგებელი იყოთ მისი გამოყენების შედეგად ტელევიზორისთვის მიყენებულ ზიანსა თუ მონაცემების დაკარგვაზე."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> კლონის შექმნა"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"გსურთ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-ის დაარქივება?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"გაგრძელება"</string> <string name="external_sources_settings" msgid="4046964413071713807">"პარამეტრები"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear აპების ინსტალაცია/დეინსტალაცია"</string> diff --git a/packages/PackageInstaller/res/values-kk/strings.xml b/packages/PackageInstaller/res/values-kk/strings.xml index f731bbcb8b3b..718ca1de6b79 100644 --- a/packages/PackageInstaller/res/values-kk/strings.xml +++ b/packages/PackageInstaller/res/values-kk/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Бұл пайдаланушы белгісіз қолданбаларды орната алмайды"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Бұл пайдаланушының қолданбаларды орнату рұқсаты жоқ"</string> <string name="ok" msgid="7871959885003339302">"Жарайды"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Мұрағаттау"</string> <string name="update_anyway" msgid="8792432341346261969">"Бәрібір жаңарту"</string> <string name="manage_applications" msgid="5400164782453975580">"Қолданбаларды басқару"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Орын жоқ"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Жаңа нұсқаны жою"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> келесі қолданбаның бөлігі:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Осы қолданба жойылсын ба?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Жеке деректеріңіз сақталады."</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Бұл қолданбаны барлық пайдаланушы үшін мұрағаттау керек пе? Жеке деректеріңіз сақталады."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Бұл қолданбаны жұмыс профиліңізде мұрағаттау керек пе? Жеке деректеріңіз сақталады."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Бұл қолданбаны <xliff:g id="USERNAME">%1$s</xliff:g> үшін мұрағаттау керек пе? Жеке деректеріңіз сақталады."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Осы құрылғыны жеке бөлмеңізде мұрағаттағыңыз келе ме? Жеке деректеріңіз сақталады."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Бұл қолданба "<b>"барлық"</b>" пайдаланушылар үшін жойылсын ба? Қолданба және оның деректері құрылғыдағы "<b>"барлық"</b>" пайдаланушылардан өшіріледі."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> үшін осы қолданба жойылсын ба?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Бұл қолданба жұмыс профиліңізден жойылсын ба?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Планшет және жеке деректер белгісіз қолданбалардың шабуылына ұшырауы мүмкін. Бұл қолданбаны орнату арқылы оны пайдалану нәтижесіндегі планшетке келетін залалға немесе деректердің жоғалуына өзіңіз ғана жауапты болатыныңызға келісесіз."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Теледидар және жеке деректер белгісіз қолданбалардың шабуылына ұшырауы мүмкін. Бұл қолданбаны орнату арқылы оны пайдалану нәтижесіндегі теледидарға келетін қандай да бір залалға немесе деректердің жоғалуына өзіңіз ғана жауапты болатыныңызға келісесіз."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клоны"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> белгісін мұрағаттау керек пе?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Жалғастыру"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Параметрлер"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear қолданбасын орнату/жою"</string> diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml index 7ae0ce7f6920..3034f88af187 100644 --- a/packages/PackageInstaller/res/values-km/strings.xml +++ b/packages/PackageInstaller/res/values-km/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"អ្នកប្រើប្រាស់នេះមិនអាចដំឡើងកម្មវិធីមិនស្គាល់បានទេ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"មិនអនុញ្ញាតឱ្យអ្នកប្រើប្រាស់នេះដំឡើងកម្មវិធីទេ"</string> <string name="ok" msgid="7871959885003339302">"យល់ព្រម"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"ទុកក្នុងបណ្ណសារ"</string> <string name="update_anyway" msgid="8792432341346261969">"មិនអីទេ ដំឡើងកំណែចុះ"</string> <string name="manage_applications" msgid="5400164782453975580">"គ្រប់គ្រងកម្មវិធី"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"អស់ទំហំផ្ទុក"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"លុបកំណែថ្មី"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ជាផ្នែកមួយនៃកម្មវិធីដូចខាងក្រោមនេះ៖"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"តើអ្នកចង់លុបកម្មវិធីនេះដែរទេ?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"ទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកនឹងត្រូវបានរក្សាទុក"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"ទុកកម្មវិធីនេះក្នុងបណ្ណសារសម្រាប់អ្នកប្រើប្រាស់ទាំងអស់ឬ? ទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកនឹងត្រូវបានរក្សាទុក"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ទុកកម្មវិធីនេះក្នុងបណ្ណសារនៅលើកម្រងព័ត៌មានការងាររបស់អ្នកឬ? ទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកនឹងត្រូវបានរក្សាទុក"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"ទុកកម្មវិធីនេះក្នុងបណ្ណសារសម្រាប់ <xliff:g id="USERNAME">%1$s</xliff:g> ឬ? ទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកនឹងត្រូវបានរក្សាទុក"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"តើអ្នកចង់ទុកកម្មវិធីនេះក្នុងបណ្ណសារពីលំហឯកជនរបស់អ្នកដែរទេ? ទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកនឹងត្រូវបានរក្សាទុក"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"តើអ្នកចង់លុបកម្មវិធីនេះសម្រាប់អ្នកប្រើប្រាស់"<b>"ទាំងអស់"</b>"ដែរទេ? កម្មវិធីនេះ និងទិន្នន័យរបស់វានឹងត្រូវបានលុបចេញពីអ្នកប្រើប្រាស់"<b>"ទាំងអស់"</b>"នៅលើឧបករណ៍នេះ។"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"តើអ្នកចង់លុបកម្មវិធីនេះសម្រាប់អ្នកប្រើប្រាស់ <xliff:g id="USERNAME">%1$s</xliff:g> ដែរទេ?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"តើអ្នកចង់លុបកម្មវិធីនេះពីកម្រងព័ត៌មានការងាររបស់អ្នកដែរទេ?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ថេប្លេត និងទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកងាយនឹងរងគ្រោះពីការវាយប្រហារពីកម្មវិធីដែលមិនស្គាល់។ ប្រសិនបើដំឡើងកម្មវិធីនេះ មានន័យថាអ្នកទទួលខុសត្រូវលើការខូចខាតទាំងឡាយចំពោះថេប្លេត ឬការបាត់បង់ទិន្នន័យរបស់អ្នក ដែលអាចបណ្ដាលមកពីការប្រើប្រាស់កម្មវិធីនេះ។"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ទូរទស្សន៍ និងទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នកងាយនឹងរងគ្រោះពីការវាយប្រហារពីកម្មវិធីដែលមិនស្គាល់។ ប្រសិនបើដំឡើងកម្មវិធីនេះ មានន័យថាអ្នកទទួលខុសត្រូវលើការខូចខាតទាំងឡាយចំពោះទូរទស្សន៍ ឬការបាត់បង់ទិន្នន័យរបស់អ្នក ដែលអាចបណ្ដាលមកពីការប្រើប្រាស់កម្មវិធីនេះ។"</string> <string name="cloned_app_label" msgid="7503612829833756160">"ក្លូន <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"ទុក <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ក្នុងបណ្ណសារឬ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"បន្ត"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ការកំណត់"</string> <string name="wear_app_channel" msgid="1960809674709107850">"ការដំឡើង/ការលុបកម្មវិធីឧបករណ៍ពាក់"</string> diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml index ec0746d5fa6d..e65770f5db7d 100644 --- a/packages/PackageInstaller/res/values-kn/strings.xml +++ b/packages/PackageInstaller/res/values-kn/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ಈ ಬಳಕೆದಾರರು ಅಪರಿಚಿತ ಆ್ಯಪ್ಗಳನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ಆ್ಯಪ್ಗಳನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಈ ಬಳಕೆದಾರರನ್ನು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ"</string> <string name="ok" msgid="7871959885003339302">"ಸರಿ"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"ಆರ್ಕೈವ್ ಮಾಡಿ"</string> <string name="update_anyway" msgid="8792432341346261969">"ಪರವಾಗಿಲ್ಲ, ಅಪ್ಡೇಟ್ ಮಾಡಿ"</string> <string name="manage_applications" msgid="5400164782453975580">"ಆ್ಯಪ್ ನಿರ್ವಹಿಸಿ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ಸಂಗ್ರಹಣೆ ಖಾಲಿ ಇಲ್ಲ"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"ಅಪ್ಡೇಟ್ ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ಎಂಬುದು ಕೆಳಗಿನ ಆ್ಯಪ್ನ ಭಾಗವಾಗಿದೆ:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಸೇವ್ ಮಾಡಲಾಗುತ್ತದೆ"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"ಎಲ್ಲಾ ಬಳಕೆದಾರರಿಗಾಗಿ ಈ ಆ್ಯಪ್ ಅನ್ನು ಆರ್ಕೈವ್ ಮಾಡಬೇಕೆ? ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಸೇವ್ ಮಾಡಲಾಗುತ್ತದೆ"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ನಲ್ಲಿ ಈ ಆ್ಯಪ್ ಅನ್ನು ಆರ್ಕೈವ್ ಮಾಡಬೇಕೆ? ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಸೇವ್ ಮಾಡಲಾಗುತ್ತದೆ"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"ಈ ಆ್ಯಪ್ ಅನ್ನು <xliff:g id="USERNAME">%1$s</xliff:g> ಗಾಗಿ ಆರ್ಕೈವ್ ಮಾಡಬೇಕೆ? ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಸೇವ್ ಮಾಡಲಾಗುತ್ತದೆ"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ನಿಮ್ಮ ಖಾಸಗಿ ಸ್ಪೇಸ್ನಿಂದ ಈ ಆ್ಯಪ್ ಅನ್ನು ಆರ್ಕೈವ್ ಮಾಡಲು ನೀವು ಬಯಸುತ್ತೀರಾ? ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಸೇವ್ ಮಾಡಲಾಗುತ್ತದೆ"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"ನೀವು "<b>"ಎಲ್ಲಾ"</b>" ಬಳಕೆದಾರರಿಗೂ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ? ಸಾಧನದಲ್ಲಿನ "<b>"ಎಲ್ಲಾ"</b>" ಬಳಕೆದಾರರಿಂದ ಆ್ಯಪ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ತೆಗೆದುಹಾಕಲಾಗುವುದು."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> ಬಳಕೆದಾರರಿಗೆ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ನೀವು ಬಯಸುವಿರಾ?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ನಿಂದ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ನೀವು ಬಯಸುವಿರಾ?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಹಾಗೂ ವೈಯಕ್ತಿಕ ಡೇಟಾ, ಅಪರಿಚಿತ ಆ್ಯಪ್ಗಳ ದಾಳಿಗೆ ತುತ್ತಾಗುವ ಸಾಧ್ಯತೆ ಹೆಚ್ಚಾಗಿದೆ. ಈ ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡುವ ಮೂಲಕ, ನಿಮ್ಮ ಫೋನ್ಗೆ ಯಾವುದೇ ಹಾನಿ ಉಂಟಾದರೆ ಅಥವಾ ಅದರ ಬಳಕೆಯಿಂದ ಡೇಟಾ ನಷ್ಟವಾದರೆ, ಅದಕ್ಕೆ ನೀವೇ ಜವಾಬ್ದಾರರು ಎನ್ನುವುದನ್ನು ಒಪ್ಪಿಕೊಳ್ಳುತ್ತೀರಿ."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ನಿಮ್ಮ ಟಿವಿ ಹಾಗೂ ವೈಯಕ್ತಿಕ ಡೇಟಾ, ಅಪರಿಚಿತ ಆ್ಯಪ್ಗಳ ದಾಳಿಗೆ ತುತ್ತಾಗುವ ಸಾಧ್ಯತೆ ಹೆಚ್ಚಾಗಿದೆ. ಈ ಆ್ಯಪ್ ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡುವ ಮೂಲಕ, ನಿಮ್ಮ ಟಿವಿಗೆ ಯಾವುದೇ ಹಾನಿ ಉಂಟಾದರೆ ಅಥವಾ ಅದರ ಬಳಕೆಯಿಂದ ಡೇಟಾ ನಷ್ಟವಾದರೆ, ಅದಕ್ಕೆ ನೀವೇ ಜವಾಬ್ದಾರರು ಎನ್ನುವುದನ್ನು ಒಪ್ಪಿಕೊಳ್ಳುತ್ತೀರಿ."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ಕ್ಲೋನ್"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ಅನ್ನು ಆರ್ಕೈವ್ ಮಾಡಬೇಕೆ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ಮುಂದುವರಿಸಿ"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="wear_app_channel" msgid="1960809674709107850">"wear ಆ್ಯಪ್ಗಳನ್ನು ಇನ್ಸ್ಟಾಲ್/ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml index 9fbff25632d9..fbe896972d8f 100644 --- a/packages/PackageInstaller/res/values-ko/strings.xml +++ b/packages/PackageInstaller/res/values-ko/strings.xml @@ -28,7 +28,7 @@ <string name="install_confirm_question_update" msgid="3348888852318388584">"이 앱을 업데이트하시겠습니까?"</string> <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p><b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>에서</b>?</p><p>이 앱을 업데이트하세요. 이 앱은 보통<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>에서 업데이트를 받습니다. 다른 출처에서 업데이트를 받으면 향후 태블릿에 있는 어떤 출처에서든지 업데이트를 받을 수 있습니다. 앱 기능이 변경될 수 있습니다.</p>"</string> <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p><b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>에서</b>?</p><p>이 앱을 업데이트하세요. 이 앱은 보통<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>에서 업데이트를 받습니다. 다른 출처에서 앱을 업데이트하면 향후 TV에 있는 어떤 출처에서든지 업데이트를 받을 수 있습니다. 앱 기능이 변경될 수 있습니다.</p>"</string> - <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p><b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g>에서</b>?</p><p>이 앱을 업데이트하세요. 이 앱은 보통<b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>에서 업데이트를 받습니다. 다른 출처에서 업데이트를 받으면 향후 휴대전화에 있는 어떤 출처든지 업데이트를 받을 수 있습니다. 앱 기능이 변경될 수 있습니다.</p>"</string> + <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p><b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>에서 이 앱을 업데이트하시겠어요?</p><p>이 앱은 보통 <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>에서 업데이트를 받습니다. 다른 출처에서 앱을 업데이트하면 향후 휴대전화에 있는 어떤 출처에서나 업데이트를 받을 수 있으며, 앱 기능이 변경될 수 있습니다.</p>"</string> <string name="install_failed" msgid="5777824004474125469">"앱이 설치되지 않았습니다."</string> <string name="install_failed_blocked" msgid="8512284352994752094">"패키지 설치가 차단되었습니다."</string> <string name="install_failed_conflict" msgid="3493184212162521426">"패키지가 기존 패키지와 충돌하여 앱이 설치되지 않았습니다."</string> @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"이 사용자는 알 수 없는 앱을 설치할 수 없습니다."</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"이 사용자는 앱을 설치할 권한이 없습니다."</string> <string name="ok" msgid="7871959885003339302">"확인"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"보관처리"</string> <string name="update_anyway" msgid="8792432341346261969">"업데이트"</string> <string name="manage_applications" msgid="5400164782453975580">"앱 관리"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"여유 공간이 없음"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"업데이트 제거"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>은(는) 다음 앱의 일부입니다."</string> <string name="uninstall_application_text" msgid="3816830743706143980">"이 앱을 제거하시겠습니까?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"내 개인 정보가 저장됩니다."</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"모든 사용자를 대상으로 이 앱을 보관처리하시겠습니까? 내 개인 정보가 저장됩니다."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"직장 프로필에서 이 앱을 보관처리하시겠습니까? 내 개인 정보가 저장됩니다."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g>님을 대상으로 이 앱을 보관처리하시겠습니까? 내 개인 정보가 저장됩니다."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"비공개 스페이스에서 이 앱을 보관처리하시겠습니까? 내 개인 정보가 저장됩니다."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119"><b>"모든"</b>" 사용자에 대해 이 앱을 제거하시겠습니까? 기기를 사용하는 "<b>"모든"</b>" 사용자에 대해 애플리케이션 및 데이터가 삭제됩니다."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g>님의 기기에 설치된 앱을 제거하시겠습니까?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"직장 프로필에서 이 앱을 제거하시겠습니까?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"태블릿과 개인 데이터는 알 수 없는 앱의 공격에 더욱 취약합니다. 이 앱을 설치하면 앱 사용으로 인해 발생할 수 있는 모든 태블릿 손상이나 데이터 손실에 사용자가 책임을 진다는 것에 동의하게 됩니다."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV와 개인 데이터는 알 수 없는 앱의 공격에 더욱 취약합니다. 이 앱을 설치하면 앱 사용으로 인해 발생할 수 있는 모든 TV 손상이나 데이터 손실에 사용자가 책임을 진다는 것에 동의하게 됩니다."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> 복제"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> 앱을 보관처리하시겠습니까?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"계속"</string> <string name="external_sources_settings" msgid="4046964413071713807">"설정"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear 앱 설치/제거"</string> diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml index b6d3e215eb6f..8b2d425ebb27 100644 --- a/packages/PackageInstaller/res/values-ky/strings.xml +++ b/packages/PackageInstaller/res/values-ky/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Бул колдонуучу белгисиз колдонмолорду орното албайт"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Бул колдонуучу колдонмолорду орното албайт"</string> <string name="ok" msgid="7871959885003339302">"ЖАРАЙТ"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Архивдөө"</string> <string name="update_anyway" msgid="8792432341346261969">"Баары бир жаңыртылсын"</string> <string name="manage_applications" msgid="5400164782453975580">"Колд. башкаруу"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Бош орун жок"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Жаңыртууну чыгарып салуу"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> төмөнкү колдонмонун бөлүгү:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Бул колдонмону чыгарып саласызбы?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Жеке маалыматыңыз сакталат"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Бул колдонмо бардык колдонуучулар үчүн архивделсинби? Жеке маалыматыңыз сакталат"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Бул колдонмо жумуш профилиңизде архивделсинби? Жеке маалыматыңыз сакталат"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Бул колдонмо <xliff:g id="USERNAME">%1$s</xliff:g> үчүн архивделсинби? Жеке маалыматыңыз сакталат"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Бул колдонмо жеке чөйрөдөн архивделсинби? Жеке маалыматыңыз сакталат"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Бул колдонмо "<b>"бардык"</b>" колдонуучулардан алынып салынсынбы? Бул колдонмо жана анын дайындары бул түзмөктүн "<b>"бардык"</b>" колдонуучуларынан өчүрүлөт."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Бул колдонмону <xliff:g id="USERNAME">%1$s</xliff:g> үчүн чыгарып саласызбы?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Бул колдонмону жумуш профилиңизден чыгарып саласызбы?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Планшетиңиз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам планшетиңизге кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Сыналгыңыз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам сыналгыңызга кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клону"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> архивделсинби?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Улантуу"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Параметрлер"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Тагынма колдонмолорду орнотуу/чыгаруу"</string> diff --git a/packages/PackageInstaller/res/values-lo/strings.xml b/packages/PackageInstaller/res/values-lo/strings.xml index d9b33ffa6214..8a9539807b81 100644 --- a/packages/PackageInstaller/res/values-lo/strings.xml +++ b/packages/PackageInstaller/res/values-lo/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ຜູ້ໃຊ້ນີ້ບໍ່ສາມາດຕິດຕັ້ງແອັບທີ່ບໍ່ຮູ້ຈັກໄດ້"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ຜູ້ໃຊ້ນີ້ບໍ່ໄດ້ຮັບອະນຸຍາດໃຫ້ຕິດຕັ້ງແອັບໄດ້"</string> <string name="ok" msgid="7871959885003339302">"ຕົກລົງ"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"ເກັບໄວ້ໃນແຟ້ມ"</string> <string name="update_anyway" msgid="8792432341346261969">"ຢືນຢັນການອັບເດດ"</string> <string name="manage_applications" msgid="5400164782453975580">"ຈັດການແອັບ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ພື້ນທີ່ຫວ່າງບໍ່ພຽງພໍ"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"ຖອນການຕິດຕັ້ງອັບເດດ"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ແມ່ນສ່ວນໜຶ່ງຂອງແອັບຕໍ່ໄປນີ້:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ບໍ່?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"ລະບົບຈະບັນທຶກຂໍ້ມູນສ່ວນຕົວຂອງທ່ານໄວ້"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"ເກັບແອັບນີ້ໄວ້ໃນແຟ້ມສຳລັບຜູ້ໃຊ້ທຸກຄົນບໍ? ລະບົບຈະບັນທຶກຂໍ້ມູນສ່ວນຕົວຂອງທ່ານໄວ້"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ເກັບແອັບນີ້ໄວ້ໃນແຟ້ມຢູ່ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານບໍ? ລະບົບຈະບັນທຶກຂໍ້ມູນສ່ວນຕົວຂອງທ່ານໄວ້"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"ເກັບແອັບນີ້ໄວ້ໃນແຟ້ມສຳລັບ <xliff:g id="USERNAME">%1$s</xliff:g> ບໍ? ລະບົບຈະບັນທຶກຂໍ້ມູນສ່ວນຕົວຂອງທ່ານໄວ້"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ທ່ານຕ້ອງການເກັບແອັບນີ້ໄວ້ໃນແຟ້ມແຍກຈາກພື້ນທີ່ສ່ວນຕົວຂອງທ່ານບໍ? ລະບົບຈະບັນທຶກຂໍ້ມູນສ່ວນຕົວຂອງທ່ານໄວ້"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"ທ່ານຕ້ອງການທີ່ຈະຖອນການຕິດຕັ້ງແອັບນີ້ສຳລັງຜູ້ໃຊ້"<b>"ທຸກຄົນ"</b>"ບໍ່? ແອັບພລິເຄຊັນ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກຈາກຜູ້ໃຊ້"<b>"ທັງໝົດ"</b>"ໃນອຸປະກອນນີ້."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ສຳລັບຜູ້ໃຊ້ <xliff:g id="USERNAME">%1$s</xliff:g> ບໍ່?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ຈາກໂປຣໄຟລ໌ບ່ອນເຮັດວຽກບໍ?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ແທັບເລັດ ແລະ ຂໍ້ມູນສ່ວນຕົວຂອງທ່ານອາດຖືກໂຈມຕີໄດ້ໂດຍແອັບທີ່ບໍ່ຮູ້ຈັກ. ໂດຍການຕິດຕັ້ງແອັບນີ້, ແມ່ນທ່ານຍອມຮັບວ່າທ່ານຈະຮັບຜິດຊອບຕໍ່ຄວາມເສຍຫາຍໃດໆກໍຕາມທີ່ເກີດຂຶ້ນຕໍ່ໂທລະທັດຂອງທ່ານ ຫຼື ການສູນເສຍຂໍ້ມູນທີ່ອາດເກີດຈາກການນຳໃຊ້ມັນ."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ໂທລະທັດ ແລະ ຂໍ້ມູນສ່ວນຕົວຂອງທ່ານອາດຖືກໂຈມຕີໄດ້ໂດຍແອັບທີ່ບໍ່ຮູ້ຈັກ. ໂດຍການຕິດຕັ້ງແອັບນີ້, ແມ່ນທ່ານຍອມຮັບວ່າທ່ານຈະຮັບຜິດຊອບຕໍ່ຄວາມເສຍຫາຍໃດໆກໍຕາມທີ່ເກີດຂຶ້ນຕໍ່ໂທລະທັດຂອງທ່ານ ຫຼື ການສູນເສຍຂໍ້ມູນທີ່ອາດເກີດຈາກການນຳໃຊ້ມັນ."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ໂຄລນ"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"ເກັບ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ໄວ້ໃນແຟ້ມບໍ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ສືບຕໍ່"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ການຕັ້ງຄ່າ"</string> <string name="wear_app_channel" msgid="1960809674709107850">"ການຕິດຕັ້ງ/ຖອນການຕິດຕັ້ງແອັບ Wear"</string> diff --git a/packages/PackageInstaller/res/values-lt/strings.xml b/packages/PackageInstaller/res/values-lt/strings.xml index b5ae480f4ec2..47778ec23121 100644 --- a/packages/PackageInstaller/res/values-lt/strings.xml +++ b/packages/PackageInstaller/res/values-lt/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Šis naudotojas negali diegti nežinomų programų"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Šiam naudotojui neleidžiama diegti programų"</string> <string name="ok" msgid="7871959885003339302">"Gerai"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archyvuoti"</string> <string name="update_anyway" msgid="8792432341346261969">"Vis tiek atnaujinti"</string> <string name="manage_applications" msgid="5400164782453975580">"Tvark. progr."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nėra vietos"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Pašalinti naujinį"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"Veikla „<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>“ yra toliau nurodytos programos dalis."</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Ar norite pašalinti šią programą?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Jūsų asmens duomenys bus išsaugoti"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Archyvuoti šią programą visiems naudotojams? Jūsų asmens duomenys bus išsaugoti"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Archyvuoti šią programą darbo profilyje? Jūsų asmens duomenys bus išsaugoti"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Archyvuoti šią programą naudotojui (-ai) (<xliff:g id="USERNAME">%1$s</xliff:g>)? Jūsų asmens duomenys bus išsaugoti"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Ar norite archyvuoti šią programą iš privačios erdvės? Jūsų asmens duomenys bus išsaugoti"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ar norite pašalinti šią programą "<b>"visiems"</b>" naudotojams? Programa ir jos duomenys bus pašalinti "<b>"visiems"</b>" įrenginio naudotojams."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Ar norite pašalinti šią naudotojo <xliff:g id="USERNAME">%1$s</xliff:g> programą?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ar norite pašalinti šią programą iš savo darbo profilio?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Planšetinis kompiuteris ir asmens duomenys labiau pažeidžiami įdiegus nežinomų programų. Įdiegdami šią programą sutinkate, kad patys esate atsakingi už žalą planšetiniam kompiuteriui arba prarastus duomenis dėl šios programos naudojimo."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV ir asmens duomenys labiau pažeidžiami įdiegus nežinomų programų. Įdiegdami šią programą sutinkate, kad patys esate atsakingi už žalą TV arba prarastus duomenis dėl šios programos naudojimo."</string> <string name="cloned_app_label" msgid="7503612829833756160">"„<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>“ kopija"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Archyvuoti „<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>“?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Tęsti"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Nustatymai"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Įdiegiamos / pašalinamos „Wear“ program."</string> diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml index 61b539228f77..b129706d572a 100644 --- a/packages/PackageInstaller/res/values-lv/strings.xml +++ b/packages/PackageInstaller/res/values-lv/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Šis lietotājs nevar instalēt nezināmas lietotnes"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Šim lietotājam nav atļauts instalēt lietotnes"</string> <string name="ok" msgid="7871959885003339302">"Labi"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arhivēt"</string> <string name="update_anyway" msgid="8792432341346261969">"Tik un tā atjaunināt"</string> <string name="manage_applications" msgid="5400164782453975580">"Pārv. lietotnes"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nav brīvas vietas"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Atinstalēt atjauninājumu"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ir daļa no šādas lietotnes:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Vai vēlaties atinstalēt šo lietotni?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Jūsu personas dati tiks saglabāti."</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Vai arhivēt šo lietotni visiem lietotājiem? Jūsu personas dati tiks saglabāti."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Vai arhivēt šo lietotni jūsu darba profilā? Jūsu personas dati tiks saglabāti."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Vai arhivēt šo lietotāja <xliff:g id="USERNAME">%1$s</xliff:g> lietotni? Jūsu personas dati tiks saglabāti."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Vai vēlaties arhivēt šo lietotni no savas privātās telpas? Jūsu personas dati tiks saglabāti."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vai vēlaties atinstalēt šo lietotni "<b>"visiem"</b>" lietotājiem? Šī lietojumprogramma un tās dati tiks noņemti no "<b>"visiem"</b>" ierīces lietotāju kontiem."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Vai vēlaties atinstalēt šo lietotni lietotājam <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vai vēlaties atinstalēt šo lietotni no sava darba profila?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Jūsu planšetdators un personas dati ir neaizsargātāki pret uzbrukumiem no nezināmām lietotnēm. Instalējot šo lietotni, jūs piekrītat, ka esat atbildīgs par planšetdatora bojājumiem vai datu zudumu, kas var rasties lietotnes dēļ."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Jūsu televizors un personas dati ir neaizsargātāki pret uzbrukumiem no nezināmām lietotnēm. Instalējot šo lietotni, jūs piekrītat, ka esat atbildīgs par televizora bojājumiem vai datu zudumu, kas var rasties lietotnes dēļ."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Lietotnes <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> klons"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Vai arhivēt lietotni <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Tālāk"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Iestatījumi"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear lietotņu instalēšana/atinstalēšana"</string> diff --git a/packages/PackageInstaller/res/values-mk/strings.xml b/packages/PackageInstaller/res/values-mk/strings.xml index 300ef67b4312..f453f57ab480 100644 --- a/packages/PackageInstaller/res/values-mk/strings.xml +++ b/packages/PackageInstaller/res/values-mk/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Корисников не може да инсталира непознати апликации"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"На корисников не му е дозволено да инсталира апликации"</string> <string name="ok" msgid="7871959885003339302">"Во ред"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Архивирај"</string> <string name="update_anyway" msgid="8792432341346261969">"Сепак ажурирај"</string> <string name="manage_applications" msgid="5400164782453975580">"Управување со апликациите"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Нема простор"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Деинсталирајте ажурирање"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> е дел од следната апликација:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Дали сакате да ја деинсталирате оваа апликација?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Вашите лични податоци ќе се зачуваат"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Да се архивира апликацијава за сите корисници? Вашите лични податоци ќе се зачуваат"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Да се архивира апликацијава на вашиот работен профил? Вашите лични податоци ќе се зачуваат"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Да се архивира апликацијава за <xliff:g id="USERNAME">%1$s</xliff:g>? Вашите лични податоци ќе се зачуваат"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Дали сакате да ја архивирате апликацијава од вашиот „Приватен простор“? Вашите лични податоци ќе се зачуваат"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Дали сакате да ја деинсталирате оваа апликација за "<b>"сите"</b>" корисници? Апликацијата и нејзините податоци ќе се отстранат од "<b>"сите"</b>" корисници на уредот."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Дали сакате да ја деинсталирате апликацијава за корисникот <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Дали сакате да ја деинсталирате апликацијава од работниот профил?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Таблетот и личните податоци се поподложни на напади од апликации од непознати извори. Ако ја инсталирате апликацијава, се согласувате дека сте одговорни за каква било штета на таблетот или загуба на податоци поради нејзиното користење."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Телевизорот и личните податоци се поподложни на напади од апликации од непознати извори. Ако ја инсталирате апликацијава, се согласувате дека сте одговорни за каква било штета на телевизорот или загуба на податоци поради нејзиното користење."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Клон на <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Да се архивира <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Продолжи"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Поставки"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Се инсталираат/деинсталираат аплик. Wear"</string> diff --git a/packages/PackageInstaller/res/values-ml/strings.xml b/packages/PackageInstaller/res/values-ml/strings.xml index 7f071f6289ae..f193acb5a874 100644 --- a/packages/PackageInstaller/res/values-ml/strings.xml +++ b/packages/PackageInstaller/res/values-ml/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ഈ ഉപയോക്താവിന്, അജ്ഞാത ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യാനാവില്ല"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യാൻ ഈ ഉപയോക്താവിന് അനുവാദമില്ല"</string> <string name="ok" msgid="7871959885003339302">"ശരി"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"ആർക്കൈവ് ചെയ്യുക"</string> <string name="update_anyway" msgid="8792432341346261969">"എന്തായാലും അപ്ഡേറ്റ് ചെയ്യുക"</string> <string name="manage_applications" msgid="5400164782453975580">"ആപ്പുകൾ മാനേജ് ചെയ്യുക"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ഇടമില്ല"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"അപ്ഡേറ്റ്, അൺ ഇൻസ്റ്റാൾ ചെയ്യുക"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>, ഇനിപ്പറയുന്ന ആപ്പിന്റെ ഭാഗമാണ് :"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ഈ ആപ്പ് അൺ ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"നിങ്ങളുടെ വ്യക്തിപരമായ ഡാറ്റ സംരക്ഷിക്കും"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"എല്ലാ ഉപയോക്താക്കൾക്കുമായി ഈ ആപ്പ് ആർക്കൈവ് ചെയ്യണോ? നിങ്ങളുടെ വ്യക്തിപരമായ ഡാറ്റ സംരക്ഷിക്കും"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ ഈ ആപ്പ് ആർക്കൈവ് ചെയ്യണോ? നിങ്ങളുടെ വ്യക്തിപരമായ ഡാറ്റ സംരക്ഷിക്കും"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g> എന്നയാൾക്കായി ഈ ആപ്പ് ആർക്കൈവ് ചെയ്യണോ? നിങ്ങളുടെ വ്യക്തിപരമായ ഡാറ്റ സംരക്ഷിക്കും"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"നിങ്ങളുടെ സ്വകാര്യ സ്പേസിൽ നിന്ന് ഈ ആപ്പ് ആർക്കൈവ് ചെയ്യണോ? നിങ്ങളുടെ വ്യക്തിപരമായ ഡാറ്റ സംരക്ഷിക്കും"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"ഈ അപ്പ് "<b>"എല്ലാ"</b>" ഉപയോക്താക്കൾക്കുമായി അൺ ഇൻസ്റ്റാൾ ചെയ്യണോ? ഉപകരണത്തിലെ "<b>"എല്ലാ"</b>" ഉപയോക്താക്കളിൽ നിന്നും ആപ്പും അതിന്റെ ഡാറ്റയും നീക്കം ചെയ്യപ്പെടും."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> എന്ന ഉപയോക്താവിനായി ഈ ആപ്പ് അൺ ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ നിന്ന് ഈ ആപ്പ് അൺ ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"അജ്ഞാതമായ ആപ്പുകളാൽ നിങ്ങളുടെ ടാബ്ലെറ്റും വ്യക്തിഗത ഡാറ്റയും ആക്രമിക്കപ്പെടാനുള്ള സാധ്യത വളരെ കൂടുതലാണ്. ഈ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യുന്നതിലൂടെ, ഇത് ഉപയോഗിക്കുന്നതിനാൽ നിങ്ങളുടെ ടാബ്ലെറ്റിന് സംഭവിച്ചേക്കാവുന്ന ഏത് നാശനഷ്ടത്തിന്റെയും അല്ലെങ്കിൽ ഡാറ്റാ നഷ്ടത്തിന്റെയും ഉത്തരവാദിത്തം നിങ്ങൾക്കായിരിക്കുമെന്ന് അംഗീകരിക്കുന്നു."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"അജ്ഞാതമായ ആപ്പുകളാൽ നിങ്ങളുടെ ടിവിയും വ്യക്തിഗത ഡാറ്റയും ആക്രമിക്കപ്പെടാനുള്ള സാധ്യത വളരെ കൂടുതലാണ്. ഈ ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യുന്നതിലൂടെ, ഇത് ഉപയോഗിക്കുന്നതിനാൽ നിങ്ങളുടെ ടിവിക്ക് സംഭവിച്ചേക്കാവുന്ന ഏത് നാശനഷ്ടത്തിന്റെയും അല്ലെങ്കിൽ ഡാറ്റാ നഷ്ടത്തിന്റെയും ഉത്തരവാദിത്തം നിങ്ങൾക്കായിരിക്കുമെന്ന് അംഗീകരിക്കുന്നു."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ക്ലോൺ ചെയ്യൽ"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ആർക്കൈവ് ചെയ്യണോ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"തുടരുക"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ക്രമീകരണം"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear ആപ്പ് ഇൻസ്റ്റാൾ/അൺ ഇൻസ്റ്റാൾ ചെയ്യുന്നു"</string> diff --git a/packages/PackageInstaller/res/values-mn/strings.xml b/packages/PackageInstaller/res/values-mn/strings.xml index 35beb1414dfc..091778f4f1e6 100644 --- a/packages/PackageInstaller/res/values-mn/strings.xml +++ b/packages/PackageInstaller/res/values-mn/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Энэ хэрэглэгч тодорхойгүй апп суулгах боломжгүй"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Энэ хэрэглэгч нь апп суулгах зөвшөөрөлгүй байна"</string> <string name="ok" msgid="7871959885003339302">"ОК"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Архивлах"</string> <string name="update_anyway" msgid="8792432341346261969">"Ямартай ч шинэчлэх"</string> <string name="manage_applications" msgid="5400164782453975580">"Аппуудыг удирдах"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Орон зай дутагдаж байна"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Шинэчлэлтийг устгах"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> нь дараах аппын хэсэг болно:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Та энэ аппыг устгахыг хүсэж байна уу?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Таны хувийн өгөгдлийг хадгална"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Энэ аппыг бүх хэрэглэгчид архивлах уу? Таны хувийн өгөгдлийг хадгална"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Энэ аппыг таны ажлын профайлд архивлах уу? Таны хувийн өгөгдлийг хадгална"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Энэ аппыг <xliff:g id="USERNAME">%1$s</xliff:g>-д архивлах уу? Таны хувийн өгөгдлийг хадгална"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Та энэ аппыг хувийн орон зайнаасаа архивлахыг хүсэж байна уу? Таны хувийн өгөгдлийг хадгална"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Та энэ аппыг "<b>"бүх"</b>" хэрэглэгчээс устгахыг хүсэж байна уу? Апп болон доторх өгөгдлийг төхөөрөмж дээрх "<b>"бүх"</b>" хэрэглэгчээс устгана."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Та энэ аппыг <xliff:g id="USERNAME">%1$s</xliff:g> хэрэглэгчийн өмнөөс устгахыг хүсэж байна уу?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Та энэ аппыг ажлын профайлаасаа устгахыг хүсэж байна уу?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Таны таблет болон хувийн өгөгдөл тодорхойгүй апп суулгасан тохиолдолд гэмтэж болзошгүй. Энэ аппыг суулгаснаар үүнийг ашигласнаас үүдэн таны таблетад гэмтэл гарах, эсвэл өгөгдөл устах зэрэг эрсдэлийг хариуцна гэдгээ зөвшөөрч байна."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Таны ТВ болон хувийн өгөгдөл тодорхойгүй апп суулгасан тохиолдолд гэмтэж болзошгүй. Энэ аппыг суулгаснаар үүнийг ашигласнаас үүдэн таны ТВ-д гэмтэл гарах, эсвэл өгөгдөл устах зэрэг эрсдэлийг хариуцна гэдгээ зөвшөөрч байна."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клон"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-г архивлах уу?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Үргэлжлүүлэх"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Тохиргоо"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear аппуудыг суулгаж/устгаж байна"</string> diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml index 44a0e278e2e0..a8c9bd0943d7 100644 --- a/packages/PackageInstaller/res/values-mr/strings.xml +++ b/packages/PackageInstaller/res/values-mr/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"या वापरकर्त्याद्वारे अज्ञात अॅप्स इंस्टॉल केली जाऊ शकत नाहीत"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"या वापरकर्त्याला अॅप्स इंस्टॉल करण्याची अनुमती नाही"</string> <string name="ok" msgid="7871959885003339302">"ओके"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"संग्रहित करा"</string> <string name="update_anyway" msgid="8792432341346261969">"तरीही अपडेट करा"</string> <string name="manage_applications" msgid="5400164782453975580">"अॅप्स व्यवस्थापन"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"जागा संपली"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"अपडेट अनइंस्टॉल करा"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> खालील ॲपचा भाग आहे:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"तुम्हाला हे अॅप अनइंस्टॉल करायचे आहे का?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"तुमचा वैयक्तिक डेटा सेव्ह केला जाईल"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"सर्व वापरकर्त्यांसाठी हे ॲप संग्रहित करायचे आहे का? तुमचा वैयक्तिक डेटा सेव्ह केला जाईल"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"तुमच्या कार्य प्रोफाइलवर हे ॲप संग्रहित करायचे आहे का? तुमचा वैयक्तिक डेटा सेव्ह केला जाईल"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g> साठी हे ॲप संग्रहित करायचे आहे का? तुमचा वैयक्तिक डेटा सेव्ह केला जाईल"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"तुम्हाला तुमच्या खाजगी स्पेसमधून हे ॲप संग्रहित करायचे आहे का? तुमचा वैयक्तिक डेटा सेव्ह केला जाईल"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"तुम्हाला हे अॅप "<b>"सर्व"</b>" वापरकर्त्यांसाठी अनइंस्टॉल करायचे आहे का? अॅप्लिकेशन आणि त्याचा डेटा डिव्हाइसवरील "<b>"सर्व"</b>" वापरकर्त्यांकडून काढला जाईल."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"तुम्हाला <xliff:g id="USERNAME">%1$s</xliff:g> वापरकर्त्यासाठी हे अॅप अनइंस्टॉल करायचे आहे का?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"तुम्हाला तुमच्या कार्य प्रोफाइलमधून हे ॲप अनइंस्टॉल करायचे आहे का?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"तुमचा टॅबलेट आणि वैयक्तिक डेटा अज्ञात अॅप्सकडून होणार्या अटॅकमुळे अधिक असुरक्षित आहे. हे अॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्याने तुमच्या टॅबलेटचे कोणत्याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्ही जबाबदार आहात."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तुमचा टीव्ही आणि वैयक्तिक डेटा अज्ञात अॅप्सकडून होणार्या अटॅकमुळे अधिक असुरक्षित आहे. हे अॅप इंस्टॉल करून, तुम्ही सहमती देता की ते वापरल्याने तुमच्या टीव्हीचे कोणत्याही प्रकारे होणारे नुकसान किंवा डेटा हानीसाठी तुम्ही जबाबदार आहात."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> क्लोन केलेले"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> संग्रहित करायचे आहे का?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"सुरू ठेवा"</string> <string name="external_sources_settings" msgid="4046964413071713807">"सेटिंग्ज"</string> <string name="wear_app_channel" msgid="1960809674709107850">"wear अॅप्स इंस्टॉल/अनइंस्टॉल करत आहे"</string> diff --git a/packages/PackageInstaller/res/values-ms/strings.xml b/packages/PackageInstaller/res/values-ms/strings.xml index 489c74e8d702..5b4ed96a3431 100644 --- a/packages/PackageInstaller/res/values-ms/strings.xml +++ b/packages/PackageInstaller/res/values-ms/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Apl yang tidak diketahui tidak boleh dipasang oleh pengguna ini"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Pengguna ini tidak dibenarkan memasang apl"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arkib"</string> <string name="update_anyway" msgid="8792432341346261969">"Kemas kinikan juga"</string> <string name="manage_applications" msgid="5400164782453975580">"Urus apl"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Kehabisan ruang"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Nyahpasang kemas kini"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> merupakan sebahagian daripada apl berikut:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Adakah anda mahu menyahpasang apl ini?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Data peribadi anda akan disimpan"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Arkibkan apl ini untuk semua pengguna? Data peribadi anda akan disimpan"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arkibkan apl ini dalam profil kerja anda? Data peribadi anda akan disimpan"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Arkibkan apl ini untuk <xliff:g id="USERNAME">%1$s</xliff:g>? Data peribadi anda akan disimpan"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Adakah anda mahu mengarkibkan apl ini daripada ruang peribadi anda? Data peribadi anda akan disimpan"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Adakah anda mahu menyahpasang apl ini untuk "<b>"semua"</b>" pengguna? Aplikasi dan datanya akan dialih keluar daripada "<b>"semua"</b>" pengguna pada peranti."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Adakah anda ingin menyahpasang apl ini untuk pengguna <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Adakah anda mahu menyahpasang apl ini daripada profil kerja anda?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tablet dan data peribadi anda lebih mudah diserang oleh apl yang tidak diketahui. Dengan memasang apl ini, anda bersetuju bahawa anda bertanggungjawab atas sebarang kerosakan pada tablet anda atau kehilangan data yang mungkin disebabkan oleh penggunaan apl tersebut."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV dan data peribadi anda lebih mudah diserang oleh apl yang tidak diketahui. Dengan memasang apl ini, anda bersetuju bahawa anda bertanggungjawab atas sebarang kerosakan pada TV anda atau kehilangan data yang mungkin disebabkan oleh penggunaan apl tersebut."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Arkibkan <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Teruskan"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Tetapan"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Memasang/menyahpasang apl wear"</string> diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml index bc2cb8e06fa3..d34d36336c6e 100644 --- a/packages/PackageInstaller/res/values-my/strings.xml +++ b/packages/PackageInstaller/res/values-my/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"အရင်းအမြစ်မသိသော အက်ပ်များကို ဤအသုံးပြုသူက ထည့်သွင်းခွင့်မရှိပါ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ဤအသုံးပြုသူသည် အက်ပ်များကို ထည့်သွင်းခွင့်မရှိပါ"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"သိမ်းရန်"</string> <string name="update_anyway" msgid="8792432341346261969">"ဘာဖြစ်ဖြစ် အပ်ဒိတ်လုပ်ရန်"</string> <string name="manage_applications" msgid="5400164782453975580">"အက်ပ်စီမံခြင်း"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"နေရာလွတ်မရှိပါ"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"အပ်ဒိတ်ကို ဖယ်ရှားရန်"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> သည် အောက်ပါအက်ပ်၏ တစ်စိတ်တစ်ဒေသဖြစ်သည်−"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ဤအက်ပ်ကို ဖယ်ရှားလိုပါသလား။"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"သင့်ကိုယ်ရေးအချက်အလက်ကို သိမ်းပါမည်"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"ဤအက်ပ်ကို အသုံးပြုသူအားလုံးအတွက် သိမ်းမလား။ သင့်ကိုယ်ရေးအချက်အလက်ကို သိမ်းပါမည်"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ဤအက်ပ်ကို သင့်အလုပ်ပရိုဖိုင်တွင် သိမ်းမလား။ သင့်ကိုယ်ရေးအချက်အလက်ကို သိမ်းပါမည်"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"ဤအက်ပ်ကို <xliff:g id="USERNAME">%1$s</xliff:g> အတွက် သိမ်းမလား။ သင့်ကိုယ်ရေးအချက်အလက်ကို သိမ်းပါမည်"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ဤအက်ပ်ကို သင့်သီးသန့်နေရာတွင် သိမ်းလိုသလား။ သင့်ကိုယ်ရေးအချက်အလက်ကို သိမ်းပါမည်"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"ဤအပလီကေးရှင်းကို အသုံးပြုသူ "<b>"အားလုံး"</b>" အတွက် ဖယ်ရှားလိုပါသလား။ ဤအပလီကေးရှင်းနှင့် သက်ဆိုင်ရာ အချက်အလက်များ အားလုံးကို "<b>" က "</b>" စက်အသုံးပြုသူများအတွက် ဖယ်ရှားလိုက်ပါမည်။"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"သင်သည် အသုံးပြုသူ <xliff:g id="USERNAME">%1$s</xliff:g> အတွက် ဤအကောင့်ကို ဖယ်ရှားလိုပါသလား။"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"သင့်အလုပ်ပရိုဖိုင်ကနေ ဤအက်ပ်ကို ဖယ်ရှားလိုတာ သေချာပါသလား။"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"သင်၏ တက်ဘလက်နှင့် ကိုယ်ရေးကိုယ်တာ အချက်အလက်များသည် အမျိုးအမည် မသိသောအက်ပ်များ၏ တိုက်ခိုက်ခြင်းကို ပိုမိုခံရနိုင်ပါသည်။ ဤအက်ပ်ကို ထည့်သွင်းအသုံးပြုခြင်းအားဖြင့် ဖြစ်ပေါ်လာနိုင်သော တက်ဘလက်ပျက်စီးမှု သို့မဟုတ် ဒေတာဆုံးရှုံးမှုများအတွက် သင့်ထံ၌သာ တာဝန်ရှိကြောင်း သဘောတူရာရောက်ပါသည်။"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"သင်၏ TV နှင့် ကိုယ်ရေးကိုယ်တာ အချက်အလက်များသည် အမျိုးအမည် မသိသောအက်ပ်များ၏ တိုက်ခိုက်ခြင်းကို ပိုမိုခံရနိုင်ပါသည်။ ဤအက်ပ်ကို ထည့်သွင်းအသုံးပြုခြင်းအားဖြင့် ဖြစ်ပေါ်လာနိုင်သော TV ပျက်စီးမှု သို့မဟုတ် ဒေတာဆုံးရှုံးမှုများအတွက် သင့်ထံ၌သာ တာဝန်ရှိကြောင်း သဘောတူရာရောက်ပါသည်။"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ပုံတူပွား"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ကို သိမ်းမလား။"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ရှေ့ဆက်ရန်"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ဆက်တင်များ"</string> <string name="wear_app_channel" msgid="1960809674709107850">"wear အက်ပ်ကိုထည့်သွင်းခြင်း/ဖယ်ရှားခြင်း"</string> diff --git a/packages/PackageInstaller/res/values-nb/strings.xml b/packages/PackageInstaller/res/values-nb/strings.xml index 2a24daa760cb..0a5ea5f46825 100644 --- a/packages/PackageInstaller/res/values-nb/strings.xml +++ b/packages/PackageInstaller/res/values-nb/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ukjente apper kan ikke installeres av denne brukeren"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Brukeren har ikke tillatelse til å installere apper"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arkivér"</string> <string name="update_anyway" msgid="8792432341346261969">"Oppdater likevel"</string> <string name="manage_applications" msgid="5400164782453975580">"Administrer apper"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Tom for plass"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Avinstaller oppdateringen"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> er del av følgende app:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Vil du avinstallere denne appen?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"De personlige dataene dine blir lagret"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Vil du arkivere denne appen for alle brukere? De personlige dataene dine blir lagret"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Vil du arkivere denne appen på jobbprofilen din? De personlige dataene dine blir lagret"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Vil du arkivere denne appen for <xliff:g id="USERNAME">%1$s</xliff:g>? De personlige dataene dine blir lagret"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Vil du arkivere denne appen fra det private området ditt? De personlige dataene dine blir lagret"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vil du avinstallere denne appen for "<b>"alle"</b>" brukere? Appen og tilhørende data blir fjernet fra "<b>"alle"</b>" brukere på enheten."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Ønsker du å avinstallere denne appen for brukeren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vil du avinstallere denne appen fra jobbprofilen din?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Nettbrettet ditt og de personlige dataene dine er mer sårbare for angrep fra ukjente apper. Når du installerer denne appen, samtykker du i at du er ansvarlig for eventuelle skader på nettbrettet eller tap av data som kan skyldes bruk av appen."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV-en din og de personlige dataene dine er mer sårbare for angrep fra ukjente apper. Når du installerer denne appen, samtykker du i at du er ansvarlig for eventuelle skader på TV-en eller tap av data som kan skyldes bruk av appen."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-klon"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Vil du arkivere <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Fortsett"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Innstillinger"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Installerer/avinstallerer Wear-apper"</string> diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml index 7dbe14125903..6ead9221223d 100644 --- a/packages/PackageInstaller/res/values-ne/strings.xml +++ b/packages/PackageInstaller/res/values-ne/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"यी प्रयोगकर्ता अज्ञात एपहरू इन्स्टल गर्न सक्नुहुन्न"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"यो प्रयोगकर्तालाई एपहरू इन्स्टल गर्ने अनुमति छैन"</string> <string name="ok" msgid="7871959885003339302">"ठिक छ"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"अभिलेखमा राख्नुहोस्"</string> <string name="update_anyway" msgid="8792432341346261969">"जे भए पनि अपडेट गर्नुहोस्"</string> <string name="manage_applications" msgid="5400164782453975580">"एपको प्रबन्ध गर्नु…"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"खाली ठाउँ छैन"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"अद्यावधिकको स्थापना रद्द गर्नु…"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> निम्न एपको अंश हो:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"तपाईं यो एप अनइन्स्टल गर्न चाहनुहुन्छ?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"तपाईंको व्यक्तिगत जानकारी सेभ गरिने छ"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"यो एप सबै प्रयोगकर्ताहरूका लागि अभिलेखमा राख्ने हो? तपाईंको व्यक्तिगत जानकारी सेभ गरिने छ"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"यो एप तपाईंको कार्य प्रोफाइलबाट अभिलेखमा राख्ने हो? तपाईंको व्यक्तिगत जानकारी सेभ गरिने छ"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"यो एप <xliff:g id="USERNAME">%1$s</xliff:g> का लागि अभिलेखमा राख्ने हो? तपाईंको व्यक्तिगत जानकारी सेभ गरिने छ"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"तपाईं आफ्नो निजी स्पेसबाट यो एप अभिलेखमा राख्न चाहनुहुन्छ? तपाईंको व्यक्तिगत जानकारी सेभ गरिने छ"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"तपाईं "<b>"सबै"</b>" प्रयोगकर्ताका लागि यो एप अनइन्स्टल गर्न चाहनुहुन्छ? डिभाइसका "<b>"सबै"</b>" प्रयोगकर्ताहरूबाट उक्त एप र यसको डेटा हटाइने छ।"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"तपाईं प्रयोगकर्ता <xliff:g id="USERNAME">%1$s</xliff:g> का लागि यो एप अनइन्स्टल गर्न चाहनुहुन्छ?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"तपाईं आफ्नो कार्य प्रोफाइलबाट यो एप अनइन्स्टल गर्न चाहनुहुन्छ?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"तपाईंको ट्याब्लेट तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको ट्याब्लेटमा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तपाईंको टिभी तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको टिभी मा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> क्लोन"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> अभिलेखमा राख्ने हो?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"जारी राख्नुहोस्"</string> <string name="external_sources_settings" msgid="4046964413071713807">"सेटिङहरू"</string> <string name="wear_app_channel" msgid="1960809674709107850">"वेयर एपहरूको स्थापना/स्थापना रद्द गर्दै"</string> diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml index 4816bab45781..d5aac783148d 100644 --- a/packages/PackageInstaller/res/values-nl/strings.xml +++ b/packages/PackageInstaller/res/values-nl/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Onbekende apps kunnen niet worden geïnstalleerd door deze gebruiker"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Deze gebruiker mag geen apps installeren"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archiveren"</string> <string name="update_anyway" msgid="8792432341346261969">"Toch updaten"</string> <string name="manage_applications" msgid="5400164782453975580">"Apps beheren"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Geen ruimte beschikbaar"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Update verwijderen"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> maakt deel uit van de volgende app:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Wil je deze app verwijderen?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Je persoonsgegevens worden opgeslagen"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Deze app archiveren voor alle gebruikers? Je persoonsgegevens worden opgeslagen."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Deze app in je werkprofiel archiveren? Je persoonsgegevens worden opgeslagen."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Deze app voor <xliff:g id="USERNAME">%1$s</xliff:g> archiveren? Je persoonsgegevens worden opgeslagen."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Wil je deze app in je privéruimte archiveren? Je persoonsgegevens worden opgeslagen."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Wil je deze app verwijderen voor "<b>"alle"</b>" gebruikers? Deze app en de gegevens ervan worden verwijderd voor "<b>"alle"</b>" gebruikers van het apparaat."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Wil je deze app verwijderen voor de gebruiker <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Wil je deze app verwijderen uit je werkprofiel?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Je tablet en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Als je deze app installeert, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je tablet of gegevensverlies als gevolg van het gebruik van de app."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Je tv en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Als je deze app installeert, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je tv of gegevensverlies als gevolg van het gebruik van de app."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-kloon"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> archiveren?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Doorgaan"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Instellingen"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear-apps installeren/verwijderen"</string> diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml index 70eab2d66c24..a4060de1dff4 100644 --- a/packages/PackageInstaller/res/values-or/strings.xml +++ b/packages/PackageInstaller/res/values-or/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ଏହି ୟୁଜରଙ୍କ ଦ୍ୱାରା ଅଜଣା ଆପ୍ ଇନଷ୍ଟଲ୍ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ଏହି ୟୁଜର୍ ଆପ୍ ଇନଷ୍ଟଲ୍ କରିପାରିବେ ନାହିଁ"</string> <string name="ok" msgid="7871959885003339302">"ଠିକ୍ ଅଛି"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"ଆର୍କାଇଭ କରନ୍ତୁ"</string> <string name="update_anyway" msgid="8792432341346261969">"ଯେ କୌଣସି ମତେ ଅପଡେଟ କରନ୍ତୁ"</string> <string name="manage_applications" msgid="5400164782453975580">"ଆପ୍ଗୁଡ଼ିକର ପରିଚାଳନା କରନ୍ତୁ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ଆଉ ସ୍ଥାନ ନାହିଁ"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"ଅପଡେଟ୍ ଅନଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ହେଉଛି ନିମ୍ନ ଆପ୍ର ଏକ ଅଂଶ।"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ଆପଣ ଏହି ଆପ୍ ଅନଇନଷ୍ଟଲ୍ କରିବାକୁ ଚାହାଁନ୍ତି କି?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଡାଟା ସେଭ ହୋଇଯିବ"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"ସମସ୍ତ ୟୁଜରଙ୍କ ପାଇଁ ଏହି ଆପକୁ ଆର୍କାଇଭ କରିବେ? ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଡାଟା ସେଭ ହୋଇଯିବ"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲରେ ଏହି ଆପକୁ ଆର୍କାଇଭ କରିବେ? ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଡାଟା ସେଭ ହୋଇଯିବ"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g>ଙ୍କ ପାଇଁ ଏହି ଆପକୁ ଆର୍କାଇଭ କରିବେ? ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଡାଟା ସେଭ ହୋଇଯିବ"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ଆପଣ ଆପଣଙ୍କ ପ୍ରାଇଭେଟ ସ୍ପେସରୁ ଏହି ଆପକୁ ଆର୍କାଇଭ କରିବାକୁ ଚାହାଁନ୍ତି? ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଡାଟା ସେଭ ହୋଇଯିବ"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"ଆପଣ "<b>"ସମସ୍ତ"</b>" ୟୁଜର୍ଙ୍କ ପାଇଁ ଏହି ଆପ୍କୁ ଅନଷ୍ଟଲ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି କି? ଡିଭାଇସ୍ରେ ଥିବା "<b>"ସମସ୍ତ"</b>" ୟୁଜର୍ ଆପ୍ଲିକେଶନ୍ ଏବଂ ତାହାର ଡାଟା ବାହାର କରିଦିଆଯିବ।"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"ୟୁଜର୍ <xliff:g id="USERNAME">%1$s</xliff:g>ଙ୍କ ପାଇଁ ଆପଣ ଏହି ଆପ୍ ଇନଷ୍ଟଲ୍ କରିବେ କି?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ଆପଣ ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲରୁ ଏହି ଆପକୁ ଅନଇନଷ୍ଟଲ କରିବାକୁ ଚାହାଁନ୍ତି କି?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ଅଜଣା ଆପ୍ ଦ୍ୱାରା ଆପଣଙ୍କ ଟାବଲେଟ୍ ଏବଂ ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ନଷ୍ଟ କରାଯାଇପାରିବାର ସମ୍ଭାବନା ବହୁତ ଅଧିକ। ଏହି ଆପ୍କୁ ଇନଷ୍ଟଲ୍ କରିବାର ଅର୍ଥ ହେଉଛି ଆପଣଙ୍କ ଟାବ୍ଲେଟ୍ରେ ଘଟିବା କୌଣସି ପ୍ରକାର କ୍ଷତି କିମ୍ବା ସେଗୁଡ଼ିକର ବ୍ୟବହାରରୁ ହେବା କୌଣସି ପ୍ରକାର ଡାଟାର ହାନୀ ପାଇଁ ଆପଣ ଦାୟୀ ରହିବାକୁ ରାଜି ହୁଅନ୍ତି।"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ଅଜଣା ଆପ୍ ଦ୍ୱାରା ଆପଣଙ୍କ ଟିଭି ଏବଂ ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ନଷ୍ଟ କରାଯାଇପାରିବାର ସମ୍ଭାବନା ବହୁତ ଅଧିକ। ଏହି ଆପ୍କୁ ଇନଷ୍ଟଲ୍ କରିବାର ଅର୍ଥ ହେଉଛି ଆପଣଙ୍କ ଟିଭିରେ ଘଟିବା କୌଣସି ପ୍ରକାର କ୍ଷତି କିମ୍ବା ସେଗୁଡ଼ିକର ବ୍ୟବହାରରୁ ହେବା କୌଣସି ପ୍ରକାର ଡାଟାର ହାନୀ ପାଇଁ ଆପଣ ଦାୟୀ ରହିବାକୁ ରାଜି ହୁଅନ୍ତି।"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> କ୍ଲୋନ"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>କୁ ଆର୍କାଇଭ କରିବେ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ଜାରି ରଖନ୍ତୁ"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ସେଟିଂସ"</string> <string name="wear_app_channel" msgid="1960809674709107850">"ୱିଅର୍ ଆପ୍ ଇନଷ୍ଟଲ୍/ଅନଇନଷ୍ଟଲ୍ କରାଯାଉଛି"</string> diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml index d91d032de727..c54d93f4bc41 100644 --- a/packages/PackageInstaller/res/values-pa/strings.xml +++ b/packages/PackageInstaller/res/values-pa/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ਇਹ ਵਰਤੋਂਕਾਰ ਅਗਿਆਤ ਐਪਾਂ ਨੂੰ ਸਥਾਪਤ ਨਹੀਂ ਕਰ ਸਕਦਾ"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਐਪਾਂ ਸਥਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string> <string name="ok" msgid="7871959885003339302">"ਠੀਕ ਹੈ"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"ਪੁਰਾਲੇਖਬੱਧ ਕਰੋ"</string> <string name="update_anyway" msgid="8792432341346261969">"ਫਿਰ ਵੀ ਅੱਪਡੇਟ ਕਰੋ"</string> <string name="manage_applications" msgid="5400164782453975580">"ਐਪਾਂ ਪ੍ਰਬੰਧਿਤ ਕਰੋ"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ਜਗ੍ਹਾ ਖਾਲੀ ਨਹੀਂ"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"ਅੱਪਡੇਟ ਅਣਸਥਾਪਤ ਕਰੋ"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ਅੱਗੇ ਦਿੱਤੀ ਐਪ ਦਾ ਭਾਗ ਹੈ:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"ਕੀ ਇਸ ਐਪ ਨੂੰ <xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੀ ਨਿੱਜੀ ਸਪੇਸ ਤੋਂ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ "<b>"ਸਾਰੇ"</b>" ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਐਪਲੀਕੇਸ਼ਨ ਅਤੇ ਇਸਦਾ ਡਾਟਾ ਡੀਵਾਈਸ \'ਤੇ "<b>"ਸਾਰੇ"</b>" ਵਰਤੋਂਕਾਰਾਂ ਵੱਲੋਂ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"ਕੀ ਤੁਸੀਂ ਵਰਤੋਂਕਾਰ <xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ ਇਸ ਐਪ ਨੂੰ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਅਤੇ ਨਿੱਜੀ ਡਾਟਾ ਅਗਿਆਤ ਐਪਾਂ ਤੋਂ ਹਮਲੇ ਪ੍ਰਤੀ ਵਧੇਰੇ ਵਿੰਨਣਸ਼ੀਲ ਹਨ। ਇਹ ਐਪ ਸਥਾਪਤ ਕਰਕੇ, ਤੁਸੀਂ ਸਹਿਮਤੀ ਦਿੰਦੇ ਹੋ ਕਿ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਨੁਕਸਾਨ ਜਾਂ ਡਾਟੇ ਦੀ ਹਾਨੀ ਲਈ ਤੁਸੀਂ ਜ਼ੁੰਮੇਵਾਰ ਹੋ ਜੋ ਸ਼ਾਇਦ ਇਸ ਐਪ ਨੂੰ ਵਰਤਣ ਦੇ ਨਤੀਜੇ ਵਜੋਂ ਹੋ ਸਕਦਾ ਹੈ।"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ਤੁਹਾਡਾ ਟੀਵੀ ਅਤੇ ਨਿੱਜੀ ਡਾਟਾ ਅਗਿਆਤ ਐਪਾਂ ਤੋਂ ਹਮਲੇ ਪ੍ਰਤੀ ਵਧੇਰੇ ਵਿੰਨਣਸ਼ੀਲ ਹਨ। ਇਹ ਐਪ ਸਥਾਪਤ ਕਰਕੇ, ਤੁਸੀਂ ਸਹਿਮਤੀ ਦਿੰਦੇ ਹੋ ਕਿ ਆਪਣੇ ਟੀਵੀ ਨੂੰ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਨੁਕਸਾਨ ਜਾਂ ਡਾਟੇ ਦੀ ਹਾਨੀ ਲਈ ਤੁਸੀਂ ਜ਼ੁੰਮੇਵਾਰ ਹੋ ਜੋ ਸ਼ਾਇਦ ਇਸ ਐਪ ਨੂੰ ਵਰਤਣ ਦੇ ਨਤੀਜੇ ਵਜੋਂ ਹੋ ਸਕਦਾ ਹੈ।"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ਦਾ ਕਲੋਨ"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"ਕੀ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ਨੂੰ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ਜਾਰੀ ਰੱਖੋ"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ਸੈਟਿੰਗਾਂ"</string> <string name="wear_app_channel" msgid="1960809674709107850">"ਵੀਅਰ ਐਪਾਂ ਸਥਾਪਤ ਜਾਂ ਅਣਸਥਾਪਤ ਕਰਨਾ"</string> diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml index 41bec16ba0d2..ec9ac1529ed9 100644 --- a/packages/PackageInstaller/res/values-pl/strings.xml +++ b/packages/PackageInstaller/res/values-pl/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ten użytkownik nie może instalować nieznanych aplikacji"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ten użytkownik nie może instalować aplikacji"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archiwizuj"</string> <string name="update_anyway" msgid="8792432341346261969">"Zaktualizuj mimo to"</string> <string name="manage_applications" msgid="5400164782453975580">"Zarządzaj aplikacjami"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Brak miejsca"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Odinstaluj aktualizację"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> jest częścią następującej aplikacji:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Odinstalować tę aplikację?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Twoje dane osobiste zostaną zapisane"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Zarchiwizować tę aplikację dla wszystkich użytkowników? Twoje dane osobiste zostaną zapisane"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Zarchiwizować tę aplikację w profilu służbowym? Twoje dane osobiste zostaną zapisane"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Zarchiwizować tę aplikację dla użytkownika <xliff:g id="USERNAME">%1$s</xliff:g>? Twoje dane osobiste zostaną zapisane"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Chcesz zarchiwizować tę aplikację ze swojego obszaru prywatnego? Twoje dane osobiste zostaną zapisane"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcesz odinstalować tę aplikację dla "<b>"wszystkich"</b>" użytkowników? Ta aplikacja i jej dane zostaną usunięte dla "<b>"wszystkich"</b>" użytkowników na urządzeniu."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Chcesz odinstalować tę aplikację dla użytkownika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Czy chcesz odinstalować tę aplikację z profilu służbowego?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Dane na tablecie i prywatne są bardziej narażone na atak nieznanych aplikacji. Instalując tę aplikację, bierzesz na siebie odpowiedzialność za ewentualne uszkodzenie tabletu lub utratę danych w wyniku jej używania."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Dane na telewizorze i prywatne są bardziej narażone na atak nieznanych aplikacji. Instalując tę aplikację, bierzesz na siebie odpowiedzialność za ewentualne uszkodzenie telewizora lub utratę danych w wyniku jej używania."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon aplikacji <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Zarchiwizować aplikację <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Dalej"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Ustawienia"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instalacja/usuwanie aplikacji na Wear"</string> diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml index 9d943a515c60..9c540e7dc4e1 100644 --- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml +++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Apps desconhecidos não podem ser instalados por este usuário"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuário não tem permissão para instalar apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arquivar"</string> <string name="update_anyway" msgid="8792432341346261969">"Atualizar mesmo assim"</string> <string name="manage_applications" msgid="5400164782453975580">"Gerenciar apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sem espaço"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar atualização"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> é parte do seguinte app:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Você quer desinstalar este app?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Seus dados pessoais serão salvos"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Arquivar esse app para todos os usuários? Seus dados pessoais serão salvos"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arquivar esse app no seu perfil de trabalho? Seus dados pessoais serão salvos"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Arquivar esse app para <xliff:g id="USERNAME">%1$s</xliff:g>? Seus dados pessoais serão salvos"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Você quer desinstalar esse app do seu espaço particular? Seus dados pessoais serão salvos"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Quer desinstalar este app para "<b>"todos"</b>" os usuários? O aplicativo e os dados dele serão removidos para "<b>"todos"</b>" os usuários do dispositivo."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Quer desinstalar este app para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Você quer desinstalar esse app do seu perfil de trabalho?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Seu tablet e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Sua TV e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Arquivar <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuar"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Configurações"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instalando/desinstalando apps do Wear"</string> diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml index 9d943a515c60..9c540e7dc4e1 100644 --- a/packages/PackageInstaller/res/values-pt/strings.xml +++ b/packages/PackageInstaller/res/values-pt/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Apps desconhecidos não podem ser instalados por este usuário"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Este usuário não tem permissão para instalar apps"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arquivar"</string> <string name="update_anyway" msgid="8792432341346261969">"Atualizar mesmo assim"</string> <string name="manage_applications" msgid="5400164782453975580">"Gerenciar apps"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Sem espaço"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar atualização"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> é parte do seguinte app:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Você quer desinstalar este app?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Seus dados pessoais serão salvos"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Arquivar esse app para todos os usuários? Seus dados pessoais serão salvos"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arquivar esse app no seu perfil de trabalho? Seus dados pessoais serão salvos"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Arquivar esse app para <xliff:g id="USERNAME">%1$s</xliff:g>? Seus dados pessoais serão salvos"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Você quer desinstalar esse app do seu espaço particular? Seus dados pessoais serão salvos"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Quer desinstalar este app para "<b>"todos"</b>" os usuários? O aplicativo e os dados dele serão removidos para "<b>"todos"</b>" os usuários do dispositivo."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Quer desinstalar este app para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Você quer desinstalar esse app do seu perfil de trabalho?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Seu tablet e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Sua TV e seus dados pessoais estão mais vulneráveis a ataques de apps desconhecidos. Ao instalar esse app, você concorda que é responsável por qualquer perda de dados ou dano ao dispositivo causados pelo uso desses apps."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Arquivar <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuar"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Configurações"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instalando/desinstalando apps do Wear"</string> diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml index cf50304a6ac4..0641370621c0 100644 --- a/packages/PackageInstaller/res/values-ro/strings.xml +++ b/packages/PackageInstaller/res/values-ro/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Aplicațiile necunoscute nu pot fi instalate de acest utilizator"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Acest utilizator nu are permisiunea să instaleze aplicații"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arhivează"</string> <string name="update_anyway" msgid="8792432341346261969">"Actualizează oricum"</string> <string name="manage_applications" msgid="5400164782453975580">"Gestionează"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Spațiu de stocare insuficient"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Dezinstalează actualizarea"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> face parte din următoarea aplicație:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Dezinstalezi această aplicație?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Datele tale cu caracter personal vor fi salvate"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Arhivezi aplicația pentru toți utilizatorii? Datele tale cu caracter personal vor fi salvate"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arhivezi aplicația din profilul de serviciu? Datele tale cu caracter personal vor fi salvate"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Arhivezi aplicația pentru <xliff:g id="USERNAME">%1$s</xliff:g>? Datele tale cu caracter personal vor fi salvate"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Arhivezi aplicația din spațiul privat? Datele tale cu caracter personal vor fi salvate"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Dezinstalezi această aplicație pentru "<b>"toți"</b>" utilizatorii? Aplicația și datele acesteia vor fi eliminate de la "<b>"toți"</b>" utilizatorii de pe acest dispozitiv."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Dezinstalezi această aplicație pentru utilizatorul <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Dezinstalezi această aplicație din profilul de serviciu?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tableta și datele tale personale sunt mai vulnerabile la un atac din partea aplicațiilor necunoscute. Dacă instalezi aplicația, accepți că ești singura persoană responsabilă pentru deteriorarea tabletei sau pentru pierderea datelor, care pot avea loc în urma folosirii acesteia."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Televizorul și datele tale cu caracter personal sunt mai vulnerabile la un atac din partea aplicațiilor necunoscute. Dacă instalezi această aplicație, accepți că ești singura persoană responsabilă pentru deteriorarea televizorului sau pentru pierderea datelor, care pot avea loc în urma folosirii acesteia."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clonează <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Arhivezi <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuă"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Setări"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Se (dez)instalează aplicațiile Wear"</string> diff --git a/packages/PackageInstaller/res/values-ru/strings.xml b/packages/PackageInstaller/res/values-ru/strings.xml index 2a85a0c7cf64..17222d19783a 100644 --- a/packages/PackageInstaller/res/values-ru/strings.xml +++ b/packages/PackageInstaller/res/values-ru/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Этот пользователь не может устанавливать неизвестные приложения."</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Этому пользователю не разрешено устанавливать приложения."</string> <string name="ok" msgid="7871959885003339302">"ОК"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Отправить в архив"</string> <string name="update_anyway" msgid="8792432341346261969">"Все равно обновить"</string> <string name="manage_applications" msgid="5400164782453975580">"Управление приложениями"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Недостаточно места"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Удалить обновление"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> – часть следующего приложения:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Удалить приложение?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Персональные данные будут сохранены."</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Отправить это приложение в архив для всех пользователей? Персональные данные будут сохранены."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Отправить в архив это приложение из рабочего профиля? Персональные данные будут сохранены."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Отправить это приложение в архив для пользователя <xliff:g id="USERNAME">%1$s</xliff:g>? Персональные данные будут сохранены."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Отправить в архив это приложение из личного пространства? Персональные данные будут сохранены."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Удалить это приложение для "<b>"всех"</b>" пользователей устройства? Они потеряют доступ как к приложению, так и к связанным с ним данным."<b></b></string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Удалить это приложение из профиля <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Удалить это приложение из рабочего профиля?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Ваши персональные данные и данные планшета более уязвимы для атак приложений из неизвестных источников. Устанавливая это приложение, вы берете на себя всю ответственность за последствия, связанные с его использованием, то есть за любой ущерб, нанесенный планшету, и возможную потерю данных."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Ваши персональные данные и данные телевизора более уязвимы для атак приложений из неизвестных источников. Устанавливая это приложение, вы берете на себя всю ответственность за последствия, связанные с его использованием, то есть за любой ущерб, нанесенный телевизору, и возможную потерю данных."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Клон приложения <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Отправить в архив приложение \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\"?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Продолжить"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Настройки"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Установка/удаление прилож. для Wear OS"</string> diff --git a/packages/PackageInstaller/res/values-si/strings.xml b/packages/PackageInstaller/res/values-si/strings.xml index ae94d4891b2e..8ba36b82a563 100644 --- a/packages/PackageInstaller/res/values-si/strings.xml +++ b/packages/PackageInstaller/res/values-si/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"මෙම පරිශීලකයා මඟින් නොදන්නා යෙදුම් ස්ථාපනය කළ නොහැක"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"මෙම පරිශීලකයාට යෙදුම් ස්ථාපනය කිරීමට අවසර නැත"</string> <string name="ok" msgid="7871959885003339302">"හරි"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"ලේඛනාරක්ෂණය"</string> <string name="update_anyway" msgid="8792432341346261969">"කෙසේ වෙතත් යාවත්කාලීන කරන්න"</string> <string name="manage_applications" msgid="5400164782453975580">"යෙදුම් කළමනාකරණය කරන්න"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ඉඩ නොමැත"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"යාවත්කාලිනය අස්ථාපනය කරන්න"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> පහත යෙදුමේ කොටසකි:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ඔබට මෙම යෙදුම අස්ථාපනය කිරීමට අවශ්යද?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"ඔබේ පුද්ගලික දත්ත සුරැකෙනු ඇත"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"සියලු පරිශීලකයින් සඳහා මෙම යෙදුම ලේඛනාරක්ෂණයකරන්න ද? ඔබේ පුද්ගලික දත්ත සුරැකෙනු ඇත"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"මෙම යෙදුම ඔබේ කාර්යාල පැතිකඩෙහි ලේඛනාරක්ෂණය කරන්න ද? ඔබේ පුද්ගලික දත්ත සුරැකෙනු ඇත"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g> සඳහා මෙම යෙදුම ලේඛනාරක්ෂණය කරන්න ද? ඔබේ පුද්ගලික දත්ත සුරැකෙනු ඇත"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ඔබට ඔබේ පෞද්ගලික අවකාශයෙන් මෙම යෙදුම ලේඛනාරක්ෂණය කිරීමට අවශ්ය ද? ඔබේ පුද්ගලික දත්ත සුරැකෙනු ඇත"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119"><b>"සියලු"</b>" පරිශීලකයන් සඳහා මෙම යෙදුම අස්ථාපනය කිරීමට ඔබට අවශ්යද? උපාංගයෙහි "<b>"සියලු"</b>" පරිශීලකයන් සඳහා යෙදුම සහ එහි දත්ත ඉවත්වනු ඇත."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> පරිශීලකයා සඳහා මෙම යෙදුම අස්ථාපනය කිරීමට ඔබට අවශ්යයද?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ඔබට කාර්යාල පැතිකඩ වෙතින් මෙම යෙදුම අස්ථාපනය කිරීමට අවශ්යද?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ඔබගේ ටැබ්ලට් පරිගණකය සහ පුද්ගලික දත්තවලට නොදන්නා යෙදුම් මඟින් තර්ජන එල්ල කිරීමේ හැකියාව වැඩිය. මෙම යෙදුම් ස්ථාපනය කිරීමෙන් සහ භාවිත කිරීමෙන් ඔබ ඔබේ ටැබ්ලට් පරිගණකය සඳහා සිදු වන යම් හානි හෝ එය භාවිත කිරීමේ ප්රතිඵලයක් ලෙස සිදු වන දත්ත හානි සඳහා ඔබ වගකිව යුතු බවට එකඟ වේ."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ඔබගේ TV සහ පුද්ගලික දත්තවලට නොදන්නා යෙදුම් මඟින් තර්ජන එල්ල කිරීමේ හැකියාව වැඩිය. මෙම යෙදුම් ස්ථාපනය කිරීමෙන් සහ භාවිත කිරීමෙන් ඔබ ඔබේ TV සඳහා සිදු වන යම් හානි හෝ එය භාවිත කිරීමේ ප්රතිඵලයක් ලෙස සිදු වන දත්ත හානි සඳහා ඔබ වගකිව යුතු බවට එකඟ වේ."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ක්ලෝනය"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ලේඛනාරක්ෂණය කරන්න ද?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ඉදිරියට යන්න"</string> <string name="external_sources_settings" msgid="4046964413071713807">"සැකසීම්"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear යෙදුම් ස්ථාපනය/අස්ථාපනය කරමින්"</string> diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml index 53d4a84c0031..e2428cf14532 100644 --- a/packages/PackageInstaller/res/values-sk/strings.xml +++ b/packages/PackageInstaller/res/values-sk/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Tento používateľ nemôže inštalovať neznáme aplikácie"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Tento používateľ nemá povolené inštalovať aplikácie"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Archivovať"</string> <string name="update_anyway" msgid="8792432341346261969">"Napriek tomu aktualizovať"</string> <string name="manage_applications" msgid="5400164782453975580">"Spravovať aplikácie"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nedostatok miesta"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Odinštalovať aktualizáciu"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"Aktivita <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> je súčasťou nasledujúcej aplikácie:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Chcete túto aplikáciu odinštalovať?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Vaše osobné údaje budú uložené"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Chcete túto aplikáciu archivovať pre všetkých používateľov? Vaše osobné údaje budú uložené."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Chcete túto aplikáciu archivovať vo svojom pracovnom profile? Vaše osobné údaje budú uložené."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Chcete túto aplikáciu archivovať pre použíateľa <xliff:g id="USERNAME">%1$s</xliff:g>? Vaše osobné údaje budú uložené."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Chcete túto aplikáciu archivovať zo svojho súkromného priestoru? Vaše osobné údaje budú uložené."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcete odinštalovať túto aplikáciu pre "<b>"všetkých"</b>" používateľov? Aplikácia a jej údaje sa odstránia z tohto zariadenia pre "<b>"všetkých"</b>" používateľov."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Chcete túto aplikáciu odinštalovať pre používateľa <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Chcete túto aplikáciu odinštalovať zo svojho pracovného profilu?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Váš tablet a osobné dáta sú náchylnejšie na útok z neznámych aplikácií. Inštaláciou tejto aplikácie vyjadrujete súhlas s tým, že nesiete zodpovednosť za akékoľvek poškodenie tabletu alebo stratu dát, ktoré by mohli nastať pri jej používaní."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Váš televízor a osobné údaje sú náchylnejšie na útok z neznámych aplikácií. Inštaláciou tejto aplikácie vyjadrujete súhlas s tým, že nesiete zodpovednosť za akékoľvek poškodenie televízora alebo stratu údajov, ktoré by mohli nastať pri jej používaní."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon aplikácie <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Chcete archivovať <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Pokračovať"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Nastavenia"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Inštalácia/odinštalovanie aplikácií Wear"</string> diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml index 2f6b697e742f..a172dab91fd6 100644 --- a/packages/PackageInstaller/res/values-sl/strings.xml +++ b/packages/PackageInstaller/res/values-sl/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ta uporabnik nima dovoljenja za nameščanje neznanih aplikacij"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ta uporabnik nima dovoljenja za nameščanje aplikacij"</string> <string name="ok" msgid="7871959885003339302">"V redu"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arhiviranje"</string> <string name="update_anyway" msgid="8792432341346261969">"Vseeno posodobi"</string> <string name="manage_applications" msgid="5400164782453975580">"Upravlj. aplik."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Zmanjkalo je prostora"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Odstrani posodobitev"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> je del te aplikacije:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Ali želite odmestiti to aplikacijo?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Vaši osebni podatki bodo shranjeni."</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Ali želite to aplikacijo arhivirati za vse uporabnike? Vaši osebni podatki bodo shranjeni."</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Ali želite to aplikacijo arhivirati v delovnem profilu? Vaši osebni podatki bodo shranjeni."</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Ali želite arhivirati to aplikacijo za uporabnika <xliff:g id="USERNAME">%1$s</xliff:g>? Vaši osebni podatki bodo shranjeni."</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Ali želite arhivirati to aplikacijo iz zasebnega prostora? Vaši osebni podatki bodo shranjeni."</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ali želite odstraniti aplikacijo za "<b>"vse"</b>" uporabnike? Aplikacija in njeni podatki bodo odstranjeni iz "<b>"vseh"</b>" uporabnikov v napravi."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Ali želite to aplikacijo odstraniti za uporabnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ali želite to aplikacijo odmestiti iz delovnega profila?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Neznane aplikacije lahko resno ogrozijo varnost tabličnega računalnika in osebnih podatkov. Z namestitvijo te aplikacije se strinjate, da ste sami odgovorni za morebitno škodo, nastalo v tabličnem računalniku, ali izgubo podatkov, do katerih lahko pride zaradi uporabe te aplikacije."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Neznane aplikacije lahko resno ogrozijo varnost televizorja in osebnih podatkov. Z namestitvijo te aplikacije se strinjate, da ste sami odgovorni za morebitno škodo, nastalo v televizorju, ali izgubo podatkov, do katerih lahko pride zaradi uporabe te aplikacije."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klonirana aplikacija <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Ali želite arhivirati paket <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Naprej"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Nastavitve"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Nameščanje/odstranjev. aplikacij za Wear"</string> diff --git a/packages/PackageInstaller/res/values-sq/strings.xml b/packages/PackageInstaller/res/values-sq/strings.xml index 1c4b35433fa3..f0bb5897f4a1 100644 --- a/packages/PackageInstaller/res/values-sq/strings.xml +++ b/packages/PackageInstaller/res/values-sq/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Aplikacionet e panjohura nuk mund të instalohen nga ky përdorues"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ky përdorues nuk lejohet të instalojë aplikacione"</string> <string name="ok" msgid="7871959885003339302">"Në rregull"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arkivo"</string> <string name="update_anyway" msgid="8792432341346261969">"Përditësoje gjithsesi"</string> <string name="manage_applications" msgid="5400164782453975580">"Menaxho aplikacionet"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nuk ka hapësirë"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Çinstalo përditësimin"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> është pjesë e aplikacionit të mëposhtëm:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Dëshiron ta çinstalosh këtë aplikacion?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Të dhënat e tua personale do të ruhen"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Të arkivohet ky aplikacion për të gjithë përdoruesit? Të dhënat e tua personale do të ruhen"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Të arkivohet ky aplikacion në profilin tënd të punës? Të dhënat e tua personale do të ruhen"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Të arkivohet ky aplikacion për <xliff:g id="USERNAME">%1$s</xliff:g>? Të dhënat e tua personale do të ruhen"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Dëshiron ta arkivosh këtë aplikacion nga hapësira jote private? Të dhënat e tua personale do të ruhen"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Dëshiron ta çinstalosh këtë aplikacion për "<b>"të gjithë"</b>" përdoruesit? Aplikacioni dhe të dhënat e tij do të hiqen nga "<b>"të gjithë"</b>" përdoruesit e pajisjes."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Dëshiron ta çinstalosh këtë aplikacion për përdoruesin <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Dëshiron ta çinstalosh këtë aplikacion nga profili yt i punës?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tableti dhe të dhënat e tua personale janë më të cenueshme nga sulmet nga aplikacione të panjohura. Duke instaluar këtë aplikacion, ti pranon se je përgjegjës për çdo dëm ndaj tabletit tënd ose çdo humbje të të dhënave që mund të rezultojë nga përdorimi i tij."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Televizori dhe të dhënat e tua personale janë më të cenueshme nga sulmet nga aplikacione të panjohura. Duke instaluar këtë aplikacion, ti pranon se je përgjegjës për çdo dëm ndaj televizorit tënd ose çdo humbje të të dhënave që mund të rezultojë nga përdorimi i tij."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon i <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Të arkivohet <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Vazhdo"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Cilësimet"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Instalimi/çinstalimi i aplikacioneve të Wear"</string> diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml index 4402d7f73d88..57dce51decea 100644 --- a/packages/PackageInstaller/res/values-sr/strings.xml +++ b/packages/PackageInstaller/res/values-sr/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Овај корисник не може да инсталира непознате апликације"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Овом кориснику није дозвољено да инсталира апликације"</string> <string name="ok" msgid="7871959885003339302">"Потврди"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Архивирај"</string> <string name="update_anyway" msgid="8792432341346261969">"Ипак ажурирај"</string> <string name="manage_applications" msgid="5400164782453975580">"Управљајте апл."</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Нема више простора"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Деинсталирај ажурирање"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> је део следеће апликације:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Желите да деинсталирате ову апликацију?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Лични подаци ће бити сачувани"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Желите ли да архивирате ову апликацију за све кориснике? Лични подаци ће бити сачувани"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Желите ли да архивирате ову апликацију са пословног профила? Лични подаци ће бити сачувани"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Желите ли да архивирате ову апликацију за корисника <xliff:g id="USERNAME">%1$s</xliff:g>? Лични подаци ће бити сачувани"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Желите ли да архивирате ову апликацију из приватног простора? Лични подаци ће бити сачувани"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Да ли желите да деинсталирате ову апликацију за "<b>"све"</b>" кориснике? Апликација и подаци уз ње биће уклоњени за "<b>"све"</b>" кориснике овог уређаја."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Желите ли да деинсталирате ову апликацију за корисника <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Да ли желите да деинсталирате ову апликацију са пословног профила?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Таблет и лични подаци су подложнији нападу непознатих апликација. Ако инсталирате ову апликацију, прихватате да сте одговорни за евентуална оштећења таблета или губитак података до којих може да дође због њеног коришћења."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ТВ и лични подаци су подложнији нападу непознатих апликација. Ако инсталирате ову апликацију, прихватате да сте одговорни за евентуална оштећења ТВ-а или губитак података до којих може да дође због њеног коришћења."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Клон апликације <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Желите ли да архивирате <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Настави"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Подешавања"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Инсталирање/деинсталирање Wear апликац."</string> diff --git a/packages/PackageInstaller/res/values-sv/strings.xml b/packages/PackageInstaller/res/values-sv/strings.xml index ed016a895ffd..d06f040059ea 100644 --- a/packages/PackageInstaller/res/values-sv/strings.xml +++ b/packages/PackageInstaller/res/values-sv/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Denna användare får inte installera okända appar"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Användaren har inte behörighet att installera appar"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arkivera"</string> <string name="update_anyway" msgid="8792432341346261969">"Uppdatera ändå"</string> <string name="manage_applications" msgid="5400164782453975580">"Hantera appar"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Slut på utrymme"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Avinstallera uppdatering"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> är en del av följande app:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Vill du avinstallera appen?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Din privata data sparas"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Vill du arkivera appen för alla användare? Din privata data sparas"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Vill du arkivera appen i din jobbprofil? Din privata data sparas"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Vill du arkivera appen för <xliff:g id="USERNAME">%1$s</xliff:g>? Din privata data sparas"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Vill du arkivera appen från ditt privata rum? Din privata data sparas"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vill du avinstallera den här appen för "<b>"alla"</b>" användare? Appen och alla data i den tas bort från "<b>"alla"</b>" användare på enheten."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Vill du avinstallera appen för användaren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vill du avinstallera appen från jobbprofilen?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Din surfplatta och personliga data är mer sårbara för attacker från okända appar. Genom att installera denna app bekräftar du att du är ansvarig för eventuella skador på surfplattan och för dataförlust som kan uppstå vid användning av denna app."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Din tv och personliga data är mer sårbar för attacker från okända appar. Genom att installera denna app bekräftar du att du är ansvarig för eventuella skador på tv:n och för dataförlust som kan uppstå vid användning av denna app."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Klon av <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Vill du arkivera <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Fortsätt"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Inställningar"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear-appar installeras/avinstalleras"</string> diff --git a/packages/PackageInstaller/res/values-sw/strings.xml b/packages/PackageInstaller/res/values-sw/strings.xml index 7f03d914cc3c..49af8fc730f2 100644 --- a/packages/PackageInstaller/res/values-sw/strings.xml +++ b/packages/PackageInstaller/res/values-sw/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Mtumiaji huyu hana idhini ya kusakinisha programu ambazo hazijulikani"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Mtumiaji huyu haruhusiwi kusakinisha programu"</string> <string name="ok" msgid="7871959885003339302">"Sawa"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Hifadhi kwenye kumbukumbu"</string> <string name="update_anyway" msgid="8792432341346261969">"Sasisha tu"</string> <string name="manage_applications" msgid="5400164782453975580">"Dhibiti programu"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nafasi imejaa"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Ondoa sasisho"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ni sehemu ya programu ifuatayo:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Ungependa kuondoa programu hii?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Data yako binafsi itahifadhiwa"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Ungependa kuweka programu hii kwenye kumbukumbu kwa watumiaji wote? Data yako binafsi itahifadhiwa"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Ungependa kuweka programu hii kwenye kumbukumbu katika wasifu wako wa kazini? Data yako binafsi itahifadhiwa"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Ungependa kuweka programu hii ya <xliff:g id="USERNAME">%1$s</xliff:g> kwenye kumbukumbu? Data yako binafsi itahifadhiwa"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Je, ungependa kuweka programu hii kwenye kumbukumbu kutoka kwenye sehemu yako ya faragha? Data yako binafsi itahifadhiwa"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Je, ungependa kuondoa programu hii kwa watumiaji "<b>"wote"</b>"? Programu na data yake zitaondolewa kutoka kwa watumiaji "<b>"wote"</b>" kwenye kifaa."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Je, ungependa kuondoa programu hii kwa mtumiaji <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ungependa kuondoa programu hii kwenye wasifu wako wa kazini?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Data yako ya binafsi na ya kompyuta yako kibao inaweza kuathiriwa na programu ambazo hazijulikani. Kwa kusakinisha programu hii, unakubali kuwajibikia uharibifu wowote kwenye kompyuta yako kibao au kupotea kwa data kutokana na matumizi yake."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Data yako ya binafsi na ya televisheni yako inaweza kuathiriwa na programu ambazo hazijulikani. Kwa kusakinisha programu hii, unakubali kuwajibikia uharibifu wowote kwenye televisheni yako au kupotea kwa data kutokana na matumizi yake."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Nakala ya <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Ungependa kuweka <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> kwenye kumbukumbu?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Endelea"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Mipangilio"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Inasakinisha/inaondoa programu za Android Wear"</string> diff --git a/packages/PackageInstaller/res/values-ta/strings.xml b/packages/PackageInstaller/res/values-ta/strings.xml index 3c98411aff1a..865781f921b5 100644 --- a/packages/PackageInstaller/res/values-ta/strings.xml +++ b/packages/PackageInstaller/res/values-ta/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"அறியப்படாத ஆப்ஸை இந்தப் பயனரால் நிறுவ இயலாது"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ஆப்ஸை நிறுவ இந்தப் பயனருக்கு அனுமதியில்லை"</string> <string name="ok" msgid="7871959885003339302">"சரி"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"காப்பிடு"</string> <string name="update_anyway" msgid="8792432341346261969">"பரவாயில்லை, புதுப்பிக்கவும்"</string> <string name="manage_applications" msgid="5400164782453975580">"ஆப்ஸை நிர்வகி"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"போதுமான சேமிப்பிடம் இல்லை"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"புதுப்பிப்பை நிறுவல் நீக்குதல்"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> என்பது பின்வரும் ஆப்ஸின் பகுதியாகும்:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"இந்த ஆப்ஸை நிறுவல் நீக்க விரும்புகிறீர்களா?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"உங்கள் தனிப்பட்ட தரவு சேமிக்கப்படும்"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"அனைத்துப் பயனர்களுக்கும் இந்த ஆப்ஸைக் காப்பிடவா? உங்கள் தனிப்பட்ட தரவு சேமிக்கப்படும்"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"உங்கள் பணிக் கணக்கில் இந்த ஆப்ஸைக் காப்பிடவா? உங்கள் தனிப்பட்ட தரவு சேமிக்கப்படும்"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g>க்கு இந்த ஆப்ஸைக் காப்பிடவா? உங்கள் தனிப்பட்ட தரவு சேமிக்கப்படும்"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"உங்கள் தனிப்பட்ட சேமிப்பிடத்திலிருந்து இந்த ஆப்ஸைக் காப்பிட வேண்டுமா? உங்கள் தனிப்பட்ட தரவு சேமிக்கப்படும்"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"இந்த ஆப்ஸை "<b>"அனைத்துப்"</b>" பயனர்களுக்கும் நிறுவல் நீக்க விரும்புகிறீர்களா? ஆப்ஸும் அதன் தரவும் சாதனத்திலுள்ள "<b>"அனைத்துப்"</b>" பயனர்களிடமிருந்தும் அகற்றப்படும்."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> என்ற பயனருக்கு இந்த ஆப்ஸை நிறுவல் நீக்க விரும்புகிறீர்களா?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"உங்கள் பணிக் கணக்கிலிருந்து இந்த ஆப்ஸை நிறுவல் நீக்க விரும்புகிறீர்களா?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"அறியப்படாத ஆப்ஸால் உங்கள் டேப்லெட்டும் தனிப்பட்ட தரவும் மிக எளிதாகப் பாதிப்புக்குள்ளாகலாம். இந்த ஆப்ஸை நிறுவுவதன் மூலம், இதைப் பயன்படுத்தும்போது டேப்லெட்டில் ஏதேனும் சிக்கல் ஏற்பட்டாலோ உங்களது தரவை இழந்தாலோ அதற்கு நீங்களே பொறுப்பாவீர்கள் என்பதை ஏற்கிறீர்கள்."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"அறியப்படாத ஆப்ஸால் உங்கள் டிவியும் தனிப்பட்ட தரவும் மிக எளிதாகப் பாதிப்புக்குள்ளாகலாம். இந்த ஆப்ஸை நிறுவுவதன் மூலம், இதைப் பயன்படுத்தும்போது டிவியில் ஏதேனும் சிக்கல் ஏற்பட்டாலோ உங்களது தரவை இழந்தாலோ அதற்கு நீங்களே பொறுப்பாவீர்கள் என்பதை ஏற்கிறீர்கள்."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> குளோன்"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ஐக் காப்பிடவா?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"தொடர்க"</string> <string name="external_sources_settings" msgid="4046964413071713807">"அமைப்புகள்"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear ஆப்ஸை நிறுவுதல்/நிறுவல் நீக்குதல்"</string> diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml index ef00c9f0fdc7..2deac93f75a0 100644 --- a/packages/PackageInstaller/res/values-te/strings.xml +++ b/packages/PackageInstaller/res/values-te/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ఈ వినియోగదారు తెలియని యాప్లను ఇన్స్టాల్ చేయలేరు"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"యాప్లను ఇన్స్టాల్ చేయడానికి ఈ వినియోగదారుకు అనుమతి లేదు"</string> <string name="ok" msgid="7871959885003339302">"సరే"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"ఆర్కైవ్ చేయండి"</string> <string name="update_anyway" msgid="8792432341346261969">"ఏదేమైనా అప్డేట్ చేయండి"</string> <string name="manage_applications" msgid="5400164782453975580">"యాప్లను నిర్వహించండి"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ఖాళీ లేదు"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"అప్డేట్ అన్ఇన్స్టాల్ చేయి"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> అనేది కింది యాప్లో ఒక భాగం:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"మీరు ఈ యాప్ను అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"మీ వ్యక్తిగత డేటా సేవ్ చేయబడుతుంది"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"యూజర్లందరికీ ఈ యాప్ను ఆర్కైవ్ చేయాలా? మీ వ్యక్తిగత డేటా సేవ్ చేయబడుతుంది"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"మీ వర్క్ ప్రొఫైల్లో ఈ యాప్ను ఆర్కైవ్ చేయాలా? మీ వ్యక్తిగత డేటా సేవ్ చేయబడుతుంది"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g>కు ఈ యాప్ను ఆర్కైవ్ చేయాలా? మీ వ్యక్తిగత డేటా సేవ్ చేయబడుతుంది"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"మీరు మీ ప్రైవేట్ స్పేస్ నుండి ఈ యాప్ను ఆర్కైవ్ చేయాలనుకుంటున్నారా? మీ వ్యక్తిగత డేటా సేవ్ చేయబడుతుంది"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"మీరు ఈ యాప్ను "<b>"అందరు"</b>" వినియోగదారులకు అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా? అప్లికేషన్, దాని డేటా పరికరంలోని "<b>"అందరు"</b>" వినియోగదారుల నుండి తీసివేయబడుతుంది."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"మీరు వినియోగదారు <xliff:g id="USERNAME">%1$s</xliff:g> కోసం ఈ యాప్ను అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"మీ వర్క్ ప్రొఫైల్ నుండి ఈ యాప్ను మీరు అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"మీ టాబ్లెట్ మరియు వ్యక్తిగత డేటాపై తెలియని యాప్లు దాడి చేయడానికి ఎక్కువ అవకాశం ఉంది. మీరు ఈ యాప్ను ఇన్స్టాల్ చేయడం ద్వారా, దీనిని ఉపయోగించడం వలన మీ టాబ్లెట్కు ఏదైనా హాని జరిగినా లేదా డేటా కోల్పోయినా బాధ్యత మీదేనని అంగీకరిస్తున్నారు."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"మీ టీవీ మరియు వ్యక్తిగత డేటాపై తెలియని యాప్లు దాడి చేయడానికి ఎక్కువ అవకాశం ఉంది. మీరు ఈ యాప్ను ఇన్స్టాల్ చేయడం ద్వారా, దీనిని ఉపయోగించడం వలన మీ టీవీకి ఏదైనా హాని జరిగినా లేదా డేటా కోల్పోయినా బాధ్యత మీదేనని అంగీకరిస్తున్నారు."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> క్లోన్"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>ను ఆర్కైవ్ చేయాలా?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"కొనసాగండి"</string> <string name="external_sources_settings" msgid="4046964413071713807">"సెట్టింగ్లు"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear యాప్లను ఇన్స్టాల్/అన్ఇన్స్టాల్ చేస్తోంది"</string> diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml index e330985eee35..e770a1d56379 100644 --- a/packages/PackageInstaller/res/values-th/strings.xml +++ b/packages/PackageInstaller/res/values-th/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"ผู้ใช้รายนี้ไม่สามารถติดตั้งแอปที่ไม่รู้จัก"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"ผู้ใช้รายนี้ไม่ได้รับอนุญาตให้ติดตั้งแอป"</string> <string name="ok" msgid="7871959885003339302">"ตกลง"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"เก็บ"</string> <string name="update_anyway" msgid="8792432341346261969">"อัปเดตเลย"</string> <string name="manage_applications" msgid="5400164782453975580">"จัดการแอป"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"ไม่มีพื้นที่"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"ถอนการติดตั้งการอัปเดต"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> เป็นส่วนหนึ่งของแอปต่อไปนี้"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"ต้องการถอนการติดตั้งแอปนี้ไหม"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"ระบบจะบันทึกข้อมูลส่วนตัวของคุณไว้"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"เก็บแอปนี้สำหรับผู้ใช้ทุกคนไหม ระบบจะบันทึกข้อมูลส่วนตัวของคุณไว้"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"เก็บแอปนี้ในโปรไฟล์งานไหม ระบบจะบันทึกข้อมูลส่วนตัวของคุณไว้"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"เก็บแอปนี้ไปสำหรับ <xliff:g id="USERNAME">%1$s</xliff:g> ไหม ระบบจะบันทึกข้อมูลส่วนตัวของคุณไว้"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"คุณต้องการเก็บแอปนี้ไปจากพื้นที่ส่วนตัวไหม ระบบจะบันทึกข้อมูลส่วนตัวของคุณไว้"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"ต้องการถอนการติดตั้งแอปนี้สำหรับผู้ใช้"<b>"ทั้งหมด"</b>"ไหม ระบบจะนำแอปและข้อมูลในแอปออกจากผู้ใช้"<b>"ทั้งหมด"</b>"ที่อยู่ในอุปกรณ์"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"ต้องการถอนการติดตั้งแอปนี้สำหรับผู้ใช้ <xliff:g id="USERNAME">%1$s</xliff:g> ไหม"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"คุณต้องการถอนการติดตั้งแอปนี้จากโปรไฟล์งานใช่ไหม"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"แท็บเล็ตและข้อมูลส่วนตัวของคุณมีความเสี่ยงมากขึ้นที่จะถูกโจมตีจากแอปที่ไม่รู้จัก การติดตั้งแอปนี้แสดงว่าคุณยอมรับว่าจะรับผิดชอบต่อความเสียหายใดๆ ที่จะเกิดขึ้นกับแท็บเล็ตหรือการสูญเสียข้อมูลที่อาจเกิดจากการใช้งานแอปดังกล่าว"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ทีวีและข้อมูลส่วนตัวของคุณมีความเสี่ยงมากขึ้นที่จะถูกโจมตีจากแอปที่ไม่รู้จัก การติดตั้งแอปนี้แสดงว่าคุณยอมรับว่าจะรับผิดชอบต่อความเสียหายใดๆ ที่จะเกิดขึ้นกับทีวีหรือการสูญเสียข้อมูลที่อาจเกิดจากการใช้งานแอปดังกล่าว"</string> <string name="cloned_app_label" msgid="7503612829833756160">"โคลนของ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"เก็บ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ไหม"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"ดำเนินการต่อ"</string> <string name="external_sources_settings" msgid="4046964413071713807">"การตั้งค่า"</string> <string name="wear_app_channel" msgid="1960809674709107850">"กำลังติดตั้ง/ถอนการติดตั้งแอป Wear"</string> diff --git a/packages/PackageInstaller/res/values-tl/strings.xml b/packages/PackageInstaller/res/values-tl/strings.xml index e7ef36b9b7d6..e65413033623 100644 --- a/packages/PackageInstaller/res/values-tl/strings.xml +++ b/packages/PackageInstaller/res/values-tl/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Hindi maaaring mag-install ang user na ito ng mga hindi kilalang app"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Hindi pinapayagan ang user na ito na mag-install ng mga app"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"I-archive"</string> <string name="update_anyway" msgid="8792432341346261969">"I-update pa rin"</string> <string name="manage_applications" msgid="5400164782453975580">"Pamahalaan ang app"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Wala nang espasyo"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"I-uninstall ang update"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"Bahagi ang <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ng sumusunod na app:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Gusto mo bang i-uninstall ang app na ito?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Ise-save ang iyong personal na data"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"I-archive ang app na ito para sa lahat ng user? Ise-save ang iyong personal na data"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"I-archive ang app na ito sa iyong profile sa trabaho? Ise-save ang iyong personal na data"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"I-archive ang app na ito para kay <xliff:g id="USERNAME">%1$s</xliff:g>? Ise-save ang iyong personal na data"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Gusto mo bang i-archive ang app na ito mula sa iyong pribadong space? Ise-save ang iyong personal na data"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Gusto mo bang i-uninstall ang app na ito para sa "<b>"lahat"</b>" ng user? Aalisin ang application at ang data nito sa "<b>"lahat"</b>" ng user sa device."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Gusto mo bang i-uninstall ang app na ito para sa user na si <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Gusto mo bang i-uninstall ang app na ito sa iyong profile sa trabaho?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Mas nanganganib ang iyong tablet at personal na data sa mga pag-atake mula sa mga hindi kilalang app. Sa pamamagitan ng pag-install ng app na ito, sumasang-ayon kang ikaw ang responsable sa anumang pinsala sa iyong tablet o pagkawala ng data na maaaring magresulta mula sa paggamit nito."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Mas nanganganib ang iyong TV at personal na data sa mga pag-atake mula sa mga hindi kilalang app. Sa pamamagitan ng pag-install ng app na ito, sumasang-ayon kang ikaw ang responsable sa anumang pinsala sa iyong TV o pagkawala ng data na maaaring magresulta mula sa paggamit nito."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Clone ng <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"I-archive ang <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Magpatuloy"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Mga Setting"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Ini-install/ina-uninstall ang wear app"</string> diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml index 3a0e053b6049..79d7a9436c38 100644 --- a/packages/PackageInstaller/res/values-tr/strings.xml +++ b/packages/PackageInstaller/res/values-tr/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Bilinmeyen uygulamalar bu kullanıcı tarafından yüklenemez"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Bu kullanıcının uygulama yüklemesine izin verilmiyor"</string> <string name="ok" msgid="7871959885003339302">"Tamam"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arşiv"</string> <string name="update_anyway" msgid="8792432341346261969">"Yine de güncelle"</string> <string name="manage_applications" msgid="5400164782453975580">"Uygulamaları yönet"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Yer kalmadı"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Güncelleme kaldırılsın mı?"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>, şu uygulamanın bir parçasıdır:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Bu uygulamanın yüklemesini kaldırmak istiyor musunuz?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Kişisel verileriniz kaydedilir"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Bu uygulama tüm kullanıcılar için arşivlensin mi? Kişisel verileriniz kaydedilir"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Bu uygulama iş profilinizde arşivlensin mi? Kişisel verileriniz kaydedilir"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Bu uygulama <xliff:g id="USERNAME">%1$s</xliff:g> için arşivlensin mi? Kişisel verileriniz kaydedilir"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Özel alanınızdaki bu uygulamayı arşivlemek istiyor musunuz? Kişisel verileriniz kaydedilir"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bu uygulamanın yüklemesini "<b>"tüm"</b>" kullanıcılar için kaldırmak istiyor musunuz? Uygulama ve verileri cihazdan "<b>"tüm"</b>" kullanıcılar için kaldırılacaktır."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> adlı kullanıcı için bu uygulamanın yüklemesini kaldırmak istiyor musunuz?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu uygulamanın iş profilinizdeki yüklemesini kaldırmak istiyor musunuz?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tabletiniz ve kişisel verileriniz, bilinmeyen uygulamaların saldırılarına karşı daha savunmasızdır. Bu uygulamayı yükleyerek, uygulama kullanımından dolayı tabletinizde oluşabilecek hasarın veya uğrayabileceğiniz veri kaybının sorumluluğunu kabul etmiş olursunuz."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV\'niz ve kişisel verileriniz, bilinmeyen uygulamaların saldırılarına karşı daha savunmasızdır. Bu uygulamayı yükleyerek, uygulama kullanımından dolayı TV\'nizde oluşabilecek hasarın veya uğrayabileceğiniz veri kaybının sorumluluğunu kabul etmiş olursunuz."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> Klonu"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> arşivlensin mi?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Devam"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Ayarlar"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear uygulamalarını yükleme/kaldırma"</string> diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml index 4ac918517f0f..fe966f7d0d01 100644 --- a/packages/PackageInstaller/res/values-uk/strings.xml +++ b/packages/PackageInstaller/res/values-uk/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Цей користувач не може встановлювати невідомі додатки"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Цей користувач не може встановлювати додатки"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Архівувати"</string> <string name="update_anyway" msgid="8792432341346261969">"Усе одно оновити"</string> <string name="manage_applications" msgid="5400164782453975580">"Керувати додатками"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Недостат. місця"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Видалити оновлення"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"Дія <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> є частиною такої програми:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Видалити цей додаток?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Ваші особисті дані буде збережено"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Архівувати цей додаток для всіх користувачів? Ваші особисті дані буде збережено"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Архівувати цей додаток у вашому робочому профілі? Ваші особисті дані буде збережено"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Архівувати цей додаток для користувача <xliff:g id="USERNAME">%1$s</xliff:g>? Ваші особисті дані буде збережено"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Архівувати цей додаток із вашого приватного простору? Ваші особисті дані буде збережено"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Хочете видалити цю програму для "<b>"всіх"</b>" користувачів? Програму та її дані буде видалено для "<b>"всіх"</b>" користувачів цього пристрою."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Видалити цей додаток для користувача <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Видалити цей додаток із вашого робочого профілю?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Ваш планшет і особисті дані більш уразливі до атак невідомих додатків. Установлюючи цей додаток, ви берете на себе відповідальність за пошкодження планшета чи втрату даних унаслідок використання додатка."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Ваш телевізор і особисті дані більш уразливі до атак невідомих додатків. Установлюючи цей додаток, ви берете на себе відповідальність за пошкодження телевізора чи втрату даних унаслідок використання додатка."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Копія додатка <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Архівувати додаток <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Продовжити"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Налаштування"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Встановлення або видалення додатків Wear"</string> diff --git a/packages/PackageInstaller/res/values-ur/strings.xml b/packages/PackageInstaller/res/values-ur/strings.xml index 6730574b57bd..98d6e8fb0204 100644 --- a/packages/PackageInstaller/res/values-ur/strings.xml +++ b/packages/PackageInstaller/res/values-ur/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"یہ صارف نامعلوم ایپس کو انسٹال نہیں کر سکتا"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"اس صارف کو ایپس انسٹال کرنے کی اجازت نہیں ہے"</string> <string name="ok" msgid="7871959885003339302">"ٹھیک ہے"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"آرکائیو کریں"</string> <string name="update_anyway" msgid="8792432341346261969">"بہر حال اپ ڈیٹ کریں"</string> <string name="manage_applications" msgid="5400164782453975580">"ایپس منظم کریں"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"جگہ نہیں ہے"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"اپ ڈیٹ اَن انسٹال کریں"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> درج ذیل ایپ کا حصہ ہے:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"کیا آپ اس ایپ کو اَن انسٹال کرنا چاہتے ہیں؟"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"آپ کا ذاتی ڈیٹا محفوظ ہو جائے گا"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"اس ایپ کو تمام صارفین کے لیے آرکائیو کریں؟ آپ کا ذاتی ڈیٹا محفوظ ہو جائے گا"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"اس ایپ کو اپنی دفتری پروفائل پر آرکائیو کریں؟ آپ کا ذاتی ڈیٹا محفوظ ہو جائے گا"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"<xliff:g id="USERNAME">%1$s</xliff:g> کے لیے اس ایپ کو آرکائیو کریں؟ آپ کا ذاتی ڈیٹا محفوظ ہو جائے گا"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"کیا آپ اس ایپ کو اپنی نجی جگہ سے آرکائیو کرنا چاہتے ہیں؟ آپ کا ذاتی ڈیٹا محفوظ ہو جائے گا"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"کیا آپ "<b>"سبھی"</b>" صارفین کیلئے اس ایپ کو اَن انسٹال کرنا چاہتے ہیں؟ ایپلیکیشن اور اس کا ڈیٹا آلہ پر موجود "<b>"سبھی"</b>" صارفین سے ہٹا دیا جائے گا۔"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"کیا آپ اس ایپ کو صارف <xliff:g id="USERNAME">%1$s</xliff:g> کیلئے اَن انسٹال کرنا چاہتے ہیں؟"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"کیا آپ اپنے دفتری پروفائل سے یہ ایپ اَن انسٹال کرنا چاہتے ہیں؟"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"آپ کے ٹیبلیٹ اور ذاتی ڈیٹا کو نامعلوم ایپس کی جانب سے حملے کا زیادہ خطرہ ہے۔ اس ایپ کو انسٹال کر کے، آپ اس بات سے اتفاق کرتے ہیں کہ آپ اس سے اپنے ٹیبلیٹ کو ہونے والے کسی بھی نقصان یا ڈیٹا کے نقصان کے لئے خود ذمہ دار ہیں۔"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"آپ کے TV اور ذاتی ڈیٹا کو نامعلوم ایپس کی جانب سے حملے کا زیادہ خطرہ ہے۔ اس ایپ کو انسٹال کر کے، آپ اس بات سے اتفاق کرتے ہیں کہ آپ اس سے اپنے TV کو ہونے والے کسی بھی نقصان یا ڈیٹا کے نقصان کے لئے خود ذمہ دار ہیں۔"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> کلون"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> کو آرکائیو کریں؟"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"جاری رکھیں"</string> <string name="external_sources_settings" msgid="4046964413071713807">"ترتیبات"</string> <string name="wear_app_channel" msgid="1960809674709107850">"wear ایپس کو انسٹال/اَن انسٹال کرنا"</string> diff --git a/packages/PackageInstaller/res/values-uz/strings.xml b/packages/PackageInstaller/res/values-uz/strings.xml index cc5f6bdd533e..843efe92014d 100644 --- a/packages/PackageInstaller/res/values-uz/strings.xml +++ b/packages/PackageInstaller/res/values-uz/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Notanish ilovalarni bu foydalanuvchi tomonidan o‘rnatib bo‘lmaydi"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Bu foydalanuvchiga ilovalarni o‘rnatish uchun ruxsat berilmagan"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Arxivlash"</string> <string name="update_anyway" msgid="8792432341346261969">"Baribir yangilansin"</string> <string name="manage_applications" msgid="5400164782453975580">"Ilovalarni boshqarish"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Joy qolmadi"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Yangilanishni o‘chirish"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> quyidagi ilovaning bir qismidir:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Bu ilovani o‘chirib tashlamoqchimisiz?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Shaxsiy maʼlumotlar saqlanadi"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Bu ilova barcha foydalanuvchilar uchun arxivlansinmi? Shaxsiy maʼlumotlar saqlanadi"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Ish profilidagi mazkur ilova arxivlansinmi? Shaxsiy maʼlumotlar saqlanadi"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Bu ilova <xliff:g id="USERNAME">%1$s</xliff:g> uchun arxivlansinmi? Shaxsiy maʼlumotlar saqlanadi"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Maxfiy joydagi mazkur ilova arxivlansinmi? Shaxsiy maʼlumotlar saqlanadi"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ushbu ilova "<b>"barcha"</b>" foydalanuvchilar uchun o‘chirilsinmi? Ilova va uning axborotlari qurilmadagi "<b>"barcha"</b>" foydalanuvchilardan o‘chib ketadi."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Haqiqatdan ham <xliff:g id="USERNAME">%1$s</xliff:g> foydalanuvchi uchun ushbu ilovani olib tashlamoqchimisiz?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu ilova ish profilidan olib tashlansinmi?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Planshetingiz va shaxsiy axborotlaringiz notanish ilovalar hujumiga zaif bo‘ladi. Bu ilovani o‘rnatish bilan planshetingizga yetkaziladigan shikast va axborotlaringizni o‘chirib yuborilishiga javobgarlikni o‘z zimmangizga olasiz."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV va shaxsiy axborotlaringiz notanish ilovalar hujumiga zaif bo‘ladi. Bu ilovani o‘rnatish bilan televizoringizga yetkaziladigan shikast va axborotlaringizni o‘chirib yuborilishiga javobgarlikni o‘z zimmangizga olasiz."</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> nusxasi"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> arxivlansinmi?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Davom etish"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Sozlamalar"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Wear ilovalarini o‘rnatish/o‘chirish"</string> diff --git a/packages/PackageInstaller/res/values-vi/strings.xml b/packages/PackageInstaller/res/values-vi/strings.xml index 6af9b826c139..40e6dd5d333d 100644 --- a/packages/PackageInstaller/res/values-vi/strings.xml +++ b/packages/PackageInstaller/res/values-vi/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Người dùng này không thể cài đặt ứng dụng không xác định"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Người dùng này không được phép cài đặt ứng dụng"</string> <string name="ok" msgid="7871959885003339302">"OK"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Lưu trữ"</string> <string name="update_anyway" msgid="8792432341346261969">"Vẫn cập nhật"</string> <string name="manage_applications" msgid="5400164782453975580">"Quản lý ứng dụng"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Hết dung lượng"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Gỡ cài đặt bản cập nhật"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> là một phần của ứng dụng sau:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Bạn có muốn gỡ cài đặt ứng dụng này không?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Dữ liệu cá nhân của bạn sẽ được lưu"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Lưu trữ ứng dụng này cho tất cả người dùng. Dữ liệu cá nhân của bạn sẽ được lưu"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Lưu trữ ứng dụng này trên hồ sơ công việc của bạn? Dữ liệu cá nhân của bạn sẽ được lưu"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Lưu trữ ứng dụng này cho <xliff:g id="USERNAME">%1$s</xliff:g>? Dữ liệu cá nhân của bạn sẽ được lưu"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Bạn có muốn lưu trữ ứng dụng này ra khỏi không gian riêng tư của mình không? Dữ liệu cá nhân của bạn sẽ được lưu"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bạn có muốn gỡ cài đặt ứng dụng này cho "<b>"tất cả"</b>" người dùng không? Ứng dụng và dữ liệu của ứng dụng sẽ bị xóa khỏi "<b>"tất cả"</b>" người dùng trên thiết bị."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Bạn có muốn gỡ cài đặt ứng dụng này cho người dùng <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bạn có muốn gỡ cài đặt ứng dụng này khỏi hồ sơ công việc của mình không?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Máy tính bảng và dữ liệu cá nhân của bạn dễ bị các ứng dụng không xác định tấn công hơn. Bằng cách cài đặt ứng dụng này, bạn đồng ý tự chịu trách nhiệm cho mọi hỏng hóc đối với máy tính bảng của mình hoặc mất mát dữ liệu có thể phát sinh do sử dụng ứng dụng này."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"TV và dữ liệu cá nhân của bạn dễ bị các ứng dụng không xác định tấn công hơn. Bằng cách cài đặt ứng dụng này, bạn đồng ý tự chịu trách nhiệm cho mọi hỏng hóc đối với TV của mình hoặc mất mát dữ liệu có thể phát sinh do sử dụng ứng dụng này."</string> <string name="cloned_app_label" msgid="7503612829833756160">"Bản sao của <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Lưu trữ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Tiếp tục"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Cài đặt"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Cài đặt/gỡ cài đặt ứng dụng Wear"</string> diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml index 3e77d7f02e8f..605726afb1e5 100644 --- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml +++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"该用户无法安装未知应用"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"此用户无权安装应用"</string> <string name="ok" msgid="7871959885003339302">"确定"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"归档"</string> <string name="update_anyway" msgid="8792432341346261969">"仍然更新"</string> <string name="manage_applications" msgid="5400164782453975580">"管理应用"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"空间不足"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"卸载更新"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>属于以下应用:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"要卸载此应用吗?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"系统将保存您的个人数据"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"要针对所有用户归档此应用吗?系统将保存您的个人数据"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"要归档工作资料中的此应用吗?系统将保存您的个人数据"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"要针对<xliff:g id="USERNAME">%1$s</xliff:g>归档此应用吗?系统将保存您的个人数据"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"要归档私密空间中的此应用吗?系统将保存您的个人数据"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"要为"<b>"所有"</b>"用户卸载此应用吗?系统将为设备上的"<b>"所有"</b>"用户移除此应用及其数据。"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"要为用户<xliff:g id="USERNAME">%1$s</xliff:g>卸载此应用吗?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"您想从您的工作资料中卸载此应用吗?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"来历不明的应用很可能会损害您的平板电脑和个人数据。安装该应用即表示,您同意对于因使用该应用可能导致的任何平板电脑损坏或数据丢失情况,您负有全部责任。"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"来历不明的应用很可能会损害您的电视和个人数据。安装该应用即表示,您同意对于因使用该应用可能导致的任何电视损坏或数据丢失情况,您负有全部责任。"</string> <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> 克隆应用"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"要归档<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>吗?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"继续"</string> <string name="external_sources_settings" msgid="4046964413071713807">"设置"</string> <string name="wear_app_channel" msgid="1960809674709107850">"正在安装/卸载 Wear 应用"</string> diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml index 4d2edea6cb9b..ab7b7ffc22a5 100644 --- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml +++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"此使用者無法安裝來源不明的應用程式"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"此使用者無法安裝應用程式"</string> <string name="ok" msgid="7871959885003339302">"確定"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"封存"</string> <string name="update_anyway" msgid="8792432341346261969">"仍要更新"</string> <string name="manage_applications" msgid="5400164782453975580">"管理應用程式"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"儲存空間不足"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"解除安裝更新"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"「<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>」屬於以下應用程式:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"你要解除安裝此應用程式嗎?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"系統會儲存你的個人資料"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"要為所有使用者封存此應用程式嗎?系統會儲存你的個人資料"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"要封存工作設定檔中的這個應用程式嗎?系統會儲存你的個人資料"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"要為<xliff:g id="USERNAME">%1$s</xliff:g>封存此應用程式嗎?系統會儲存你的個人資料"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"要封存私人空間中的這個應用程式嗎?系統會儲存你的個人資料"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"你要為"<b>"所有"</b>"使用者解除安裝這個應用程式嗎?應用程式及其資料會從裝置上的"<b>"所有"</b>"使用者設定檔中移除。"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"你要為使用者<xliff:g id="USERNAME">%1$s</xliff:g>解除安裝此應用程式嗎?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"要從工作設定檔解除安裝此應用程式嗎?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"來源不明的應用程式可能會侵害你的平板電腦和個人資料。安裝此應用程式,即表示你同意承擔因使用這個應用程式而導致平板電腦損壞或資料遺失的責任。"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"來源不明的應用程式可能會侵害你的電視和個人資料。安裝此應用程式,即表示你同意承擔因使用這個應用程式而導致電視損壞或資料遺失的責任。"</string> <string name="cloned_app_label" msgid="7503612829833756160">"「<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>」複製本"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"要封存<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>嗎?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"繼續"</string> <string name="external_sources_settings" msgid="4046964413071713807">"設定"</string> <string name="wear_app_channel" msgid="1960809674709107850">"正在安裝/解除安裝 Wear 應用程式"</string> diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml index 30e66a0407fb..16d9a3085955 100644 --- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml +++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"這位使用者無法安裝不明的應用程式"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"這位使用者無法安裝應用程式"</string> <string name="ok" msgid="7871959885003339302">"確定"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"封存"</string> <string name="update_anyway" msgid="8792432341346261969">"仍要更新"</string> <string name="manage_applications" msgid="5400164782453975580">"管理應用程式"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"空間不足"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"解除安裝更新"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"「<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>」屬於下列應用程式:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"要解除安裝這個應用程式嗎?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"系統會儲存你的個人資料"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"要為所有使用者封存這個應用程式嗎?系統會儲存你的個人資料"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"要在工作資料夾封存這個應用程式嗎?系統會儲存你的個人資料"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"要為<xliff:g id="USERNAME">%1$s</xliff:g>封存這個應用程式嗎?系統會儲存你的個人資料"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"要從私人空間封存這個應用程式嗎?系統會儲存你的個人資料"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"要為"<b>"所有"</b>"使用者解除安裝這個應用程式嗎?該應用程式及其資料會從裝置上的"<b>"所有"</b>"使用者設定檔移除。"</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"要為使用者 <xliff:g id="USERNAME">%1$s</xliff:g> 解除安裝這個應用程式嗎?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"要從工作資料夾解除安裝這個應用程式嗎?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"來歷不明的應用程式可能會損害你的平板電腦和個人資料。如因安裝及使用這個應用程式,導致你的平板電腦受損或資料遺失,請自行負責。"</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"來歷不明的應用程式可能會損害你的電視和個人資料。如因安裝及使用這個應用程式,導致你的電視受損或資料遺失,請自行負責。"</string> <string name="cloned_app_label" msgid="7503612829833756160">"「<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>」副本"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"要封存「<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>」嗎?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"繼續"</string> <string name="external_sources_settings" msgid="4046964413071713807">"設定"</string> <string name="wear_app_channel" msgid="1960809674709107850">"安裝/解除安裝中的 Wear 應用程式"</string> diff --git a/packages/PackageInstaller/res/values-zu/strings.xml b/packages/PackageInstaller/res/values-zu/strings.xml index 0bfc9b7043d1..624ed0f503c2 100644 --- a/packages/PackageInstaller/res/values-zu/strings.xml +++ b/packages/PackageInstaller/res/values-zu/strings.xml @@ -44,8 +44,7 @@ <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Izinhlelo zokusebenza ezingaziwa azikwazi ukufakwa ilo msebenzisi"</string> <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Lo msebenzisi akavunyelwe ukufaka izinhlelo zokusebenza"</string> <string name="ok" msgid="7871959885003339302">"KULUNGILE"</string> - <!-- no translation found for archive (4447791830199354721) --> - <skip /> + <string name="archive" msgid="4447791830199354721">"Ingobo yomlando"</string> <string name="update_anyway" msgid="8792432341346261969">"Buyekeza noma kunjalo"</string> <string name="manage_applications" msgid="5400164782453975580">"Phatha izinhlelo zokusebenza"</string> <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Iphelelwe yisikhala"</string> @@ -60,16 +59,11 @@ <string name="uninstall_update_title" msgid="824411791011583031">"Khipha isibuyekezo"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"I-<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ingxenye yohlelo lokusebenza olulandelayo:"</string> <string name="uninstall_application_text" msgid="3816830743706143980">"Ufuna ukukhipha le app?"</string> - <!-- no translation found for archive_application_text (8482325710714386348) --> - <skip /> - <!-- no translation found for archive_application_text_all_users (3151229641681672580) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_work_profile (1450487362134779752) --> - <skip /> - <!-- no translation found for archive_application_text_user (2586558895535581451) --> - <skip /> - <!-- no translation found for archive_application_text_current_user_private_profile (1958423158655599132) --> - <skip /> + <string name="archive_application_text" msgid="8482325710714386348">"Idatha yakho yomuntu siqu izolondolozwa"</string> + <string name="archive_application_text_all_users" msgid="3151229641681672580">"Faka le app kungobo yomlando yabo bonke abasebenzisi? Idatha yakho yomuntu siqu izolondolozwa"</string> + <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Faka kungobo yomlando le app ekuphrofayela yakho yomsebenzi? Idatha yakho yomuntu siqu izolondolozwa"</string> + <string name="archive_application_text_user" msgid="2586558895535581451">"Faka le app kungobo yamlando uyifakele u-<xliff:g id="USERNAME">%1$s</xliff:g>? Idatha yakho yomuntu siqu izolondolozwa"</string> + <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Ingabe ufuna ukuthi le app esendaweni yakho yangasese ifakwe kungobo yomlando? Idatha yakho yomuntu siqu izolondolozwa"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ingabe ufuna ukukhipha lolu hlelo lokusebenza kubo "<b>"bonke"</b>" abasebenzisi? Uhlelo lokusebenza nedatha yalo kuzosuswa kubo "<b>"bonke"</b>" abasebenzisi kudivayisi."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"Ingabe ufuna ukukhiphela lolu hlelo lokusebenza kumsebenzisi ongu-<xliff:g id="USERNAME">%1$s</xliff:g>?"</string> <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ingabe ufuna ukukhipha le app kusukela kuphrofayela yakho yokusebenza?"</string> @@ -108,8 +102,7 @@ <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Ithebulethi yakho nedatha yomuntu siqu zisengcupheni kakhulu ekuhlaselweni izinhlelo zokusebenza ezingaziwa. Ngokufaka lolu hlelo lokusebenza, uyavuma ukuthi unesibopho sanoma ikuphi ukonakala kuthebulethi yakho noma ukulahleka kwedatha okungabangelwa ukusetshenziswa kwayo."</string> <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Idatha yakho ye-TV neyomuntu siqu isengcupheni kakhulu ekuhlaselweni izinhlelo zokusebenza ezingaziwa. Ngokufaka lolu hlelo lokusebenza, uyavuma ukuthi unesibopho sanoma ikuphi ukonakala ku-TV yakho noma ukulahlekelwa kwedatha okungabangelwa ukusetshenziswa kwayo."</string> <string name="cloned_app_label" msgid="7503612829833756160">"I-Clone ye-<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> - <!-- no translation found for archiving_app_label (1127085259724124725) --> - <skip /> + <string name="archiving_app_label" msgid="1127085259724124725">"Faka i-<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> kungobo yomlando?"</string> <string name="anonymous_source_continue" msgid="4375745439457209366">"Qhubeka"</string> <string name="external_sources_settings" msgid="4046964413071713807">"Amasethingi"</string> <string name="wear_app_channel" msgid="1960809674709107850">"Ifaka/ikhipha izinhlelo zokusebenza ze-wear"</string> diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/AnonymousSourceFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/AnonymousSourceFragment.java index 679f696ff59f..b29cb2ab308c 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/AnonymousSourceFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/AnonymousSourceFragment.java @@ -34,7 +34,10 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class AnonymousSourceFragment extends DialogFragment { public static String TAG = AnonymousSourceFragment.class.getSimpleName(); + @NonNull private InstallActionListener mInstallActionListener; + @NonNull + private AlertDialog mDialog; @Override public void onAttach(@NonNull Context context) { @@ -45,7 +48,7 @@ public class AnonymousSourceFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) + mDialog = new AlertDialog.Builder(requireContext()) .setMessage(R.string.anonymous_source_warning) .setPositiveButton(R.string.anonymous_source_continue, ((dialog, which) -> mInstallActionListener.onPositiveResponse( @@ -53,6 +56,7 @@ public class AnonymousSourceFragment extends DialogFragment { .setNegativeButton(R.string.cancel, ((dialog, which) -> mInstallActionListener.onNegativeResponse( InstallStage.STAGE_USER_ACTION_REQUIRED))).create(); + return mDialog; } @Override @@ -60,4 +64,24 @@ public class AnonymousSourceFragment extends DialogFragment { super.onCancel(dialog); mInstallActionListener.onNegativeResponse(InstallStage.STAGE_USER_ACTION_REQUIRED); } + + @Override + public void onStart() { + super.onStart(); + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); + } + + @Override + public void onPause() { + super.onPause(); + // This prevents tapjacking since an overlay activity started in front of Pia will + // cause Pia to be paused. + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false); + } + + @Override + public void onResume() { + super.onResume(); + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java index 49901de96bc4..2314d6b3b47e 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java @@ -35,8 +35,12 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class ExternalSourcesBlockedFragment extends DialogFragment { private final String TAG = ExternalSourcesBlockedFragment.class.getSimpleName(); + @NonNull private final InstallUserActionRequired mDialogData; + @NonNull private InstallActionListener mInstallActionListener; + @NonNull + private AlertDialog mDialog; public ExternalSourcesBlockedFragment(InstallUserActionRequired dialogData) { mDialogData = dialogData; @@ -51,7 +55,7 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { - return new AlertDialog.Builder(requireContext()) + mDialog = new AlertDialog.Builder(requireContext()) .setTitle(mDialogData.getAppLabel()) .setIcon(mDialogData.getAppIcon()) .setMessage(R.string.untrusted_external_source_warning) @@ -62,6 +66,7 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { (dialog, which) -> mInstallActionListener.onNegativeResponse( mDialogData.getStageCode())) .create(); + return mDialog; } @Override @@ -69,4 +74,24 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { super.onCancel(dialog); mInstallActionListener.onNegativeResponse(mDialogData.getStageCode()); } + + @Override + public void onStart() { + super.onStart(); + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); + } + + @Override + public void onPause() { + super.onPause(); + // This prevents tapjacking since an overlay activity started in front of Pia will + // cause Pia to be paused. + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false); + } + + @Override + public void onResume() { + super.onResume(); + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java index 25363d0b5f7b..5ca02eae5167 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java @@ -42,6 +42,8 @@ public class InstallConfirmationFragment extends DialogFragment { private final InstallUserActionRequired mDialogData; @NonNull private InstallActionListener mInstallActionListener; + @NonNull + private AlertDialog mDialog; public InstallConfirmationFragment(@NonNull InstallUserActionRequired dialogData) { mDialogData = dialogData; @@ -58,7 +60,7 @@ public class InstallConfirmationFragment extends DialogFragment { public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); - AlertDialog dialog = new AlertDialog.Builder(requireContext()) + mDialog = new AlertDialog.Builder(requireContext()) .setIcon(mDialogData.getAppIcon()) .setTitle(mDialogData.getAppLabel()) .setView(dialogView) @@ -84,7 +86,7 @@ public class InstallConfirmationFragment extends DialogFragment { } viewToEnable.setVisibility(View.VISIBLE); - return dialog; + return mDialog; } @Override @@ -92,4 +94,24 @@ public class InstallConfirmationFragment extends DialogFragment { super.onCancel(dialog); mInstallActionListener.onNegativeResponse(mDialogData.getStageCode()); } + + @Override + public void onStart() { + super.onStart(); + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); + } + + @Override + public void onPause() { + super.onPause(); + // This prevents tapjacking since an overlay activity started in front of Pia will + // cause Pia to be paused. + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false); + } + + @Override + public void onResume() { + super.onResume(); + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); + } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/CheckboxPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/CheckboxPreference.kt new file mode 100644 index 000000000000..93d77d409416 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/CheckboxPreference.kt @@ -0,0 +1,181 @@ +/* + * 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.spa.widget.preference + +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.selection.toggleable +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.AirplanemodeActive +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.framework.util.EntryHighlight +import com.android.settingslib.spa.framework.util.wrapOnSwitchWithLog +import com.android.settingslib.spa.widget.ui.SettingsCheckbox +import com.android.settingslib.spa.widget.ui.SettingsIcon + +/** + * The widget model for [CheckboxPreference] widget. + */ +interface CheckboxPreferenceModel { + /** + * The title of this [CheckboxPreference]. + */ + val title: String + + /** + * The summary of this [CheckboxPreference]. + */ + val summary: () -> String + get() = { "" } + + /** + * The icon of this [Preference]. + * + * Default is `null` which means no icon. + */ + val icon: (@Composable () -> Unit)? + get() = null + + /** + * Indicates whether this [CheckboxPreference] is checked. + * + * This can be `null` during the data loading before the data is available. + */ + val checked: () -> Boolean? + + /** + * Indicates whether this [CheckboxPreference] is changeable. + * + * Not changeable [CheckboxPreference] will be displayed in disabled style. + */ + val changeable: () -> Boolean + get() = { true } + + /** + * The checkbox change handler of this [CheckboxPreference]. + * + * If `null`, this [CheckboxPreference] is not [toggleable]. + */ + val onCheckedChange: ((newChecked: Boolean) -> Unit)? +} + +/** + * CheckboxPreference widget. + * + * Data is provided through [CheckboxPreferenceModel]. + */ +@Composable +fun CheckboxPreference(model: CheckboxPreferenceModel) { + EntryHighlight { + InternalCheckboxPreference( + title = model.title, + summary = model.summary, + icon = model.icon, + checked = model.checked(), + changeable = model.changeable(), + onCheckedChange = model.onCheckedChange, + ) + } +} + +@Composable +internal fun InternalCheckboxPreference( + title: String, + summary: () -> String = { "" }, + icon: @Composable (() -> Unit)? = null, + checked: Boolean?, + changeable: Boolean = true, + paddingStart: Dp = SettingsDimension.itemPaddingStart, + paddingEnd: Dp = SettingsDimension.itemPaddingEnd, + paddingVertical: Dp = SettingsDimension.itemPaddingVertical, + onCheckedChange: ((newChecked: Boolean) -> Unit)?, +) { + val indication = LocalIndication.current + val onChangeWithLog = wrapOnSwitchWithLog(onCheckedChange) + val interactionSource = remember { MutableInteractionSource() } + val modifier = remember(checked, changeable) { + if (checked != null && onChangeWithLog != null) { + Modifier.toggleable( + value = checked, + interactionSource = interactionSource, + indication = indication, + enabled = changeable, + role = Role.Checkbox, + onValueChange = onChangeWithLog, + ) + } else Modifier + } + BasePreference( + title = title, + summary = summary, + modifier = modifier, + enabled = { changeable }, + paddingStart = paddingStart, + paddingEnd = paddingEnd, + paddingVertical = paddingVertical, + icon = icon, + ) { + Spacer(Modifier.width(SettingsDimension.itemPaddingEnd)) + SettingsCheckbox( + checked = checked, + changeable = { changeable }, + // The onCheckedChange is handled on the whole CheckboxPreference. + // DO NOT set it on SettingsCheckbox. + onCheckedChange = null, + interactionSource = interactionSource, + ) + } +} + +@Preview +@Composable +private fun CheckboxPreferencePreview() { + SettingsTheme { + Column { + InternalCheckboxPreference( + title = "Use Dark theme", + checked = true, + onCheckedChange = {}, + ) + InternalCheckboxPreference( + title = "Use Dark theme", + summary = { "Summary" }, + checked = false, + onCheckedChange = {}, + ) + InternalCheckboxPreference( + title = "Use Dark theme", + summary = { "Summary" }, + checked = true, + onCheckedChange = {}, + icon = @Composable { + SettingsIcon(imageVector = Icons.Outlined.AirplanemodeActive) + }, + ) + } + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Checkbox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Checkbox.kt new file mode 100644 index 000000000000..7a9d46cb0f54 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Checkbox.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.settingslib.spa.widget.ui + +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.material3.Checkbox +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import com.android.settingslib.spa.framework.util.wrapOnSwitchWithLog + +@Composable +internal fun SettingsCheckbox( + checked: Boolean?, + changeable: () -> Boolean, + onCheckedChange: ((newChecked: Boolean) -> Unit)? = null, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, +) { + if (checked != null) { + Checkbox( + checked = checked, + onCheckedChange = wrapOnSwitchWithLog(onCheckedChange), + enabled = changeable(), + interactionSource = interactionSource, + ) + } else { + Checkbox( + checked = false, + onCheckedChange = null, + enabled = false, + interactionSource = interactionSource, + ) + } +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/CheckboxPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/CheckboxPreferenceTest.kt new file mode 100644 index 000000000000..7375923605da --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/CheckboxPreferenceTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.spa.widget.preference + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsOff +import androidx.compose.ui.test.assertIsOn +import androidx.compose.ui.test.isToggleable +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class CheckboxPreferenceTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun title_displayed() { + composeTestRule.setContent { + testCheckboxPreference(changeable = true) + } + + composeTestRule.onNodeWithText("CheckboxPreference").assertIsDisplayed() + } + + @Test + fun toggleable_initialStateIsCorrect() { + composeTestRule.setContent { + testCheckboxPreference(changeable = true) + } + + composeTestRule.onNode(isToggleable()).assertIsOff() + } + + @Test + fun click_changeable_withEffect() { + composeTestRule.setContent { + testCheckboxPreference(changeable = true) + } + + composeTestRule.onNodeWithText("CheckboxPreference").performClick() + composeTestRule.onNode(isToggleable()).assertIsOn() + } + + @Test + fun click_notChangeable_noEffect() { + composeTestRule.setContent { + testCheckboxPreference(changeable = false) + } + + composeTestRule.onNodeWithText("CheckboxPreference").performClick() + composeTestRule.onNode(isToggleable()).assertIsOff() + } +} + +@Composable +private fun testCheckboxPreference(changeable: Boolean) { + var checked by rememberSaveable { mutableStateOf(false) } + CheckboxPreference(remember { + object : CheckboxPreferenceModel { + override val title = "CheckboxPreference" + override val checked = { checked } + override val changeable = { changeable } + override val onCheckedChange = { newChecked: Boolean -> checked = newChecked } + } + }) +}
\ No newline at end of file diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml index 9d783ec98383..3c5135bb87e8 100644 --- a/packages/SettingsLib/res/values-da/arrays.xml +++ b/packages/SettingsLib/res/values-da/arrays.xml @@ -26,7 +26,7 @@ <item msgid="6050951078202663628">"Opretter forbindelse..."</item> <item msgid="8356618438494652335">"Godkender..."</item> <item msgid="2837871868181677206">"Henter IP-adresse…"</item> - <item msgid="4613015005934755724">"Tilsluttet"</item> + <item msgid="4613015005934755724">"Forbundet"</item> <item msgid="3763530049995655072">"Sat på pause"</item> <item msgid="7852381437933824454">"Afbryder ..."</item> <item msgid="5046795712175415059">"Afbrudt"</item> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 2a6a247dca36..0d0f0c62c6f1 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -85,15 +85,15 @@ <string name="bluetooth_disconnected" msgid="7739366554710388701">"Afbrudt"</string> <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Afbryder ..."</string> <string name="bluetooth_connecting" msgid="5871702668260192755">"Opretter forbindelse..."</string> - <string name="bluetooth_connected" msgid="8065345572198502293">"Tilsluttet <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> + <string name="bluetooth_connected" msgid="8065345572198502293">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_pairing" msgid="4269046942588193600">"Parrer..."</string> - <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Tilsluttet <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (ingen telefon)"</string> - <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Tilsluttet <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (ingen medier)"</string> - <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"Tilsluttet <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (ingen telefon eller medier)"</string> - <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Tilsluttet <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> - <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Tilsluttet <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen telefon) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> - <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Tilsluttet <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen medier) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> - <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Tilsluttet <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen telefon eller medier) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (ingen telefon)"</string> + <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (ingen medier)"</string> + <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> (ingen telefon eller medier)"</string> + <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen telefon) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen medier) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Forbundet med <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (ingen telefon eller medier) – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktiv, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string> <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivt, V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string> <string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string> @@ -129,7 +129,7 @@ <string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"Sluttet til SAP"</string> <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Ikke forbundet til filoverførselsserver"</string> <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Forbundet til inputenhed"</string> - <string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Tilsluttet enhed for at få internetadgang"</string> + <string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Forbundet med enhed for at få internetadgang"</string> <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Deler lokal internetforbindelse med enhed"</string> <string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"Brug til internetadgang"</string> <string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"Brug til kort"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 364ba5461de6..5d2210c2defe 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -155,8 +155,8 @@ <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Entzungailua"</string> <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Idazteko gailua"</string> <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth bidezko gailua"</string> - <string name="accessibility_wifi_off" msgid="1195445715254137155">"Desaktibatuta dago Wi-Fi konexioa."</string> - <string name="accessibility_no_wifi" msgid="5297119459491085771">"Deskonektatu egin da Wi-Fi konexioa."</string> + <string name="accessibility_wifi_off" msgid="1195445715254137155">"Desaktibatuta dago wifi-konexioa."</string> + <string name="accessibility_no_wifi" msgid="5297119459491085771">"Deskonektatu egin da wifi-konexioa."</string> <string name="accessibility_wifi_one_bar" msgid="6025652717281815212">"Wi-Fi sarearen barra bat."</string> <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi sarearen bi barra."</string> <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi sarearen hiru barra."</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index a5bfe5e1d893..08152682508e 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -84,7 +84,7 @@ <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string> <string name="bluetooth_disconnected" msgid="7739366554710388701">"Frakoblet"</string> <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Kobler fra…"</string> - <string name="bluetooth_connecting" msgid="5871702668260192755">"Kobler til…"</string> + <string name="bluetooth_connecting" msgid="5871702668260192755">"Kobler til …"</string> <string name="bluetooth_connected" msgid="8065345572198502293">"Koblet til <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_pairing" msgid="4269046942588193600">"Kobler til …"</string> <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Koblet til (ingen telefon) <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index d8e11522f4f1..6c4ddf2a56a0 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -335,7 +335,7 @@ <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB मा एपको पुष्टि गरियोस्"</string> <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"हानिकारक व्यवहार पत्ता लगाउन ADB/ADT बाट इन्स्टल गरिएका एपको जाँच गरियोस्"</string> <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"नामकरण नगरिएका ब्लुटुथ डिभाइस (म्याक एड्रेस भएका मात्र) देखाइने छ"</string> - <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"यसले रिमोट डिभाइसमा अत्याधिक ठूलो वा अनियन्त्रित भोल्युम बज्नेको जस्ता अवस्थामा ब्लुटुथको निरपेक्ष भोल्युम अफ गर्छ।"</string> + <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"यसले रिमोट डिभाइसमा अत्यधिक ठूलो वा अनियन्त्रित भोल्युम बज्नेको जस्ता अवस्थामा ब्लुटुथको निरपेक्ष भोल्युम अफ गर्छ।"</string> <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"ब्लुटुथ Gabeldorsche सुविधाको स्ट्याक अन गरियोस्।"</string> <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"यसले परिष्कृत जडानको सुविधा सक्षम पार्छ।"</string> <string name="enable_terminal_title" msgid="3834790541986303654">"स्थानीय टर्मिनल"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index ba40a5030141..e5fce5bfe02a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -98,14 +98,15 @@ public abstract class InfoMediaManager extends MediaManager { private final Map<String, RouteListingPreference.Item> mPreferenceItemMap = new ConcurrentHashMap<>(); - public InfoMediaManager(Context context, String packageName, Notification notification, + public InfoMediaManager( + Context context, + @NonNull String packageName, + Notification notification, LocalBluetoothManager localBluetoothManager) { super(context, notification); mBluetoothManager = localBluetoothManager; - if (!TextUtils.isEmpty(packageName)) { - mPackageName = packageName; - } + mPackageName = packageName; } /** Creates an instance of InfoMediaManager. */ @@ -114,6 +115,14 @@ public abstract class InfoMediaManager extends MediaManager { String packageName, Notification notification, LocalBluetoothManager localBluetoothManager) { + + // The caller is only interested in system routes (headsets, built-in speakers, etc), and is + // not interested in a specific app's routing. The media routing APIs still require a + // package name, so we use the package name of the calling app. + if (TextUtils.isEmpty(packageName)) { + packageName = context.getPackageName(); + } + if (Flags.useMediaRouter2ForInfoMediaManager()) { try { return new RouterInfoMediaManager( diff --git a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java index 5298a46a9c89..8a122fcddcb3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java @@ -71,11 +71,6 @@ public final class RouterInfoMediaManager extends InfoMediaManager { LocalBluetoothManager localBluetoothManager) throws PackageNotAvailableException { super(context, packageName, notification, localBluetoothManager); - // TODO: b/291277292 - Change optional package name for a mandatory uid. - if (packageName == null) { - packageName = context.getPackageName(); - } - mRouter = MediaRouter2.getInstance(context, packageName); if (mRouter == null) { diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml index 42b635a691e4..1a4b009e2998 100644 --- a/packages/Shell/res/values-hi/strings.xml +++ b/packages/Shell/res/values-hi/strings.xml @@ -21,7 +21,7 @@ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"गड़बड़ी की रिपोर्ट <xliff:g id="ID">#%d</xliff:g> तैयार की जा रही है"</string> <string name="bugreport_finished_title" msgid="4429132808670114081">"गड़बड़ी की रिपोर्ट <xliff:g id="ID">#%d</xliff:g> कैप्चर की गई"</string> <string name="bugreport_updating_title" msgid="4423539949559634214">"गड़बड़ी की रिपोर्ट में पूरी जानकारी जोड़ी जा रही है"</string> - <string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा करें…"</string> + <string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया इंतज़ार करें…"</string> <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"गड़बड़ी की रिपोर्ट थोड़ी ही देर में फ़ोन पर दिखाई देगी"</string> <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"अपनी गड़बड़ी की रिपोर्ट शेयर करने के लिए टैप करें"</string> <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"अपनी गड़बड़ी की रिपोर्ट शेयर करने के लिए टैप करें"</string> diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 41d12dca869e..aa0903cab7aa 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -145,6 +145,16 @@ flag { } flag { + name: "enable_background_keyguard_ondrawn_callback" + namespace: "systemui" + description: "Calls the onDrawn keyguard in the background, without being blocked by main" + "thread work. This results in the screen to turn on earlier when the main thread is stuck. " + "Note that, even after this callback is called, we're waiting for all windows to finish " + " drawing." + bug: "295873557" +} + +flag { name: "qs_new_pipeline" namespace: "systemui" description: "Use the new pipeline for Quick Settings. Should have no behavior changes." @@ -212,6 +222,13 @@ flag { } flag { + name: "revamped_bouncer_messages" + namespace: "systemui" + description: "Change the bouncer message to be a 2-line more descriptive message" + bug: "236891644" +} + +flag { name: "rest_to_unlock" namespace: "systemui" description: "Require prolonged touch for fingerprint authentication" @@ -277,6 +294,13 @@ flag { } flag { + name: "new_volume_panel" + namespace: "systemui" + description: "Switches to the new volume panel (without Slices)." + bug: "202262476" +} + +flag { name: "screenshare_notification_hiding" namespace: "systemui" description: "Enable hiding of notifications during screenshare" @@ -289,3 +313,10 @@ flag { description: "Displays the auto on toggle in the bluetooth QS tile dialog" bug: "316985153" } + +flag { + name: "smartspace_relocate_to_bottom" + namespace: "systemui" + description: "Relocate Smartspace to bottom of the Lock Screen" + bug: "316212788" +} diff --git a/packages/SystemUI/animation/core/Android.bp b/packages/SystemUI/animation/Android.bp index 8438051e3430..8438051e3430 100644 --- a/packages/SystemUI/animation/core/Android.bp +++ b/packages/SystemUI/animation/Android.bp diff --git a/packages/SystemUI/animation/core/AndroidManifest.xml b/packages/SystemUI/animation/AndroidManifest.xml index 321cc53142c6..321cc53142c6 100644 --- a/packages/SystemUI/animation/core/AndroidManifest.xml +++ b/packages/SystemUI/animation/AndroidManifest.xml diff --git a/packages/SystemUI/animation/core/build.gradle b/packages/SystemUI/animation/build.gradle index 12637f4071df..939455fa44ac 100644 --- a/packages/SystemUI/animation/core/build.gradle +++ b/packages/SystemUI/animation/build.gradle @@ -5,8 +5,8 @@ apply plugin: 'kotlin-android' android { sourceSets { main { - java.srcDirs = ["${SYS_UI_DIR}/animation/core/src/com/android/systemui/surfaceeffects/"] - manifest.srcFile "${SYS_UI_DIR}/animation/core/AndroidManifest.xml" + java.srcDirs = ["${SYS_UI_DIR}/animation/src/com/android/systemui/surfaceeffects/"] + manifest.srcFile "${SYS_UI_DIR}/animation/AndroidManifest.xml" } } diff --git a/packages/SystemUI/animation/core/res/anim/launch_dialog_enter.xml b/packages/SystemUI/animation/res/anim/launch_dialog_enter.xml index c6b87d38f7da..c6b87d38f7da 100644 --- a/packages/SystemUI/animation/core/res/anim/launch_dialog_enter.xml +++ b/packages/SystemUI/animation/res/anim/launch_dialog_enter.xml diff --git a/packages/SystemUI/animation/core/res/anim/launch_dialog_exit.xml b/packages/SystemUI/animation/res/anim/launch_dialog_exit.xml index a0f441eaeed4..a0f441eaeed4 100644 --- a/packages/SystemUI/animation/core/res/anim/launch_dialog_exit.xml +++ b/packages/SystemUI/animation/res/anim/launch_dialog_exit.xml diff --git a/packages/SystemUI/animation/core/res/values/ids.xml b/packages/SystemUI/animation/res/values/ids.xml index 2d82307aca76..2d82307aca76 100644 --- a/packages/SystemUI/animation/core/res/values/ids.xml +++ b/packages/SystemUI/animation/res/values/ids.xml diff --git a/packages/SystemUI/animation/core/res/values/styles.xml b/packages/SystemUI/animation/res/values/styles.xml index 3b3f7f6128fa..3b3f7f6128fa 100644 --- a/packages/SystemUI/animation/core/res/values/styles.xml +++ b/packages/SystemUI/animation/res/values/styles.xml diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 9c46ebdc5ac8..9c46ebdc5ac8 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/AnimationFeatureFlags.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/AnimationFeatureFlags.kt index 1c9dabbb0e07..1c9dabbb0e07 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/AnimationFeatureFlags.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/AnimationFeatureFlags.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt index b879ba0b1ece..b879ba0b1ece 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt index 168039ed5d3d..168039ed5d3d 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/DialogLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/Expandable.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt index c49a487c6766..c49a487c6766 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/Expandable.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt index addabcc0282a..addabcc0282a 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/FontInterpolator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/FontVariationUtils.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt index 78ae4af258fc..78ae4af258fc 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/FontVariationUtils.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt index b738e2bc972b..b738e2bc972b 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt index d6eba2e7064d..d6eba2e7064d 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/LaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/LaunchableView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt index ed8e70568b48..ed8e70568b48 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/LaunchableView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/RemoteAnimationDelegate.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt index d465962d6edf..d465962d6edf 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/RemoteAnimationDelegate.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ShadeInterpolation.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt index b89a8b0e0272..b89a8b0e0272 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ShadeInterpolation.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt index dc54240affc3..8dc74951d332 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/TextAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt @@ -42,9 +42,9 @@ interface TypefaceVariantCache { return baseTypeface } - val axes = - FontVariationAxis.fromFontVariationSettings(fVar)?.toMutableList() - ?: mutableListOf() + val axes = FontVariationAxis.fromFontVariationSettings(fVar) + ?.toMutableList() + ?: mutableListOf() axes.removeIf { !baseTypeface.isSupportedAxes(it.getOpenTypeTagValue()) } if (axes.isEmpty()) { return baseTypeface @@ -206,14 +206,12 @@ class TextAnimator( * * Here is an example of font runs: "fin. 終わり" * - * ``` * Characters : f i n . _ 終 わ り * Code Points: \u0066 \u0069 \u006E \u002E \u0020 \u7D42 \u308F \u308A * Font Runs : <-- Roboto-Regular.ttf --><-- NotoSans-CJK.otf --> * runStart = 0, runLength = 5 runStart = 5, runLength = 3 * Glyph IDs : 194 48 7 8 4367 1039 1002 * Glyph Index: 0 1 2 3 0 1 2 - * ``` * * In this example, the "fi" is converted into ligature form, thus the single glyph ID is * assigned for two characters, f and i. @@ -245,21 +243,22 @@ class TextAnimator( /** * Set text style with animation. * - * By passing -1 to weight, the view preserve the current weight. By passing -1 to textSize, the - * view preserve the current text size. Bu passing -1 to duration, the default text animation, - * 1000ms, is used. By passing false to animate, the text will be updated without animation. + * By passing -1 to weight, the view preserve the current weight. + * By passing -1 to textSize, the view preserve the current text size. + * Bu passing -1 to duration, the default text animation, 1000ms, is used. + * By passing false to animate, the text will be updated without animation. * * @param fvar an optional text fontVariationSettings. * @param textSize an optional font size. - * @param colors an optional colors array that must be the same size as numLines passed to the - * TextInterpolator + * @param colors an optional colors array that must be the same size as numLines passed to + * the TextInterpolator * @param strokeWidth an optional paint stroke width * @param animate an optional boolean indicating true for showing style transition as animation, - * false for immediate style transition. True by default. + * false for immediate style transition. True by default. * @param duration an optional animation duration in milliseconds. This is ignored if animate is - * false. + * false. * @param interpolator an optional time interpolator. If null is passed, last set interpolator - * will be used. This is ignored if animate is false. + * will be used. This is ignored if animate is false. */ fun setTextStyle( fvar: String? = "", @@ -325,8 +324,7 @@ class TextAnimator( } /** - * Set text style with animation. Similar as fun setTextStyle( fvar: String? = "", textSize: - * ``` + * Set text style with animation. Similar as * fun setTextStyle( * fvar: String? = "", * textSize: Float = -1f, @@ -338,7 +336,6 @@ class TextAnimator( * delay: Long = 0, * onAnimationEnd: Runnable? = null * ) - * ``` * * @param weight an optional style value for `wght` in fontVariationSettings. * @param width an optional style value for `wdth` in fontVariationSettings. @@ -359,13 +356,12 @@ class TextAnimator( delay: Long = 0, onAnimationEnd: Runnable? = null ) { - val fvar = - fontVariationUtils.updateFontVariation( - weight = weight, - width = width, - opticalSize = opticalSize, - roundness = roundness, - ) + val fvar = fontVariationUtils.updateFontVariation( + weight = weight, + width = width, + opticalSize = opticalSize, + roundness = roundness, + ) setTextStyle( fvar = fvar, textSize = textSize, diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt index 02caeeddd774..02caeeddd774 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/TextInterpolator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt index 1290f0097536..1290f0097536 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt index a9c53d190cea..00d905652987 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt @@ -196,9 +196,9 @@ class ViewHierarchyAnimator { * * @param includeFadeIn true if the animator should also fade in the view and child views. * @param fadeInInterpolator the interpolator to use when fading in the view. Unused if - * [includeFadeIn] is false. - * @param onAnimationEnd an optional runnable that will be run once the animation finishes - * successfully. Will not be run if the animation is cancelled. + * [includeFadeIn] is false. + * @param onAnimationEnd an optional runnable that will be run once the animation + * finishes successfully. Will not be run if the animation is cancelled. */ @JvmOverloads fun animateAddition( @@ -241,10 +241,7 @@ class ViewHierarchyAnimator { // First, fade in the container view val containerDuration = duration / 6 createAndStartFadeInAnimator( - rootView, - containerDuration, - startDelay = 0, - interpolator = fadeInInterpolator + rootView, containerDuration, startDelay = 0, interpolator = fadeInInterpolator ) // Then, fade in the child views @@ -400,7 +397,7 @@ class ViewHierarchyAnimator { * included by specifying [includeMargins]. * * @param onAnimationEnd an optional runnable that will be run once the animation finishes - * successfully. Will not be run if the animation is cancelled. + * successfully. Will not be run if the animation is cancelled. */ @JvmOverloads fun animateRemoval( @@ -619,7 +616,6 @@ class ViewHierarchyAnimator { * not newly introduced margins are included. * * Base case - * * ``` * 1) origin=TOP * x---------x x---------x x---------x x---------x x---------x @@ -640,11 +636,9 @@ class ViewHierarchyAnimator { * x-----x x-------x | | * x---------x * ``` - * * In case the start and end values differ in the direction of the origin, and * [ignorePreviousValues] is false, the previous values are used and a translation is * included in addition to the view expansion. - * * ``` * origin=TOP_LEFT - (0,0,0,0) -> (30,30,70,70) * x @@ -783,7 +777,8 @@ class ViewHierarchyAnimator { includeMargins: Boolean = false, ): Map<Bound, Int> { val marginAdjustment = - if (includeMargins && (rootView.layoutParams is ViewGroup.MarginLayoutParams)) { + if (includeMargins && + (rootView.layoutParams is ViewGroup.MarginLayoutParams)) { val marginLp = rootView.layoutParams as ViewGroup.MarginLayoutParams DimenHolder( left = marginLp.leftMargin, @@ -791,9 +786,9 @@ class ViewHierarchyAnimator { right = marginLp.rightMargin, bottom = marginLp.bottomMargin ) - } else { - DimenHolder(0, 0, 0, 0) - } + } else { + DimenHolder(0, 0, 0, 0) + } // These are the end values to use *if* this bound is part of the destination. val endLeft = left - marginAdjustment.left @@ -810,69 +805,60 @@ class ViewHierarchyAnimator { // - If destination=BOTTOM_LEFT, then endBottom == endTop AND endLeft == endRight. return when (destination) { - Hotspot.TOP -> - mapOf( - Bound.TOP to endTop, - Bound.BOTTOM to endTop, - Bound.LEFT to left, - Bound.RIGHT to right, - ) - Hotspot.TOP_RIGHT -> - mapOf( - Bound.TOP to endTop, - Bound.BOTTOM to endTop, - Bound.RIGHT to endRight, - Bound.LEFT to endRight, - ) - Hotspot.RIGHT -> - mapOf( - Bound.RIGHT to endRight, - Bound.LEFT to endRight, - Bound.TOP to top, - Bound.BOTTOM to bottom, - ) - Hotspot.BOTTOM_RIGHT -> - mapOf( - Bound.BOTTOM to endBottom, - Bound.TOP to endBottom, - Bound.RIGHT to endRight, - Bound.LEFT to endRight, - ) - Hotspot.BOTTOM -> - mapOf( - Bound.BOTTOM to endBottom, - Bound.TOP to endBottom, - Bound.LEFT to left, - Bound.RIGHT to right, - ) - Hotspot.BOTTOM_LEFT -> - mapOf( - Bound.BOTTOM to endBottom, - Bound.TOP to endBottom, - Bound.LEFT to endLeft, - Bound.RIGHT to endLeft, - ) - Hotspot.LEFT -> - mapOf( - Bound.LEFT to endLeft, - Bound.RIGHT to endLeft, - Bound.TOP to top, - Bound.BOTTOM to bottom, - ) - Hotspot.TOP_LEFT -> - mapOf( - Bound.TOP to endTop, - Bound.BOTTOM to endTop, - Bound.LEFT to endLeft, - Bound.RIGHT to endLeft, - ) - Hotspot.CENTER -> - mapOf( - Bound.LEFT to (endLeft + endRight) / 2, - Bound.RIGHT to (endLeft + endRight) / 2, - Bound.TOP to (endTop + endBottom) / 2, - Bound.BOTTOM to (endTop + endBottom) / 2, - ) + Hotspot.TOP -> mapOf( + Bound.TOP to endTop, + Bound.BOTTOM to endTop, + Bound.LEFT to left, + Bound.RIGHT to right, + ) + Hotspot.TOP_RIGHT -> mapOf( + Bound.TOP to endTop, + Bound.BOTTOM to endTop, + Bound.RIGHT to endRight, + Bound.LEFT to endRight, + ) + Hotspot.RIGHT -> mapOf( + Bound.RIGHT to endRight, + Bound.LEFT to endRight, + Bound.TOP to top, + Bound.BOTTOM to bottom, + ) + Hotspot.BOTTOM_RIGHT -> mapOf( + Bound.BOTTOM to endBottom, + Bound.TOP to endBottom, + Bound.RIGHT to endRight, + Bound.LEFT to endRight, + ) + Hotspot.BOTTOM -> mapOf( + Bound.BOTTOM to endBottom, + Bound.TOP to endBottom, + Bound.LEFT to left, + Bound.RIGHT to right, + ) + Hotspot.BOTTOM_LEFT -> mapOf( + Bound.BOTTOM to endBottom, + Bound.TOP to endBottom, + Bound.LEFT to endLeft, + Bound.RIGHT to endLeft, + ) + Hotspot.LEFT -> mapOf( + Bound.LEFT to endLeft, + Bound.RIGHT to endLeft, + Bound.TOP to top, + Bound.BOTTOM to bottom, + ) + Hotspot.TOP_LEFT -> mapOf( + Bound.TOP to endTop, + Bound.BOTTOM to endTop, + Bound.LEFT to endLeft, + Bound.RIGHT to endLeft, + ) + Hotspot.CENTER -> mapOf( + Bound.LEFT to (endLeft + endRight) / 2, + Bound.RIGHT to (endLeft + endRight) / 2, + Bound.TOP to (endTop + endBottom) / 2, + Bound.BOTTOM to (endTop + endBottom) / 2, + ) } } @@ -1097,13 +1083,11 @@ class ViewHierarchyAnimator { animator.startDelay = startDelay animator.duration = duration animator.interpolator = interpolator - animator.addListener( - object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - view.setTag(R.id.tag_alpha_animator, null /* tag */) - } + animator.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + view.setTag(R.id.tag_alpha_animator, null /* tag */) } - ) + }) (view.getTag(R.id.tag_alpha_animator) as? ObjectAnimator)?.cancel() view.setTag(R.id.tag_alpha_animator, animator) diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ViewRootSync.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewRootSync.kt index e4f6db57f689..e4f6db57f689 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/ViewRootSync.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewRootSync.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt index dd32851a97cf..dd32851a97cf 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/back/BackAnimationSpec.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt index c6b70736bc67..c6b70736bc67 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpecForSysUi.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/back/BackTransformation.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackTransformation.kt index 49d1fb423d2b..49d1fb423d2b 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/back/BackTransformation.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackTransformation.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt index 8740d1467296..8740d1467296 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/view/LaunchableFrameLayout.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableFrameLayout.kt index 7538f188fb81..7538f188fb81 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/view/LaunchableFrameLayout.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableFrameLayout.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/view/LaunchableImageView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableImageView.kt index e42b589f05cf..e42b589f05cf 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/view/LaunchableImageView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableImageView.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt index bce262291f87..bce262291f87 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/animation/view/LaunchableTextView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt index 147669528c5e..147669528c5e 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/animation/view/LaunchableTextView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt index d8e17c9c8204..d8e17c9c8204 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt index 6c175ddf1ea4..6c175ddf1ea4 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt index d4372507e2c4..d4372507e2c4 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt index 91c0a5b635c9..91c0a5b635c9 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt index 7e56f4b3d2b2..7e56f4b3d2b2 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt index b89912709576..b89912709576 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt index c94fad7246fa..c94fad7246fa 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt index df07856e325e..df07856e325e 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/shaderutil/SdfShaderLibrary.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/SdfShaderLibrary.kt index 78898932249b..78898932249b 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/shaderutil/SdfShaderLibrary.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/SdfShaderLibrary.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt index 23fcb691ddb4..23fcb691ddb4 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt index 2cd587ffbc45..2cd587ffbc45 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt index b8f4b276dd6a..b8f4b276dd6a 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt index d3c57c91405a..d3c57c91405a 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt index 43d6504fce84..43d6504fce84 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/util/AnimatorExtensions.kt b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt index 35dbb89ad801..35dbb89ad801 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/util/AnimatorExtensions.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/util/Dialog.kt b/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt index 0f63548b6f0c..0f63548b6f0c 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/util/Dialog.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt diff --git a/packages/SystemUI/animation/core/src/com/android/systemui/util/Dimension.kt b/packages/SystemUI/animation/src/com/android/systemui/util/Dimension.kt index 4bc9972dd50f..4bc9972dd50f 100644 --- a/packages/SystemUI/animation/core/src/com/android/systemui/util/Dimension.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/util/Dimension.kt diff --git a/packages/SystemUI/compose/core/src/com/android/compose/ui/platform/DensityAwareComposeView.kt b/packages/SystemUI/compose/core/src/com/android/compose/ui/platform/DensityAwareComposeView.kt new file mode 100644 index 000000000000..dff8753fd880 --- /dev/null +++ b/packages/SystemUI/compose/core/src/com/android/compose/ui/platform/DensityAwareComposeView.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.compose.ui.platform + +import android.content.Context +import android.content.res.Configuration +import android.util.AttributeSet +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.platform.AbstractComposeView + +/** + * A ComposeView that recreates its composition if the display size or font scale was changed. + * + * TODO(b/317317814): Remove this workaround. + */ +class DensityAwareComposeView(context: Context) : OpenComposeView(context) { + private var lastDensityDpi: Int = -1 + private var lastFontScale: Float = -1f + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + val configuration = context.resources.configuration + lastDensityDpi = configuration.densityDpi + lastFontScale = configuration.fontScale + } + + override fun dispatchConfigurationChanged(newConfig: Configuration) { + super.dispatchConfigurationChanged(newConfig) + + // If the density or font scale changed, we dispose then recreate the composition. Note that + // we do this here after dispatching the new configuration to children (instead of doing + // this in onConfigurationChanged()) because the new configuration should first be + // dispatched to the AndroidComposeView that holds the current density before we recreate + // the composition. + val densityDpi = newConfig.densityDpi + val fontScale = newConfig.fontScale + if (densityDpi != lastDensityDpi || fontScale != lastFontScale) { + lastDensityDpi = densityDpi + lastFontScale = fontScale + + disposeComposition() + if (isAttachedToWindow) { + createComposition() + } + } + } +} + +/** A fork of [androidx.compose.ui.platform.ComposeView] that is open and can be subclassed. */ +open class OpenComposeView +internal constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : + AbstractComposeView(context, attrs, defStyleAttr) { + + private val content = mutableStateOf<(@Composable () -> Unit)?>(null) + + @Suppress("RedundantVisibilityModifier") + protected override var shouldCreateCompositionOnAttachedToWindow: Boolean = false + + @Composable + override fun Content() { + content.value?.invoke() + } + + override fun getAccessibilityClassName(): CharSequence { + return javaClass.name + } + + /** + * Set the Jetpack Compose UI content for this view. Initial composition will occur when the + * view becomes attached to a window or when [createComposition] is called, whichever comes + * first. + */ + fun setContent(content: @Composable () -> Unit) { + shouldCreateCompositionOnAttachedToWindow = true + this.content.value = content + if (isAttachedToWindow) { + createComposition() + } + } +} diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt index 5055ee1d73f6..d31547bd0d64 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.LifecycleOwner import com.android.compose.theme.PlatformTheme +import com.android.compose.ui.platform.DensityAwareComposeView import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation import com.android.systemui.common.ui.compose.windowinsets.DisplayCutout import com.android.systemui.common.ui.compose.windowinsets.DisplayCutoutProvider @@ -84,7 +85,7 @@ object ComposeFacade : BaseComposeFacade { viewModel: FooterActionsViewModel, qsVisibilityLifecycleOwner: LifecycleOwner, ): View { - return ComposeView(context).apply { + return DensityAwareComposeView(context).apply { setContent { PlatformTheme { FooterActions(viewModel, qsVisibilityLifecycleOwner) } } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt index 1d7c7d636158..6591543f44fe 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt @@ -19,7 +19,6 @@ package com.android.systemui.bouncer.ui.composable import android.app.AlertDialog -import android.app.Dialog import android.content.DialogInterface import androidx.compose.animation.Crossfade import androidx.compose.animation.core.animateFloatAsState @@ -135,7 +134,7 @@ fun BouncerContent( } Dialog( - viewModel = viewModel, + bouncerViewModel = viewModel, dialogFactory = dialogFactory, ) } @@ -666,32 +665,30 @@ private fun ActionArea( @Composable private fun Dialog( - viewModel: BouncerViewModel, + bouncerViewModel: BouncerViewModel, dialogFactory: BouncerDialogFactory, ) { - val dialogMessage: String? by viewModel.dialogMessage.collectAsState() - var dialog: Dialog? by remember { mutableStateOf(null) } + val dialogViewModel by bouncerViewModel.dialogViewModel.collectAsState() + var dialog: AlertDialog? by remember { mutableStateOf(null) } - if (dialogMessage != null) { + dialogViewModel?.let { viewModel -> if (dialog == null) { - dialog = - dialogFactory().apply { - setMessage(dialogMessage) - setButton( - DialogInterface.BUTTON_NEUTRAL, - context.getString(R.string.ok), - ) { _, _ -> - viewModel.onDialogDismissed() - } - setCancelable(false) - setCanceledOnTouchOutside(false) - show() - } + dialog = dialogFactory() + } + dialog?.apply { + setMessage(viewModel.text) + setButton(DialogInterface.BUTTON_NEUTRAL, context.getString(R.string.ok)) { _, _ -> + viewModel.onDismiss() + } + setCancelable(false) + setCanceledOnTouchOutside(false) + show() } - } else { - dialog?.dismiss() - dialog = null } + ?: { + dialog?.dismiss() + dialog = null + } } /** Renders the UI of the user switcher that's displayed on large screens next to the bouncer UI. */ @@ -772,7 +769,7 @@ private fun UserSwitcher( } /** - * Renders the dropdowm menu that displays the actual users and/or user actions that can be + * Renders the dropdown menu that displays the actual users and/or user actions that can be * selected. */ @Composable diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index 55fc3a2a81c1..5a4e0a9cd5ce 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -16,6 +16,7 @@ package com.android.systemui.communal.ui.compose +import android.appwidget.AppWidgetHostView import android.os.Bundle import android.util.SizeF import android.widget.FrameLayout @@ -194,6 +195,7 @@ private fun BoxScope.CommunalHubLazyGrid( items( count = list.size, key = { index -> list[index].key }, + contentType = { index -> list[index].key }, span = { index -> GridItemSpan(list[index].size.span) }, ) { index -> val cardModifier = Modifier.width(Dimensions.CardWidth) @@ -361,6 +363,8 @@ private fun WidgetContent( .createView(context, model.appWidgetId, model.providerInfo) .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) } }, + // For reusing composition in lazy lists. + onReset = {}, ) } } @@ -373,10 +377,10 @@ private fun SmartspaceContent( AndroidView( modifier = modifier, factory = { context -> - FrameLayout(context).apply { addView(model.remoteViews.apply(context, this)) } + AppWidgetHostView(context).apply { updateAppWidget(model.remoteViews) } }, // For reusing composition in lazy lists. - onReset = {} + onReset = {}, ) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt index 67a68200f269..ff53ff256931 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt @@ -37,9 +37,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -/** Set this to `true` to use the LockscreenContent replacement of KeyguardRootView. */ -private val UseLockscreenContent = false - /** The lock screen scene shows when the device is locked. */ @SysUISingleton class LockscreenScene @@ -48,7 +45,6 @@ constructor( @Application private val applicationScope: CoroutineScope, private val viewModel: LockscreenSceneViewModel, private val lockscreenContent: Lazy<LockscreenContent>, - private val viewBasedLockscreenContent: Lazy<ViewBasedLockscreenContent>, ) : ComposableScene { override val key = SceneKey.Lockscreen @@ -73,7 +69,6 @@ constructor( ) { LockscreenScene( lockscreenContent = lockscreenContent, - viewBasedLockscreenContent = viewBasedLockscreenContent, modifier = modifier, ) } @@ -93,22 +88,13 @@ constructor( } @Composable -private fun SceneScope.LockscreenScene( +private fun LockscreenScene( lockscreenContent: Lazy<LockscreenContent>, - viewBasedLockscreenContent: Lazy<ViewBasedLockscreenContent>, modifier: Modifier = Modifier, ) { - if (UseLockscreenContent) { - lockscreenContent - .get() - .Content( - modifier = modifier.fillMaxSize(), - ) - } else { - with(viewBasedLockscreenContent.get()) { - Content( - modifier = modifier.fillMaxSize(), - ) - } - } + lockscreenContent + .get() + .Content( + modifier = modifier.fillMaxSize(), + ) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt index 9abb50c35ccf..3677cab890f5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt @@ -20,6 +20,7 @@ import com.android.systemui.keyguard.ui.composable.blueprint.CommunalBlueprintMo import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule import com.android.systemui.keyguard.ui.composable.blueprint.ShortcutsBesideUdfpsBlueprintModule import com.android.systemui.keyguard.ui.composable.blueprint.SplitShadeBlueprintModule +import com.android.systemui.keyguard.ui.composable.section.OptionalSectionModule import dagger.Module @Module( @@ -27,6 +28,7 @@ import dagger.Module [ CommunalBlueprintModule::class, DefaultBlueprintModule::class, + OptionalSectionModule::class, ShortcutsBesideUdfpsBlueprintModule::class, SplitShadeBlueprintModule::class, ], diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/ViewBasedLockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/ViewBasedLockscreenContent.kt deleted file mode 100644 index 976161b3beb7..000000000000 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/ViewBasedLockscreenContent.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.keyguard.ui.composable - -import android.graphics.Rect -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.toComposeRect -import androidx.compose.ui.layout.Layout -import androidx.compose.ui.layout.onPlaced -import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.view.isVisible -import com.android.compose.animation.scene.SceneScope -import com.android.systemui.keyguard.qualifiers.KeyguardRootView -import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel -import com.android.systemui.notifications.ui.composable.NotificationStack -import com.android.systemui.res.R -import javax.inject.Inject - -/** - * Renders the content of the lockscreen. - * - * This is different from [LockscreenContent] (which is pure compose) and uses a view-based - * implementation of the lockscreen scene content that relies on [KeyguardRootView]. - * - * TODO(b/316211368): remove this once [LockscreenContent] is feature complete. - */ -class ViewBasedLockscreenContent -@Inject -constructor( - private val viewModel: LockscreenSceneViewModel, - @KeyguardRootView private val viewProvider: () -> @JvmSuppressWildcards View, -) { - @Composable - fun SceneScope.Content( - modifier: Modifier = Modifier, - ) { - fun findSettingsMenu(): View { - return viewProvider().requireViewById(R.id.keyguard_settings_button) - } - - LockscreenLongPress( - viewModel = viewModel.longPress, - modifier = modifier, - ) { onSettingsMenuPlaced -> - AndroidView( - factory = { _ -> - val keyguardRootView = viewProvider() - // Remove the KeyguardRootView from any parent it might already have in legacy - // code just in case (a view can't have two parents). - (keyguardRootView.parent as? ViewGroup)?.removeView(keyguardRootView) - keyguardRootView - }, - modifier = Modifier.fillMaxSize(), - ) - - val notificationStackPosition by - viewModel.keyguardRoot.notificationBounds.collectAsState() - - Layout( - modifier = - Modifier.fillMaxSize().onPlaced { - val settingsMenuView = findSettingsMenu() - onSettingsMenuPlaced( - if (settingsMenuView.isVisible) { - val bounds = Rect() - settingsMenuView.getHitRect(bounds) - bounds.toComposeRect() - } else { - null - } - ) - }, - content = { - NotificationStack( - viewModel = viewModel.notifications, - isScrimVisible = false, - ) - } - ) { measurables, constraints -> - check(measurables.size == 1) - val height = notificationStackPosition.height.toInt() - val childConstraints = constraints.copy(minHeight = height, maxHeight = height) - val placeable = measurables[0].measure(childConstraints) - layout(constraints.maxWidth, constraints.maxHeight) { - val start = (constraints.maxWidth - placeable.measuredWidth) / 2 - placeable.placeRelative(x = start, y = notificationStackPosition.top.toInt()) - } - } - } - } -} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt new file mode 100644 index 000000000000..c4184905f28d --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt @@ -0,0 +1,94 @@ +/* + * 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.composable.blueprint + +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.union +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalDensity +import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor +import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters +import com.android.systemui.plugins.clocks.ClockController +import kotlin.math.min +import kotlin.math.roundToInt + +/** Produces a [BurnInState] that can be used to query the `LockscreenBurnInViewModel` flows. */ +@Composable +fun rememberBurnIn( + clockInteractor: KeyguardClockInteractor, +): BurnInState { + val clock by clockInteractor.currentClock.collectAsState() + + val (smartspaceTop, onSmartspaceTopChanged) = remember { mutableStateOf<Float?>(null) } + val (smallClockTop, onSmallClockTopChanged) = remember { mutableStateOf<Float?>(null) } + + val topmostTop = + when { + smartspaceTop != null && smallClockTop != null -> min(smartspaceTop, smallClockTop) + smartspaceTop != null -> smartspaceTop + smallClockTop != null -> smallClockTop + else -> 0f + }.roundToInt() + + val params = rememberBurnInParameters(clock, topmostTop) + + return remember(params, onSmartspaceTopChanged, onSmallClockTopChanged) { + BurnInState( + parameters = params, + onSmartspaceTopChanged = onSmartspaceTopChanged, + onSmallClockTopChanged = onSmallClockTopChanged, + ) + } +} + +@Composable +private fun rememberBurnInParameters( + clock: ClockController?, + topmostTop: Int, +): BurnInParameters { + val density = LocalDensity.current + val topInset = WindowInsets.systemBars.union(WindowInsets.displayCutout).getTop(density) + + return remember(clock, topInset, topmostTop) { + BurnInParameters( + clockControllerProvider = { clock }, + topInset = topInset, + statusViewTop = topmostTop, + ) + } +} + +data class BurnInState( + /** Parameters for use with the `LockscreenBurnInViewModel. */ + val parameters: BurnInParameters, + /** + * Callback to invoke when the top coordinate of the smartspace element is updated, pass `null` + * when the element is not shown. + */ + val onSmartspaceTopChanged: (Float?) -> Unit, + /** + * Callback to invoke when the top coordinate of the small clock element is updated, pass `null` + * when the element is not shown. + */ + val onSmallClockTopChanged: (Float?) -> Unit, +) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt index d9d98cbd2da6..84d42463913c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope +import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection @@ -37,6 +38,7 @@ import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel import dagger.Binds import dagger.Module import dagger.multibindings.IntoSet +import java.util.Optional import javax.inject.Inject /** @@ -52,9 +54,10 @@ constructor( private val smartSpaceSection: SmartSpaceSection, private val notificationSection: NotificationSection, private val lockSection: LockSection, - private val ambientIndicationSection: AmbientIndicationSection, + private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>, private val bottomAreaSection: BottomAreaSection, private val settingsMenuSection: SettingsMenuSection, + private val clockInteractor: KeyguardClockInteractor, ) : LockscreenSceneBlueprint { override val id: String = "default" @@ -62,6 +65,7 @@ constructor( @Composable override fun SceneScope.Content(modifier: Modifier) { val isUdfpsVisible = viewModel.isUdfpsVisible + val burnIn = rememberBurnIn(clockInteractor) LockscreenLongPress( viewModel = viewModel.longPress, @@ -74,14 +78,25 @@ constructor( modifier = Modifier.fillMaxWidth(), ) { with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } - with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } - with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } + with(clockSection) { + SmallClock( + onTopChanged = burnIn.onSmallClockTopChanged, + modifier = Modifier.fillMaxWidth(), + ) + } + with(smartSpaceSection) { + SmartSpace( + burnInParams = burnIn.parameters, + onTopChanged = burnIn.onSmartspaceTopChanged, + modifier = Modifier.fillMaxWidth(), + ) + } with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } with(notificationSection) { Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) } - if (!isUdfpsVisible) { - with(ambientIndicationSection) { + if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { + with(ambientIndicationSectionOptional.get()) { AmbientIndication(modifier = Modifier.fillMaxWidth()) } } @@ -91,8 +106,8 @@ constructor( // Aligned to bottom and constrained to below the lock icon. Column(modifier = Modifier.fillMaxWidth()) { - if (isUdfpsVisible) { - with(ambientIndicationSection) { + if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { + with(ambientIndicationSectionOptional.get()) { AmbientIndication(modifier = Modifier.fillMaxWidth()) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt index 4704f5c3d1eb..414846276b2a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope +import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection @@ -37,6 +38,7 @@ import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel import dagger.Binds import dagger.Module import dagger.multibindings.IntoSet +import java.util.Optional import javax.inject.Inject /** @@ -52,9 +54,10 @@ constructor( private val smartSpaceSection: SmartSpaceSection, private val notificationSection: NotificationSection, private val lockSection: LockSection, - private val ambientIndicationSection: AmbientIndicationSection, + private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>, private val bottomAreaSection: BottomAreaSection, private val settingsMenuSection: SettingsMenuSection, + private val clockInteractor: KeyguardClockInteractor, ) : LockscreenSceneBlueprint { override val id: String = "shortcuts-besides-udfps" @@ -62,6 +65,7 @@ constructor( @Composable override fun SceneScope.Content(modifier: Modifier) { val isUdfpsVisible = viewModel.isUdfpsVisible + val burnIn = rememberBurnIn(clockInteractor) LockscreenLongPress( viewModel = viewModel.longPress, @@ -74,14 +78,25 @@ constructor( modifier = Modifier.fillMaxWidth(), ) { with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } - with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } - with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } + with(clockSection) { + SmallClock( + onTopChanged = burnIn.onSmallClockTopChanged, + modifier = Modifier.fillMaxWidth(), + ) + } + with(smartSpaceSection) { + SmartSpace( + burnInParams = burnIn.parameters, + onTopChanged = burnIn.onSmartspaceTopChanged, + modifier = Modifier.fillMaxWidth(), + ) + } with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } with(notificationSection) { Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) } - if (!isUdfpsVisible) { - with(ambientIndicationSection) { + if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { + with(ambientIndicationSectionOptional.get()) { AmbientIndication(modifier = Modifier.fillMaxWidth()) } } @@ -97,8 +112,8 @@ constructor( // Aligned to bottom and constrained to below the lock icon. Column(modifier = Modifier.fillMaxWidth()) { - if (isUdfpsVisible) { - with(ambientIndicationSection) { + if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { + with(ambientIndicationSectionOptional.get()) { AmbientIndication(modifier = Modifier.fillMaxWidth()) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt new file mode 100644 index 000000000000..f9dd04b66b1f --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt @@ -0,0 +1,68 @@ +/* + * 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.composable.modifier + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.boundsInWindow +import androidx.compose.ui.layout.onPlaced +import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel +import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters +import com.android.systemui.keyguard.ui.viewmodel.BurnInScaleViewModel + +/** + * Modifies the composable to account for anti-burn in translation, alpha, and scaling. + * + * Please override [isClock] as `true` if the composable is an element that's part of a clock. + */ +@Composable +fun Modifier.burnInAware( + viewModel: AodBurnInViewModel, + params: BurnInParameters, + isClock: Boolean = false, +): Modifier { + val translationX by viewModel.translationX(params).collectAsState(initial = 0f) + val translationY by viewModel.translationY(params).collectAsState(initial = 0f) + val alpha by viewModel.alpha.collectAsState(initial = 1f) + val scaleViewModel by viewModel.scale(params).collectAsState(initial = BurnInScaleViewModel()) + + return this.graphicsLayer { + val scale = + when { + scaleViewModel.scaleClockOnly && isClock -> scaleViewModel.scale + !scaleViewModel.scaleClockOnly -> scaleViewModel.scale + else -> 1f + } + + this.translationX = translationX + this.translationY = translationY + this.alpha = alpha + this.scaleX = scale + this.scaleY = scale + } +} + +/** Reports the "top" coordinate of the modified composable to the given [consumer]. */ +@Composable +fun Modifier.onTopPlacementChanged( + consumer: (Float) -> Unit, +): Modifier { + return onPlaced { coordinates -> consumer(coordinates.boundsInWindow().top) } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt index 0e7ac5ec046a..af9a195c4575 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/AmbientIndicationSection.kt @@ -16,36 +16,11 @@ package com.android.systemui.keyguard.ui.composable.section -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope -import javax.inject.Inject -class AmbientIndicationSection @Inject constructor() { - @Composable - fun SceneScope.AmbientIndication(modifier: Modifier = Modifier) { - MovableElement( - key = AmbientIndicationElementKey, - modifier = modifier, - ) { - Box( - modifier = Modifier.fillMaxWidth().background(Color.Green), - ) { - Text( - text = "TODO(b/316211368): Ambient indication", - color = Color.White, - modifier = Modifier.align(Alignment.Center), - ) - } - } - } +/** Defines interface for classes that can render the ambient indication area. */ +interface AmbientIndicationSection { + @Composable fun SceneScope.AmbientIndication(modifier: Modifier) } - -private val AmbientIndicationElementKey = ElementKey("AmbientIndication") diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt index db20f65ee78d..8bd0d45920f4 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt @@ -35,10 +35,10 @@ import com.android.systemui.animation.view.LaunchableImageView import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea +import com.android.systemui.keyguard.ui.viewmodel.AodAlphaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.statusbar.KeyguardIndicationController @@ -55,7 +55,7 @@ constructor( private val vibratorHelper: VibratorHelper, private val indicationController: KeyguardIndicationController, private val indicationAreaViewModel: KeyguardIndicationAreaViewModel, - private val keyguardRootViewModel: KeyguardRootViewModel, + private val alphaViewModel: AodAlphaViewModel, ) { /** * Renders a single lockscreen shortcut. @@ -74,20 +74,22 @@ constructor( key = if (isStart) StartButtonElementKey else EndButtonElementKey, modifier = modifier, ) { - Shortcut( - viewId = if (isStart) R.id.start_button else R.id.end_button, - viewModel = if (isStart) viewModel.startButton else viewModel.endButton, - transitionAlpha = viewModel.transitionAlpha, - falsingManager = falsingManager, - vibratorHelper = vibratorHelper, - indicationController = indicationController, - modifier = - if (applyPadding) { - Modifier.shortcutPadding() - } else { - Modifier - } - ) + content { + Shortcut( + viewId = if (isStart) R.id.start_button else R.id.end_button, + viewModel = if (isStart) viewModel.startButton else viewModel.endButton, + transitionAlpha = viewModel.transitionAlpha, + falsingManager = falsingManager, + vibratorHelper = vibratorHelper, + indicationController = indicationController, + modifier = + if (applyPadding) { + Modifier.shortcutPadding() + } else { + Modifier + } + ) + } } } @@ -99,11 +101,13 @@ constructor( key = IndicationAreaElementKey, modifier = modifier.shortcutPadding(), ) { - IndicationArea( - indicationAreaViewModel = indicationAreaViewModel, - keyguardRootViewModel = keyguardRootViewModel, - indicationController = indicationController, - ) + content { + IndicationArea( + indicationAreaViewModel = indicationAreaViewModel, + alphaViewModel = alphaViewModel, + indicationController = indicationController, + ) + } } } @@ -179,7 +183,7 @@ constructor( @Composable private fun IndicationArea( indicationAreaViewModel: KeyguardIndicationAreaViewModel, - keyguardRootViewModel: KeyguardRootViewModel, + alphaViewModel: AodAlphaViewModel, indicationController: KeyguardIndicationController, modifier: Modifier = Modifier, ) { @@ -192,7 +196,7 @@ constructor( KeyguardIndicationAreaBinder.bind( view = view, viewModel = indicationAreaViewModel, - keyguardRootViewModel = keyguardRootViewModel, + aodAlphaViewModel = alphaViewModel, indicationController = indicationController, ) ) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt index eaf8063b6f15..f021bb6743c4 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt @@ -16,41 +16,73 @@ package com.android.systemui.keyguard.ui.composable.section -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.viewinterop.AndroidView import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope +import com.android.compose.modifiers.padding +import com.android.keyguard.KeyguardClockSwitch +import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor +import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChanged import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel +import com.android.systemui.res.R import javax.inject.Inject class ClockSection @Inject constructor( private val viewModel: KeyguardClockViewModel, + private val clockInteractor: KeyguardClockInteractor, ) { + @Composable - fun SceneScope.SmallClock(modifier: Modifier = Modifier) { - if (viewModel.useLargeClock) { + fun SceneScope.SmallClock( + onTopChanged: (top: Float?) -> Unit, + modifier: Modifier = Modifier, + ) { + val clockSize by viewModel.clockSize.collectAsState() + val currentClock by viewModel.currentClock.collectAsState() + viewModel.clock = currentClock + + if (clockSize != KeyguardClockSwitch.SMALL) { + onTopChanged(null) + return + } + + if (currentClock?.smallClock?.view == null) { return } + val view = LocalView.current + + DisposableEffect(view) { + clockInteractor.clockEventController.registerListeners(view) + + onDispose { clockInteractor.clockEventController.unregisterListeners() } + } + MovableElement( key = ClockElementKey, modifier = modifier, ) { - Box( - modifier = Modifier.fillMaxWidth().background(Color.Magenta), - ) { - Text( - text = "TODO(b/316211368): Small clock", - color = Color.White, - modifier = Modifier.align(Alignment.Center), + content { + AndroidView( + factory = { checkNotNull(currentClock).smallClock.view }, + modifier = + Modifier.padding( + horizontal = + dimensionResource(R.dimen.keyguard_affordance_horizontal_offset) + ) + .padding(top = { viewModel.getSmallClockTopMargin(view.context) }) + .onTopPlacementChanged(onTopChanged), ) } } @@ -58,21 +90,36 @@ constructor( @Composable fun SceneScope.LargeClock(modifier: Modifier = Modifier) { - if (!viewModel.useLargeClock) { + val clockSize by viewModel.clockSize.collectAsState() + val currentClock by viewModel.currentClock.collectAsState() + viewModel.clock = currentClock + + if (clockSize != KeyguardClockSwitch.LARGE) { + return + } + + if (currentClock?.largeClock?.view == null) { return } + val view = LocalView.current + + DisposableEffect(view) { + clockInteractor.clockEventController.registerListeners(view) + + onDispose { clockInteractor.clockEventController.unregisterListeners() } + } + MovableElement( key = ClockElementKey, modifier = modifier, ) { - Box( - modifier = Modifier.fillMaxWidth().background(Color.Blue), - ) { - Text( - text = "TODO(b/316211368): Large clock", - color = Color.White, - modifier = Modifier.align(Alignment.Center), + content { + AndroidView( + factory = { checkNotNull(currentClock).largeClock.view }, + modifier = + Modifier.fillMaxWidth() + .padding(top = { viewModel.getLargeClockTopMargin(view.context) }) ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt index c547e2b93158..900616f6af89 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt @@ -22,7 +22,6 @@ import com.android.compose.animation.scene.SceneScope import com.android.systemui.notifications.ui.composable.NotificationStack import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher class NotificationSection @Inject diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/OptionalSectionModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/OptionalSectionModule.kt new file mode 100644 index 000000000000..5b7a8e6eb52f --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/OptionalSectionModule.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.composable.section + +import dagger.BindsOptionalOf +import dagger.Module + +/** + * Dagger module for providing placeholders for optional lockscreen scene sections that don't exist + * in AOSP but may be provided by OEMs. + */ +@Module +interface OptionalSectionModule { + @BindsOptionalOf fun ambientIndicationSection(): AmbientIndicationSection +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt index ca03af566fb2..9b718444b75c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt @@ -16,32 +16,180 @@ package com.android.systemui.keyguard.ui.composable.section -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box +import android.widget.FrameLayout +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope +import com.android.systemui.keyguard.KeyguardUnlockAnimationController +import com.android.systemui.keyguard.ui.composable.modifier.burnInAware +import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChanged +import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel +import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters +import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel +import com.android.systemui.res.R +import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController import javax.inject.Inject -class SmartSpaceSection @Inject constructor() { +class SmartSpaceSection +@Inject +constructor( + private val lockscreenSmartspaceController: LockscreenSmartspaceController, + private val keyguardUnlockAnimationController: KeyguardUnlockAnimationController, + private val keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel, + private val aodBurnInViewModel: AodBurnInViewModel, +) { @Composable - fun SceneScope.SmartSpace(modifier: Modifier = Modifier) { - MovableElement(key = SmartSpaceElementKey, modifier = modifier) { - Box( - modifier = Modifier.fillMaxWidth().background(Color.Cyan), - ) { - Text( - text = "TODO(b/316211368): Smart space", - color = Color.White, - modifier = Modifier.align(Alignment.Center), - ) + fun SceneScope.SmartSpace( + burnInParams: BurnInParameters, + onTopChanged: (top: Float?) -> Unit, + modifier: Modifier = Modifier, + ) { + Column( + modifier = modifier.element(SmartSpaceElementKey).onTopPlacementChanged(onTopChanged), + ) { + if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) { + return } + + val paddingBelowClockStart = dimensionResource(R.dimen.below_clock_padding_start) + val paddingBelowClockEnd = dimensionResource(R.dimen.below_clock_padding_end) + + if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = + Modifier.fillMaxWidth() + // All items will be constrained to be as tall as the shortest item. + .height(IntrinsicSize.Min) + .padding( + start = paddingBelowClockStart, + ), + ) { + Date( + modifier = + Modifier.burnInAware( + viewModel = aodBurnInViewModel, + params = burnInParams, + ), + ) + Spacer(modifier = Modifier.width(4.dp)) + Weather( + modifier = + Modifier.burnInAware( + viewModel = aodBurnInViewModel, + params = burnInParams, + ), + ) + } + } + + Card( + modifier = + Modifier.fillMaxWidth() + .padding( + start = paddingBelowClockStart, + end = paddingBelowClockEnd, + ) + .burnInAware( + viewModel = aodBurnInViewModel, + params = burnInParams, + ), + ) + } + } + + @Composable + private fun Card( + modifier: Modifier = Modifier, + ) { + AndroidView( + factory = { context -> + FrameLayout(context).apply { + addView( + lockscreenSmartspaceController.buildAndConnectView(this).apply { + layoutParams = + FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT, + ) + + keyguardUnlockAnimationController.lockscreenSmartspace = this + } + ) + } + }, + onRelease = { keyguardUnlockAnimationController.lockscreenSmartspace = null }, + modifier = modifier, + ) + } + + @Composable + private fun Weather( + modifier: Modifier = Modifier, + ) { + val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsState() + if (!isVisible) { + return } + + AndroidView( + factory = { context -> + FrameLayout(context).apply { + addView( + lockscreenSmartspaceController.buildAndConnectWeatherView(this).apply { + layoutParams = + FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT, + ) + } + ) + } + }, + modifier = modifier, + ) + } + + @Composable + private fun Date( + modifier: Modifier = Modifier, + ) { + val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsState() + if (!isVisible) { + return + } + + AndroidView( + factory = { context -> + FrameLayout(context).apply { + addView( + lockscreenSmartspaceController.buildAndConnectDateView(this).apply { + layoutParams = + FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT, + ) + } + ) + } + }, + modifier = modifier, + ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt index 6811eb4cea5c..ddc12ff22d50 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt @@ -21,9 +21,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope @@ -51,37 +53,43 @@ constructor( key = StatusBarElementKey, modifier = modifier, ) { - AndroidView( - factory = { - notificationPanelView.get().findViewById<View>(R.id.keyguard_header)?.let { - (it.parent as ViewGroup).removeView(it) - } + content { + AndroidView( + factory = { + notificationPanelView.get().findViewById<View>(R.id.keyguard_header)?.let { + (it.parent as ViewGroup).removeView(it) + } + + val provider = + object : ShadeViewStateProvider { + override val lockscreenShadeDragProgress: Float = 0f + override val panelViewExpandedHeight: Float = 0f - val provider = - object : ShadeViewStateProvider { - override val lockscreenShadeDragProgress: Float = 0f - override val panelViewExpandedHeight: Float = 0f - override fun shouldHeadsUpBeVisible(): Boolean { - return false + override fun shouldHeadsUpBeVisible(): Boolean { + return false + } } - } - @SuppressLint("InflateParams") - val view = - LayoutInflater.from(context) - .inflate( - R.layout.keyguard_status_bar, - null, - false, - ) as KeyguardStatusBarView - componentFactory.build(view, provider).keyguardStatusBarViewController.init() - view - }, - modifier = - Modifier.fillMaxWidth().height { - Utils.getStatusBarHeaderHeightKeyguard(context) + @SuppressLint("InflateParams") + val view = + LayoutInflater.from(context) + .inflate( + R.layout.keyguard_status_bar, + null, + false, + ) as KeyguardStatusBarView + componentFactory + .build(view, provider) + .keyguardStatusBarViewController + .init() + view }, - ) + modifier = + Modifier.fillMaxWidth().padding(horizontal = 16.dp).height { + Utils.getStatusBarHeaderHeightKeyguard(context) + }, + ) + } } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index 12f1b301c836..0eec024d3c81 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -44,7 +44,7 @@ import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.ValueKey -import com.android.compose.animation.scene.animateSharedFloatAsState +import com.android.compose.animation.scene.animateElementFloatAsState import com.android.systemui.notifications.ui.composable.Notifications.Form import com.android.systemui.notifications.ui.composable.Notifications.SharedValues.SharedExpansionValue import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel @@ -157,10 +157,10 @@ private fun SceneScope.NotificationPlaceholder( modifier: Modifier = Modifier, ) { val elementKey = Notifications.Elements.NotificationPlaceholder - Box( + Element( + elementKey, modifier = modifier - .element(elementKey) .debugBackground(viewModel) .onSizeChanged { size: IntSize -> debugLog(viewModel) { "STACK onSizeChanged: size=$size" } @@ -182,19 +182,23 @@ private fun SceneScope.NotificationPlaceholder( } ) { val animatedExpansion by - animateSharedFloatAsState( + animateElementFloatAsState( value = if (form == Form.HunFromTop) 0f else 1f, - key = SharedExpansionValue, - element = elementKey + key = SharedExpansionValue ) debugLog(viewModel) { "STACK composed: expansion=$animatedExpansion" } - if (viewModel.isPlaceholderTextVisible) { - Text( - text = "Notifications", - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.align(Alignment.Center), - ) + + content { + if (viewModel.isPlaceholderTextVisible) { + Box(Modifier.fillMaxSize()) { + Text( + text = "Notifications", + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.align(Alignment.Center), + ) + } + } } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt index f3cde534ebaa..9778e53d8f69 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt @@ -40,6 +40,7 @@ import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Companion.Collaps import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Expanding import com.android.systemui.res.R import com.android.systemui.scene.ui.composable.Gone +import com.android.systemui.scene.ui.composable.Lockscreen import com.android.systemui.scene.ui.composable.QuickSettings as QuickSettingsSceneKey import com.android.systemui.scene.ui.composable.Shade @@ -77,7 +78,12 @@ private fun SceneScope.stateForQuickSettingsContent(): QSSceneAdapter.State { toScene == Shade -> QSSceneAdapter.State.QQS toScene == QuickSettingsSceneKey -> QSSceneAdapter.State.QS toScene == Gone -> QSSceneAdapter.State.CLOSED - else -> error("Bad transition for QuickSettings: $transitionState") + toScene == Lockscreen -> QSSceneAdapter.State.CLOSED + else -> + error( + "Bad transition for QuickSettings: fromScene=$fromScene," + + " toScene=$toScene" + ) } } } @@ -98,7 +104,7 @@ fun SceneScope.QuickSettings( key = QuickSettings.Elements.Content, modifier = modifier.fillMaxWidth().defaultMinSize(minHeight = 300.dp) ) { - QuickSettingsContent(qsSceneAdapter = qsSceneAdapter, contentState) + content { QuickSettingsContent(qsSceneAdapter = qsSceneAdapter, contentState) } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt index 4bbb78b69392..e2beaeea6402 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt @@ -50,7 +50,7 @@ import androidx.compose.ui.viewinterop.AndroidView import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.ValueKey -import com.android.compose.animation.scene.animateSharedFloatAsState +import com.android.compose.animation.scene.animateSceneFloatAsState import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.settingslib.Utils import com.android.systemui.battery.BatteryMeterView @@ -69,7 +69,6 @@ import com.android.systemui.statusbar.policy.Clock object ShadeHeader { object Elements { - val FormatPlaceholder = ElementKey("ShadeHeaderFormatPlaceholder") val ExpandedContent = ElementKey("ShadeHeaderExpandedContent") val CollapsedContent = ElementKey("ShadeHeaderCollapsedContent") } @@ -92,19 +91,19 @@ fun SceneScope.CollapsedShadeHeader( statusBarIconController: StatusBarIconController, modifier: Modifier = Modifier, ) { - // TODO(b/298153892): Remove this once animateSharedFloatAsState.element can be null. - Spacer(Modifier.element(ShadeHeader.Elements.FormatPlaceholder)) val formatProgress = - animateSharedFloatAsState( - 0.0f, - ShadeHeader.Keys.transitionProgress, - ShadeHeader.Elements.FormatPlaceholder - ) + animateSceneFloatAsState(0f, ShadeHeader.Keys.transitionProgress) + .unsafeCompositionState(initialValue = 0f) val cutoutWidth = LocalDisplayCutout.current.width() val cutoutLocation = LocalDisplayCutout.current.location - val useExpandedFormat = formatProgress.value > 0.5f || cutoutLocation != CutoutLocation.CENTER + val useExpandedFormat by + remember(formatProgress) { + derivedStateOf { + cutoutLocation != CutoutLocation.CENTER || formatProgress.value > 0.5f + } + } // This layout assumes it is globally positioned at (0, 0) and is the // same size as the screen. @@ -217,14 +216,9 @@ fun SceneScope.ExpandedShadeHeader( statusBarIconController: StatusBarIconController, modifier: Modifier = Modifier, ) { - // TODO(b/298153892): Remove this once animateSharedFloatAsState.element can be null. - Spacer(Modifier.element(ShadeHeader.Elements.FormatPlaceholder)) val formatProgress = - animateSharedFloatAsState( - 1.0f, - ShadeHeader.Keys.transitionProgress, - ShadeHeader.Elements.FormatPlaceholder - ) + animateSceneFloatAsState(1f, ShadeHeader.Keys.transitionProgress) + .unsafeCompositionState(initialValue = 1f) val useExpandedFormat by remember(formatProgress) { derivedStateOf { formatProgress.value > 0.5f } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt index 2944bd9f9a8e..b26194f2397b 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt @@ -17,10 +17,15 @@ package com.android.compose.animation.scene import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.Stable import androidx.compose.runtime.State -import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshots.Snapshot +import androidx.compose.runtime.snapshotFlow +import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.lerp import androidx.compose.ui.unit.Dp @@ -28,180 +33,263 @@ import androidx.compose.ui.unit.lerp import com.android.compose.ui.util.lerp /** - * Animate a shared Int value. + * A [State] whose [value] is animated. * - * @see SceneScope.animateSharedValueAsState + * Important: This animated value should always be ready *after* composition, e.g. during layout, + * drawing or inside a LaunchedEffect. If you read [value] during composition, it will probably + * throw an exception, for 2 important reasons: + * 1. You should never read animated values during composition, because this will probably lead to + * bad performance. + * 2. Given that this value depends on the target value in different scenes, its current value + * (depending on the current transition state) can only be computed once the full tree has been + * composed. + * + * If you don't have the choice and *have to* get the value during composition, for instance because + * a Modifier or Composable reading this value does not have a lazy/lambda-based API, then you can + * access [unsafeCompositionState] and use a fallback value for the first frame where this animated + * value can not be computed yet. Note however that doing so will be bad for performance and might + * lead to late-by-one-frame flickers. + */ +@Stable +interface AnimatedState<T> : State<T> { + /** + * Return a [State] that can be read during composition. + * + * Important: You should avoid using this as much as possible and instead read [value] during + * layout/drawing, otherwise you will probably end up with a few frames that have a value that + * is not correctly interpolated. + */ + @Composable fun unsafeCompositionState(initialValue: T): State<T> +} + +/** + * Animate a scene Int value. + * + * @see SceneScope.animateSceneValueAsState */ @Composable -fun SceneScope.animateSharedIntAsState( +fun SceneScope.animateSceneIntAsState( value: Int, key: ValueKey, - element: ElementKey?, canOverflow: Boolean = true, -): State<Int> { - return animateSharedValueAsState(value, key, element, ::lerp, canOverflow) +): AnimatedState<Int> { + return animateSceneValueAsState(value, key, ::lerp, canOverflow) } /** - * Animate a shared Int value. + * Animate a shared element Int value. * - * @see MovableElementScope.animateSharedValueAsState + * @see ElementScope.animateElementValueAsState */ @Composable -fun MovableElementScope.animateSharedIntAsState( +fun ElementScope<*>.animateElementIntAsState( value: Int, - debugName: String, + key: ValueKey, canOverflow: Boolean = true, -): State<Int> { - return animateSharedValueAsState(value, debugName, ::lerp, canOverflow) +): AnimatedState<Int> { + return animateElementValueAsState(value, key, ::lerp, canOverflow) } /** - * Animate a shared Float value. + * Animate a scene Float value. * - * @see SceneScope.animateSharedValueAsState + * @see SceneScope.animateSceneValueAsState */ @Composable -fun SceneScope.animateSharedFloatAsState( +fun SceneScope.animateSceneFloatAsState( value: Float, key: ValueKey, - element: ElementKey?, canOverflow: Boolean = true, -): State<Float> { - return animateSharedValueAsState(value, key, element, ::lerp, canOverflow) +): AnimatedState<Float> { + return animateSceneValueAsState(value, key, ::lerp, canOverflow) } /** - * Animate a shared Float value. + * Animate a shared element Float value. * - * @see MovableElementScope.animateSharedValueAsState + * @see ElementScope.animateElementValueAsState */ @Composable -fun MovableElementScope.animateSharedFloatAsState( +fun ElementScope<*>.animateElementFloatAsState( value: Float, - debugName: String, + key: ValueKey, canOverflow: Boolean = true, -): State<Float> { - return animateSharedValueAsState(value, debugName, ::lerp, canOverflow) +): AnimatedState<Float> { + return animateElementValueAsState(value, key, ::lerp, canOverflow) } /** - * Animate a shared Dp value. + * Animate a scene Dp value. * - * @see SceneScope.animateSharedValueAsState + * @see SceneScope.animateSceneValueAsState */ @Composable -fun SceneScope.animateSharedDpAsState( +fun SceneScope.animateSceneDpAsState( value: Dp, key: ValueKey, - element: ElementKey?, canOverflow: Boolean = true, -): State<Dp> { - return animateSharedValueAsState(value, key, element, ::lerp, canOverflow) +): AnimatedState<Dp> { + return animateSceneValueAsState(value, key, ::lerp, canOverflow) } /** - * Animate a shared Dp value. + * Animate a shared element Dp value. * - * @see MovableElementScope.animateSharedValueAsState + * @see ElementScope.animateElementValueAsState */ @Composable -fun MovableElementScope.animateSharedDpAsState( +fun ElementScope<*>.animateElementDpAsState( value: Dp, - debugName: String, + key: ValueKey, canOverflow: Boolean = true, -): State<Dp> { - return animateSharedValueAsState(value, debugName, ::lerp, canOverflow) +): AnimatedState<Dp> { + return animateElementValueAsState(value, key, ::lerp, canOverflow) } /** - * Animate a shared Color value. + * Animate a scene Color value. * - * @see SceneScope.animateSharedValueAsState + * @see SceneScope.animateSceneValueAsState */ @Composable -fun SceneScope.animateSharedColorAsState( +fun SceneScope.animateSceneColorAsState( value: Color, key: ValueKey, - element: ElementKey?, -): State<Color> { - return animateSharedValueAsState(value, key, element, ::lerp, canOverflow = false) +): AnimatedState<Color> { + return animateSceneValueAsState(value, key, ::lerp, canOverflow = false) } /** - * Animate a shared Color value. + * Animate a shared element Color value. * - * @see MovableElementScope.animateSharedValueAsState + * @see ElementScope.animateElementValueAsState */ @Composable -fun MovableElementScope.animateSharedColorAsState( +fun ElementScope<*>.animateElementColorAsState( value: Color, - debugName: String, -): State<Color> { - return animateSharedValueAsState(value, debugName, ::lerp, canOverflow = false) + key: ValueKey, +): AnimatedState<Color> { + return animateElementValueAsState(value, key, ::lerp, canOverflow = false) } @Composable internal fun <T> animateSharedValueAsState( layoutImpl: SceneTransitionLayoutImpl, - scene: Scene, - element: Element?, + scene: SceneKey, + element: ElementKey?, key: ValueKey, value: T, lerp: (T, T, Float) -> T, canOverflow: Boolean, -): State<T> { - val sharedValue = - Snapshot.withoutReadObservation { - val sharedValues = - element?.sceneValues?.getValue(scene.key)?.sharedValues ?: scene.sharedValues - sharedValues.getOrPut(key) { Element.SharedValue(key, value) } as Element.SharedValue<T> - } +): AnimatedState<T> { + DisposableEffect(layoutImpl, scene, element, key) { + // Create the associated maps that hold the current value for each (element, scene) pair. + val valueMap = layoutImpl.sharedValues.getOrPut(key) { mutableMapOf() } + val sceneToValueMap = + valueMap.getOrPut(element) { SnapshotStateMap<SceneKey, Any>() } + as SnapshotStateMap<SceneKey, T> + sceneToValueMap[scene] = value + + onDispose { + // Remove the value associated to the current scene, and eventually remove the maps if + // they are empty. + sceneToValueMap.remove(scene) - if (value != sharedValue.value) { - sharedValue.value = value + if (sceneToValueMap.isEmpty() && valueMap[element] === sceneToValueMap) { + valueMap.remove(element) + + if (valueMap.isEmpty() && layoutImpl.sharedValues[key] === valueMap) { + layoutImpl.sharedValues.remove(key) + } + } + } } - return remember(layoutImpl, element, sharedValue, lerp, canOverflow) { - derivedStateOf { computeValue(layoutImpl, element, sharedValue, lerp, canOverflow) } + // Update the current value. Note that side effects run after disposable effects, so we know + // that the associated maps were created at this point. + SideEffect { sceneToValueMap<T>(layoutImpl, key, element)[scene] = value } + + return remember(layoutImpl, scene, element, lerp, canOverflow) { + object : AnimatedState<T> { + override val value: T + get() = value(layoutImpl, scene, element, key, lerp, canOverflow) + + @Composable + override fun unsafeCompositionState(initialValue: T): State<T> { + val state = remember { mutableStateOf(initialValue) } + + val animatedState = this + LaunchedEffect(animatedState) { + snapshotFlow { animatedState.value }.collect { state.value = it } + } + + return state + } + } } } -private fun <T> computeValue( +private fun <T> sceneToValueMap( layoutImpl: SceneTransitionLayoutImpl, - element: Element?, - sharedValue: Element.SharedValue<T>, + key: ValueKey, + element: ElementKey? +): MutableMap<SceneKey, T> { + return layoutImpl.sharedValues[key]?.get(element)?.let { it as SnapshotStateMap<SceneKey, T> } + ?: error(valueReadTooEarlyMessage(key)) +} + +private fun valueReadTooEarlyMessage(key: ValueKey) = + "Animated value $key was read before its target values were set. This probably " + + "means that you are reading it during composition, which you should not do. See the " + + "documentation of AnimatedState for more information." + +private fun <T> value( + layoutImpl: SceneTransitionLayoutImpl, + scene: SceneKey, + element: ElementKey?, + key: ValueKey, lerp: (T, T, Float) -> T, canOverflow: Boolean, ): T { - val transition = layoutImpl.state.currentTransition - if (transition == null || !layoutImpl.isTransitionReady(transition)) { - return sharedValue.value - } + return valueOrNull(layoutImpl, scene, element, key, lerp, canOverflow) + ?: error(valueReadTooEarlyMessage(key)) +} - fun sceneValue(scene: SceneKey): Element.SharedValue<T>? { - val sharedValues = - if (element == null) { - layoutImpl.scene(scene).sharedValues - } else { - element.sceneValues[scene]?.sharedValues - } - ?: return null - val value = sharedValues[sharedValue.key] ?: return null - return value as Element.SharedValue<T> - } +private fun <T> valueOrNull( + layoutImpl: SceneTransitionLayoutImpl, + scene: SceneKey, + element: ElementKey?, + key: ValueKey, + lerp: (T, T, Float) -> T, + canOverflow: Boolean, +): T? { + val sceneToValueMap = sceneToValueMap<T>(layoutImpl, key, element) + fun sceneValue(scene: SceneKey): T? = sceneToValueMap[scene] - val fromValue = sceneValue(transition.fromScene) - val toValue = sceneValue(transition.toScene) - return if (fromValue != null && toValue != null) { - val progress = - if (canOverflow) transition.progress else transition.progress.coerceIn(0f, 1f) - lerp(fromValue.value, toValue.value, progress) - } else if (fromValue != null) { - fromValue.value - } else if (toValue != null) { - toValue.value - } else { - sharedValue.value + return when (val transition = layoutImpl.state.transitionState) { + is TransitionState.Idle -> sceneValue(transition.currentScene) + is TransitionState.Transition -> { + // Note: no need to check for transition ready here given that all target values are + // defined during composition, we should already have the correct values to interpolate + // between here. + val fromValue = sceneValue(transition.fromScene) + val toValue = sceneValue(transition.toScene) + if (fromValue != null && toValue != null) { + if (fromValue == toValue) { + // Optimization: avoid reading progress if the values are the same, so we don't + // relayout/redraw for nothing. + fromValue + } else { + val progress = + if (canOverflow) transition.progress + else transition.progress.coerceIn(0f, 1f) + lerp(fromValue, toValue, progress) + } + } else fromValue ?: toValue + } } + // TODO(b/311600838): Remove this. We should not have to fallback to the current scene value, + // but we have to because code of removed nodes can still run if they are placed with a graphics + // layer. + ?: sceneValue(scene) } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt index a85d9bff283e..280fbfb7d3d3 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt @@ -16,15 +16,10 @@ package com.android.compose.animation.scene -import android.graphics.Picture -import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue -import androidx.compose.runtime.movableContentOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import androidx.compose.runtime.snapshots.Snapshot -import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset @@ -52,43 +47,22 @@ import kotlinx.coroutines.launch @Stable internal class Element(val key: ElementKey) { /** - * The last values of this element, coming from any scene. Note that this value will be unstable + * The last state of this element, coming from any scene. Note that this state will be unstable * if this element is present in multiple scenes but the shared element animation is disabled, - * given that multiple instances of the element with different states will write to these - * values. You should prefer using [TargetValues.lastValues] in the current scene if it is - * defined. + * given that multiple instances of the element with different states will write to this state. + * You should prefer using [SceneState.lastState] in the current scene when it is defined. */ - val lastSharedValues = Values() + val lastSharedState = State() - /** The mapping between a scene and the values/state this element has in that scene, if any. */ - val sceneValues = SnapshotStateMap<SceneKey, TargetValues>() - - /** - * The movable content of this element, if this element is composed using - * [SceneScope.MovableElement]. - */ - private var _movableContent: (@Composable (@Composable () -> Unit) -> Unit)? = null - val movableContent: @Composable (@Composable () -> Unit) -> Unit - get() = - _movableContent - ?: movableContentOf { content: @Composable () -> Unit -> content() } - .also { _movableContent = it } - - /** - * The [Picture] to which we save the last drawing commands of this element, if it is movable. - * This is necessary because the content of this element might not be composed in the scene it - * should currently be drawn. - */ - private var _picture: Picture? = null - val picture: Picture - get() = _picture ?: Picture().also { _picture = it } + /** The mapping between a scene and the state this element has in that scene, if any. */ + val sceneStates = mutableMapOf<SceneKey, SceneState>() override fun toString(): String { return "Element(key=$key)" } - /** The current values of this element, either in a specific scene or in a shared context. */ - class Values { + /** The state of this element, either in a specific scene or in a shared context. */ + class State { /** The offset of the element, relative to the SceneTransitionLayout containing it. */ var offset = Offset.Unspecified @@ -102,16 +76,14 @@ internal class Element(val key: ElementKey) { var alpha = AlphaUnspecified } - /** The target values of this element in a given scene. */ + /** The last and target state of this element in a given scene. */ @Stable - class TargetValues(val scene: SceneKey) { - val lastValues = Values() + class SceneState(val scene: SceneKey) { + val lastState = State() var targetSize by mutableStateOf(SizeUnspecified) var targetOffset by mutableStateOf(Offset.Unspecified) - val sharedValues = SnapshotStateMap<ValueKey, SharedValue<*>>() - /** * The attached [ElementNode] a Modifier.element() for a given element and scene. During * composition, this set could have 0 to 2 elements. After composition and after all @@ -120,12 +92,6 @@ internal class Element(val key: ElementKey) { val nodes = mutableSetOf<ElementNode>() } - /** A shared value of this element. */ - @Stable - class SharedValue<T>(val key: ValueKey, initialValue: T) { - var value by mutableStateOf(initialValue) - } - companion object { val SizeUnspecified = IntSize(Int.MAX_VALUE, Int.MAX_VALUE) val AlphaUnspecified = Float.MIN_VALUE @@ -147,27 +113,18 @@ internal fun Modifier.element( scene: Scene, key: ElementKey, ): Modifier { - val element: Element - val sceneValues: Element.TargetValues - - // Get the element associated to [key] if it was already composed in another scene, - // otherwise create it and add it to our Map<ElementKey, Element>. This is done inside a - // withoutReadObservation() because there is no need to recompose when that map is mutated. - Snapshot.withoutReadObservation { - element = layoutImpl.elements[key] ?: Element(key).also { layoutImpl.elements[key] = it } - sceneValues = - element.sceneValues[scene.key] - ?: Element.TargetValues(scene.key).also { element.sceneValues[scene.key] = it } - } - - return this.then(ElementModifier(layoutImpl, scene, element, sceneValues)) + return this.then(ElementModifier(layoutImpl, scene, key)) // TODO(b/311132415): Move this into ElementNode once we can create a delegate // IntermediateLayoutModifierNode. .intermediateLayout { measurable, constraints -> - val placeable = - measure(layoutImpl, scene, element, sceneValues, measurable, constraints) + // TODO(b/311132415): No need to fetch the element and sceneState from the map anymore + // once this is merged into ElementNode. + val element = layoutImpl.elements.getValue(key) + val sceneState = element.sceneStates.getValue(scene.key) + + val placeable = measure(layoutImpl, scene, element, sceneState, measurable, constraints) layout(placeable.width, placeable.height) { - place(layoutImpl, scene, element, sceneValues, placeable, placementScope = this) + place(layoutImpl, scene, element, sceneState, placeable, placementScope = this) } } .testTag(key.testTag) @@ -180,72 +137,89 @@ internal fun Modifier.element( private data class ElementModifier( private val layoutImpl: SceneTransitionLayoutImpl, private val scene: Scene, - private val element: Element, - private val sceneValues: Element.TargetValues, + private val key: ElementKey, ) : ModifierNodeElement<ElementNode>() { - override fun create(): ElementNode = ElementNode(layoutImpl, scene, element, sceneValues) + override fun create(): ElementNode = ElementNode(layoutImpl, scene, key) override fun update(node: ElementNode) { - node.update(layoutImpl, scene, element, sceneValues) + node.update(layoutImpl, scene, key) } } internal class ElementNode( private var layoutImpl: SceneTransitionLayoutImpl, private var scene: Scene, - private var element: Element, - private var sceneValues: Element.TargetValues, + private var key: ElementKey, ) : Modifier.Node(), DrawModifierNode { + private var _element: Element? = null + private val element: Element + get() = _element!! + + private var _sceneState: Element.SceneState? = null + private val sceneState: Element.SceneState + get() = _sceneState!! override fun onAttach() { super.onAttach() - addNodeToSceneValues() + updateElementAndSceneValues() + addNodeToSceneState() } - private fun addNodeToSceneValues() { - sceneValues.nodes.add(this) + private fun updateElementAndSceneValues() { + val element = + layoutImpl.elements[key] ?: Element(key).also { layoutImpl.elements[key] = it } + _element = element + _sceneState = + element.sceneStates[scene.key] + ?: Element.SceneState(scene.key).also { element.sceneStates[scene.key] = it } + } + + private fun addNodeToSceneState() { + sceneState.nodes.add(this) coroutineScope.launch { // At this point all [CodeLocationNode] have been attached or detached, which means that - // [sceneValues.codeLocations] should have exactly 1 element, otherwise this means that + // [sceneState.codeLocations] should have exactly 1 element, otherwise this means that // this element was composed multiple times in the same scene. - val nCodeLocations = sceneValues.nodes.size - if (nCodeLocations != 1 || !sceneValues.nodes.contains(this@ElementNode)) { - error("${element.key} was composed $nCodeLocations times in ${sceneValues.scene}") + val nCodeLocations = sceneState.nodes.size + if (nCodeLocations != 1 || !sceneState.nodes.contains(this@ElementNode)) { + error("$key was composed $nCodeLocations times in ${sceneState.scene}") } } } override fun onDetach() { super.onDetach() - removeNodeFromSceneValues() - maybePruneMaps(layoutImpl, element, sceneValues) + removeNodeFromSceneState() + maybePruneMaps(layoutImpl, element, sceneState) + + _element = null + _sceneState = null } - private fun removeNodeFromSceneValues() { - sceneValues.nodes.remove(this) + private fun removeNodeFromSceneState() { + sceneState.nodes.remove(this) } fun update( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, - element: Element, - sceneValues: Element.TargetValues, + key: ElementKey, ) { check(layoutImpl == this.layoutImpl && scene == this.scene) - removeNodeFromSceneValues() + removeNodeFromSceneState() val prevElement = this.element - val prevSceneValues = this.sceneValues - this.element = element - this.sceneValues = sceneValues + val prevSceneState = this.sceneState + this.key = key + updateElementAndSceneValues() - addNodeToSceneValues() - maybePruneMaps(layoutImpl, prevElement, prevSceneValues) + addNodeToSceneState() + maybePruneMaps(layoutImpl, prevElement, prevSceneState) } override fun ContentDrawScope.draw() { - val drawScale = getDrawScale(layoutImpl, element, scene, sceneValues) + val drawScale = getDrawScale(layoutImpl, element, scene, sceneState) if (drawScale == Scale.Default) { drawContent() } else { @@ -263,18 +237,16 @@ internal class ElementNode( private fun maybePruneMaps( layoutImpl: SceneTransitionLayoutImpl, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, ) { // If element is not composed from this scene anymore, remove the scene values. This // works because [onAttach] is called before [onDetach], so if an element is moved from // the UI tree we will first add the new code location then remove the old one. - if ( - sceneValues.nodes.isEmpty() && element.sceneValues[sceneValues.scene] == sceneValues - ) { - element.sceneValues.remove(sceneValues.scene) + if (sceneState.nodes.isEmpty() && element.sceneStates[sceneState.scene] == sceneState) { + element.sceneStates.remove(sceneState.scene) // If the element is not composed in any scene, remove it from the elements map. - if (element.sceneValues.isEmpty() && layoutImpl.elements[element.key] == element) { + if (element.sceneStates.isEmpty() && layoutImpl.elements[element.key] == element) { layoutImpl.elements.remove(element.key) } } @@ -293,8 +265,8 @@ private fun shouldDrawElement( if ( transition == null || !layoutImpl.isTransitionReady(transition) || - transition.fromScene !in element.sceneValues || - transition.toScene !in element.sceneValues + transition.fromScene !in element.sceneStates || + transition.toScene !in element.sceneStates ) { return true } @@ -310,7 +282,6 @@ private fun shouldDrawElement( transition, scene.key, element.key, - sharedTransformation, ) } @@ -319,17 +290,14 @@ internal fun shouldDrawOrComposeSharedElement( transition: TransitionState.Transition, scene: SceneKey, element: ElementKey, - sharedTransformation: SharedElementTransformation? ): Boolean { - val scenePicker = sharedTransformation?.scenePicker ?: DefaultSharedElementScenePicker + val scenePicker = element.scenePicker val fromScene = transition.fromScene val toScene = transition.toScene return scenePicker.sceneDuringTransition( element = element, - fromScene = fromScene, - toScene = toScene, - progress = transition::progress, + transition = transition, fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex, toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex, ) == scene @@ -374,28 +342,28 @@ private fun isElementOpaque( layoutImpl: SceneTransitionLayoutImpl, element: Element, scene: Scene, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, ): Boolean { val transition = layoutImpl.state.currentTransition ?: return true if (!layoutImpl.isTransitionReady(transition)) { val lastValue = - sceneValues.lastValues.alpha.takeIf { it != Element.AlphaUnspecified } - ?: element.lastSharedValues.alpha.takeIf { it != Element.AlphaUnspecified } ?: 1f + sceneState.lastState.alpha.takeIf { it != Element.AlphaUnspecified } + ?: element.lastSharedState.alpha.takeIf { it != Element.AlphaUnspecified } ?: 1f return lastValue == 1f } val fromScene = transition.fromScene val toScene = transition.toScene - val fromValues = element.sceneValues[fromScene] - val toValues = element.sceneValues[toScene] + val fromState = element.sceneStates[fromScene] + val toState = element.sceneStates[toScene] - if (fromValues == null && toValues == null) { + if (fromState == null && toState == null) { error("This should not happen, element $element is neither in $fromScene or $toScene") } - val isSharedElement = fromValues != null && toValues != null + val isSharedElement = fromState != null && toState != null if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) { return true } @@ -415,7 +383,7 @@ private fun elementAlpha( layoutImpl: SceneTransitionLayoutImpl, element: Element, scene: Scene, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, ): Float { return computeValue( layoutImpl, @@ -426,9 +394,8 @@ private fun elementAlpha( idleValue = 1f, currentValue = { 1f }, lastValue = { - sceneValues.lastValues.alpha.takeIf { it != Element.AlphaUnspecified } - ?: element.lastSharedValues.alpha.takeIf { it != Element.AlphaUnspecified } - ?: 1f + sceneState.lastState.alpha.takeIf { it != Element.AlphaUnspecified } + ?: element.lastSharedState.alpha.takeIf { it != Element.AlphaUnspecified } ?: 1f }, ::lerp, ) @@ -440,15 +407,15 @@ private fun IntermediateMeasureScope.measure( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, measurable: Measurable, constraints: Constraints, ): Placeable { // Update the size this element has in this scene when idle. val targetSizeInScene = lookaheadSize - if (targetSizeInScene != sceneValues.targetSize) { + if (targetSizeInScene != sceneState.targetSize) { // TODO(b/290930950): Better handle when this changes to avoid instant size jumps. - sceneValues.targetSize = targetSizeInScene + sceneState.targetSize = targetSizeInScene } // Some lambdas called (max once) by computeValue() will need to measure [measurable], in which @@ -468,8 +435,8 @@ private fun IntermediateMeasureScope.measure( idleValue = lookaheadSize, currentValue = { measurable.measure(constraints).also { maybePlaceable = it }.size() }, lastValue = { - sceneValues.lastValues.size.takeIf { it != Element.SizeUnspecified } - ?: element.lastSharedValues.size.takeIf { it != Element.SizeUnspecified } + sceneState.lastState.size.takeIf { it != Element.SizeUnspecified } + ?: element.lastSharedState.size.takeIf { it != Element.SizeUnspecified } ?: measurable.measure(constraints).also { maybePlaceable = it }.size() }, ::lerp, @@ -485,8 +452,8 @@ private fun IntermediateMeasureScope.measure( ) val size = placeable.size() - element.lastSharedValues.size = size - sceneValues.lastValues.size = size + element.lastSharedState.size = size + sceneState.lastState.size = size return placeable } @@ -494,7 +461,7 @@ private fun getDrawScale( layoutImpl: SceneTransitionLayoutImpl, element: Element, scene: Scene, - sceneValues: Element.TargetValues + sceneState: Element.SceneState ): Scale { return computeValue( layoutImpl, @@ -505,8 +472,8 @@ private fun getDrawScale( idleValue = Scale.Default, currentValue = { Scale.Default }, lastValue = { - sceneValues.lastValues.drawScale.takeIf { it != Scale.Default } - ?: element.lastSharedValues.drawScale + sceneState.lastState.drawScale.takeIf { it != Scale.Default } + ?: element.lastSharedState.drawScale }, ::lerp, ) @@ -517,7 +484,7 @@ private fun IntermediateMeasureScope.place( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, placeable: Placeable, placementScope: Placeable.PlacementScope, ) { @@ -526,14 +493,14 @@ private fun IntermediateMeasureScope.place( // when idle. val coords = coordinates ?: error("Element ${element.key} does not have any coordinates") val targetOffsetInScene = lookaheadScopeCoordinates.localLookaheadPositionOf(coords) - if (targetOffsetInScene != sceneValues.targetOffset) { + if (targetOffsetInScene != sceneState.targetOffset) { // TODO(b/290930950): Better handle when this changes to avoid instant offset jumps. - sceneValues.targetOffset = targetOffsetInScene + sceneState.targetOffset = targetOffsetInScene } val currentOffset = lookaheadScopeCoordinates.localPositionOf(coords, Offset.Zero) - val lastSharedValues = element.lastSharedValues - val lastValues = sceneValues.lastValues + val lastSharedState = element.lastSharedState + val lastSceneState = sceneState.lastState val targetOffset = computeValue( layoutImpl, @@ -544,36 +511,36 @@ private fun IntermediateMeasureScope.place( idleValue = targetOffsetInScene, currentValue = { currentOffset }, lastValue = { - lastValues.offset.takeIf { it.isSpecified } - ?: lastSharedValues.offset.takeIf { it.isSpecified } ?: currentOffset + lastSceneState.offset.takeIf { it.isSpecified } + ?: lastSharedState.offset.takeIf { it.isSpecified } ?: currentOffset }, ::lerp, ) - lastSharedValues.offset = targetOffset - lastValues.offset = targetOffset + lastSharedState.offset = targetOffset + lastSceneState.offset = targetOffset // No need to place the element in this scene if we don't want to draw it anyways. Note that - // it's still important to compute the target offset and update lastValues, otherwise it - // will be out of date. + // it's still important to compute the target offset and update last(Shared|Scene)State, + // otherwise they will be out of date. if (!shouldDrawElement(layoutImpl, scene, element)) { return } val offset = (targetOffset - currentOffset).round() - if (isElementOpaque(layoutImpl, element, scene, sceneValues)) { + if (isElementOpaque(layoutImpl, element, scene, sceneState)) { // TODO(b/291071158): Call placeWithLayer() if offset != IntOffset.Zero and size is not // animated once b/305195729 is fixed. Test that drawing is not invalidated in that // case. placeable.place(offset) - lastSharedValues.alpha = 1f - lastValues.alpha = 1f + lastSharedState.alpha = 1f + lastSceneState.alpha = 1f } else { placeable.placeWithLayer(offset) { - val alpha = elementAlpha(layoutImpl, element, scene, sceneValues) + val alpha = elementAlpha(layoutImpl, element, scene, sceneState) this.alpha = alpha - lastSharedValues.alpha = alpha - lastValues.alpha = alpha + lastSharedState.alpha = alpha + lastSceneState.alpha = alpha } } } @@ -605,7 +572,7 @@ private inline fun <T> computeValue( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValue: (Element.TargetValues) -> T, + sceneValue: (Element.SceneState) -> T, transformation: (ElementTransformations) -> PropertyTransformation<T>?, idleValue: T, currentValue: () -> T, @@ -628,10 +595,10 @@ private inline fun <T> computeValue( val fromScene = transition.fromScene val toScene = transition.toScene - val fromValues = element.sceneValues[fromScene] - val toValues = element.sceneValues[toScene] + val fromState = element.sceneStates[fromScene] + val toState = element.sceneStates[toScene] - if (fromValues == null && toValues == null) { + if (fromState == null && toState == null) { // TODO(b/311600838): Throw an exception instead once layers of disposed elements are not // run anymore. return lastValue() @@ -640,10 +607,10 @@ private inline fun <T> computeValue( // The element is shared: interpolate between the value in fromScene and the value in toScene. // TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared // elements follow the finger direction. - val isSharedElement = fromValues != null && toValues != null + val isSharedElement = fromState != null && toState != null if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) { - val start = sceneValue(fromValues!!) - val end = sceneValue(toValues!!) + val start = sceneValue(fromState!!) + val end = sceneValue(toState!!) // Make sure we don't read progress if values are the same and we don't need to interpolate, // so we don't invalidate the phase where this is read. @@ -659,12 +626,12 @@ private inline fun <T> computeValue( // Get the transformed value, i.e. the target value at the beginning (for entering elements) or // end (for leaving elements) of the transition. - val sceneValues = + val sceneState = checkNotNull( when { - isSharedElement && scene.key == fromScene -> fromValues - isSharedElement -> toValues - else -> fromValues ?: toValues + isSharedElement && scene.key == fromScene -> fromState + isSharedElement -> toState + else -> fromState ?: toState } ) @@ -673,7 +640,7 @@ private inline fun <T> computeValue( layoutImpl, scene, element, - sceneValues, + sceneState, transition, idleValue, ) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt index 84d3b8647d6c..90f46bd4dcaa 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt @@ -64,10 +64,10 @@ class ElementKey( identity: Any = Object(), /** - * Whether this element is a background and usually drawn below other elements. This should be - * set to true to make sure that shared backgrounds are drawn below elements of other scenes. + * The [ElementScenePicker] to use when deciding in which scene we should draw shared Elements + * or compose MovableElements. */ - val isBackground: Boolean = false, + val scenePicker: ElementScenePicker = DefaultElementScenePicker, ) : Key(name, identity), ElementMatcher { @VisibleForTesting // TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt index 49df2f6b6062..af3c0999c97b 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt @@ -16,27 +16,36 @@ package com.android.compose.animation.scene -import android.util.Log import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.BoxScope import androidx.compose.runtime.Composable -import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.movableContentOf import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshots.Snapshot import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawBehind -import androidx.compose.ui.draw.drawWithCache -import androidx.compose.ui.graphics.Canvas -import androidx.compose.ui.graphics.drawscope.draw -import androidx.compose.ui.graphics.drawscope.drawIntoCanvas -import androidx.compose.ui.graphics.nativeCanvas -import androidx.compose.ui.layout.layout -import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntSize -private const val TAG = "MovableElement" +@Composable +internal fun Element( + layoutImpl: SceneTransitionLayoutImpl, + scene: Scene, + key: ElementKey, + modifier: Modifier, + content: @Composable ElementScope<ElementContentScope>.() -> Unit, +) { + Box(modifier.element(layoutImpl, scene, key)) { + val sceneScope = scene.scope + val boxScope = this + val elementScope = + remember(layoutImpl, key, scene, sceneScope, boxScope) { + ElementScopeImpl(layoutImpl, key, scene, sceneScope, boxScope) + } + + content(elementScope) + } +} @Composable internal fun MovableElement( @@ -44,72 +53,113 @@ internal fun MovableElement( scene: Scene, key: ElementKey, modifier: Modifier, - content: @Composable MovableElementScope.() -> Unit, + content: @Composable ElementScope<MovableElementContentScope>.() -> Unit, ) { Box(modifier.element(layoutImpl, scene, key)) { - // Get the Element from the map. It will always be the same and we don't want to recompose - // every time an element is added/removed from SceneTransitionLayoutImpl.elements, so we - // disable read observation during the look-up in that map. - val element = Snapshot.withoutReadObservation { layoutImpl.elements.getValue(key) } - val movableElementScope = - remember(layoutImpl, element, scene) { - MovableElementScopeImpl(layoutImpl, element, scene) + val sceneScope = scene.scope + val boxScope = this + val elementScope = + remember(layoutImpl, key, scene, sceneScope, boxScope) { + MovableElementScopeImpl(layoutImpl, key, scene, sceneScope, boxScope) } - // The [Picture] to which we save the last drawing commands of this element. This is - // necessary because the content of this element might not be composed in this scene, in - // which case we still need to draw it. - val picture = element.picture + content(elementScope) + } +} + +private abstract class BaseElementScope<ContentScope>( + private val layoutImpl: SceneTransitionLayoutImpl, + private val element: ElementKey, + private val scene: Scene, +) : ElementScope<ContentScope> { + @Composable + override fun <T> animateElementValueAsState( + value: T, + key: ValueKey, + lerp: (start: T, stop: T, fraction: Float) -> T, + canOverflow: Boolean + ): AnimatedState<T> { + return animateSharedValueAsState( + layoutImpl, + scene.key, + element, + key, + value, + lerp, + canOverflow, + ) + } +} + +private class ElementScopeImpl( + layoutImpl: SceneTransitionLayoutImpl, + element: ElementKey, + scene: Scene, + private val sceneScope: SceneScope, + private val boxScope: BoxScope, +) : BaseElementScope<ElementContentScope>(layoutImpl, element, scene) { + private val contentScope = + object : ElementContentScope, SceneScope by sceneScope, BoxScope by boxScope {} + @Composable + override fun content(content: @Composable ElementContentScope.() -> Unit) { + contentScope.content() + } +} + +private class MovableElementScopeImpl( + private val layoutImpl: SceneTransitionLayoutImpl, + private val element: ElementKey, + private val scene: Scene, + private val sceneScope: BaseSceneScope, + private val boxScope: BoxScope, +) : BaseElementScope<MovableElementContentScope>(layoutImpl, element, scene) { + private val contentScope = + object : MovableElementContentScope, BaseSceneScope by sceneScope, BoxScope by boxScope {} + + @Composable + override fun content(content: @Composable MovableElementContentScope.() -> Unit) { // Whether we should compose the movable element here. The scene picker logic to know in // which scene we should compose/draw a movable element might depend on the current // transition progress, so we put this in a derivedStateOf to prevent many recompositions // during the transition. + // TODO(b/317026105): Use derivedStateOf only if the scene picker reads the progress in its + // logic. val shouldComposeMovableElement by remember(layoutImpl, scene.key, element) { derivedStateOf { shouldComposeMovableElement(layoutImpl, scene.key, element) } } if (shouldComposeMovableElement) { - Box( - Modifier.drawWithCache { - val width = size.width.toInt() - val height = size.height.toInt() - - onDrawWithContent { - // Save the draw commands into [picture] for later to draw the last content - // even when this movable content is not composed. - val pictureCanvas = Canvas(picture.beginRecording(width, height)) - draw(this, this.layoutDirection, pictureCanvas, this.size) { - this@onDrawWithContent.drawContent() + val movableContent: MovableElementContent = + layoutImpl.movableContents[element] + ?: movableContentOf { + contentScope: MovableElementContentScope, + content: @Composable MovableElementContentScope.() -> Unit -> + contentScope.content() } - picture.endRecording() - - // Draw the content. - drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) } - } - } - ) { - element.movableContent { movableElementScope.content() } - } + .also { layoutImpl.movableContents[element] = it } + + // Important: Don't introduce any parent Box or other layout here, because contentScope + // delegates its BoxScope implementation to the Box where this content() function is + // called, so it's important that this movableContent is composed directly under that + // Box. + movableContent(contentScope, content) } else { - // If we are not composed, we draw the previous drawing commands at the same size as the - // movable content when it was composed in this scene. - val sceneValues = element.sceneValues.getValue(scene.key) - - Spacer( - Modifier.layout { measurable, _ -> - val size = - sceneValues.targetSize.takeIf { it != Element.SizeUnspecified } - ?: IntSize.Zero - val placeable = - measurable.measure(Constraints.fixed(size.width, size.height)) - layout(size.width, size.height) { placeable.place(0, 0) } - } - .drawBehind { - drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) } - } - ) + // If we are not composed, we still need to lay out an empty space with the same *target + // size* as its movable content, i.e. the same *size when idle*. During transitions, + // this size will be used to interpolate the transition size, during the intermediate + // layout pass. + Layout { _, _ -> + // No need to measure or place anything. + val size = + placeholderContentSize( + layoutImpl, + scene.key, + layoutImpl.elements.getValue(element), + ) + layout(size.width, size.height) {} + } } } } @@ -117,7 +167,7 @@ internal fun MovableElement( private fun shouldComposeMovableElement( layoutImpl: SceneTransitionLayoutImpl, scene: SceneKey, - element: Element, + element: ElementKey, ): Boolean { val transition = layoutImpl.state.currentTransition @@ -130,72 +180,55 @@ private fun shouldComposeMovableElement( val fromReady = layoutImpl.isSceneReady(fromScene) val toReady = layoutImpl.isSceneReady(toScene) - val otherScene = - when (scene) { - fromScene -> toScene - toScene -> fromScene - else -> - error( - "shouldComposeMovableElement(scene=$scene) called with fromScene=$fromScene " + - "and toScene=$toScene" - ) - } - - val isShared = otherScene in element.sceneValues - - if (isShared && !toReady && !fromReady) { - // This should usually not happen given that fromScene should be ready, but let's log a - // warning here in case it does so it helps debugging flicker issues caused by this part of - // the code. - Log.w( - TAG, - "MovableElement $element might have to be composed for the first time in both " + - "fromScene=$fromScene and toScene=$toScene. This will probably lead to a flicker " + - "where the size of the element will jump from IntSize.Zero to its actual size " + - "during the transition." - ) - } - - // Element is not shared in this transition. - if (!isShared) { - return true - } - - // toScene is not ready (because we are composing it for the first time), so we compose it there - // first. This is the most common scenario when starting a transition that has a shared movable - // element. - if (!toReady) { + if (!fromReady && !toReady) { + // Neither of the scenes will be drawn, so where we compose it doesn't really matter. Note + // that we could have slightly more complicated logic here to optimize for this case, but + // it's not worth it given that readyScenes should disappear soon (b/316901148). return scene == toScene } - // This should usually not happen, but if we are also composing for the first time in fromScene - // then we should compose it there only. - if (!fromReady) { - return scene == fromScene - } + // If one of the scenes is not ready, compose it in the other one to make sure it is drawn. + if (!fromReady) return scene == toScene + if (!toReady) return scene == fromScene + // Always compose movable elements in the scene picked by their scene picker. return shouldDrawOrComposeSharedElement( layoutImpl, transition, scene, - element.key, - sharedElementTransformation(layoutImpl.state, transition, element.key), + element, ) } -private class MovableElementScopeImpl( - private val layoutImpl: SceneTransitionLayoutImpl, - private val element: Element, - private val scene: Scene, -) : MovableElementScope { - @Composable - override fun <T> animateSharedValueAsState( - value: T, - debugName: String, - lerp: (start: T, stop: T, fraction: Float) -> T, - canOverflow: Boolean, - ): State<T> { - val key = remember { ValueKey(debugName) } - return animateSharedValueAsState(layoutImpl, scene, element, key, value, lerp, canOverflow) +/** + * Return the size of the placeholder/space that is composed when the movable content is not + * composed in a scene. + */ +private fun placeholderContentSize( + layoutImpl: SceneTransitionLayoutImpl, + scene: SceneKey, + element: Element, +): IntSize { + // If the content of the movable element was already composed in this scene before, use that + // target size. + val targetValueInScene = element.sceneStates.getValue(scene).targetSize + if (targetValueInScene != Element.SizeUnspecified) { + return targetValueInScene } + + // This code is only run during transitions (otherwise the content would be composed and the + // placeholder would not), so it's ok to cast the state into a Transition directly. + val transition = layoutImpl.state.transitionState as TransitionState.Transition + + // If the content was already composed in the other scene, we use that target size assuming it + // doesn't change between scenes. + // TODO(b/317026105): Provide a way to give a hint size/content for cases where this is not + // true. + val otherScene = if (transition.fromScene == scene) transition.toScene else transition.fromScene + val targetValueInOtherScene = element.sceneStates[otherScene]?.targetSize + if (targetValueInOtherScene != null && targetValueInOtherScene != Element.SizeUnspecified) { + return targetValueInOtherScene + } + + return IntSize.Zero } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt index 560e92becba5..454c0ecf8ac5 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt @@ -75,8 +75,8 @@ private class PunchHoleNode( if ( bounds == null || - bounds.lastSharedValues.size == Element.SizeUnspecified || - bounds.lastSharedValues.offset == Offset.Unspecified + bounds.lastSharedState.size == Element.SizeUnspecified || + bounds.lastSharedState.offset == Offset.Unspecified ) { drawContent() return @@ -87,14 +87,14 @@ private class PunchHoleNode( canvas.withSaveLayer(size.toRect(), Paint()) { drawContent() - val offset = bounds.lastSharedValues.offset - element.lastSharedValues.offset + val offset = bounds.lastSharedState.offset - element.lastSharedState.offset translate(offset.x, offset.y) { drawHole(bounds) } } } } private fun DrawScope.drawHole(bounds: Element) { - val boundsSize = bounds.lastSharedValues.size.toSize() + val boundsSize = bounds.lastSharedState.size.toSize() if (shape == RectangleShape) { drawRect(Color.Black, size = boundsSize, blendMode = BlendMode.DstOut) return diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt index 30e50a972230..3537b7989ed5 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt @@ -20,13 +20,10 @@ import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable -import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import androidx.compose.runtime.snapshots.Snapshot -import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape @@ -45,16 +42,13 @@ internal class Scene( actions: Map<UserAction, SceneKey>, zIndex: Float, ) { - private val scope = SceneScopeImpl(layoutImpl, this) + internal val scope = SceneScopeImpl(layoutImpl, this) var content by mutableStateOf(content) var userActions by mutableStateOf(actions) var zIndex by mutableFloatStateOf(zIndex) var targetSize by mutableStateOf(IntSize.Zero) - /** The shared values in this scene that are not tied to a specific element. */ - val sharedValues = SnapshotStateMap<ValueKey, Element.SharedValue<*>>() - @Composable @OptIn(ExperimentalComposeUiApi::class) fun Content(modifier: Modifier = Modifier) { @@ -77,7 +71,7 @@ internal class Scene( } } -private class SceneScopeImpl( +internal class SceneScopeImpl( private val layoutImpl: SceneTransitionLayoutImpl, private val scene: Scene, ) : SceneScope { @@ -87,6 +81,42 @@ private class SceneScopeImpl( return element(layoutImpl, scene, key) } + @Composable + override fun Element( + key: ElementKey, + modifier: Modifier, + content: @Composable (ElementScope<ElementContentScope>.() -> Unit) + ) { + Element(layoutImpl, scene, key, modifier, content) + } + + @Composable + override fun MovableElement( + key: ElementKey, + modifier: Modifier, + content: @Composable (ElementScope<MovableElementContentScope>.() -> Unit) + ) { + MovableElement(layoutImpl, scene, key, modifier, content) + } + + @Composable + override fun <T> animateSceneValueAsState( + value: T, + key: ValueKey, + lerp: (T, T, Float) -> T, + canOverflow: Boolean + ): AnimatedState<T> { + return animateSharedValueAsState( + layoutImpl = layoutImpl, + scene = scene.key, + element = null, + key = key, + value = value, + lerp = lerp, + canOverflow = canOverflow, + ) + } + override fun Modifier.horizontalNestedScrollToScene( leftBehavior: NestedScrollBehavior, rightBehavior: NestedScrollBehavior, @@ -109,45 +139,6 @@ private class SceneScopeImpl( bottomOrRightBehavior = bottomBehavior, ) - @Composable - override fun <T> animateSharedValueAsState( - value: T, - key: ValueKey, - element: ElementKey?, - lerp: (T, T, Float) -> T, - canOverflow: Boolean - ): State<T> { - val element = - element?.let { key -> - Snapshot.withoutReadObservation { - layoutImpl.elements[key] - ?: error( - "Element $key is not composed. Make sure to call " + - "animateSharedXAsState *after* Modifier.element(key)." - ) - } - } - - return animateSharedValueAsState( - layoutImpl, - scene, - element, - key, - value, - lerp, - canOverflow, - ) - } - - @Composable - override fun MovableElement( - key: ElementKey, - modifier: Modifier, - content: @Composable MovableElementScope.() -> Unit, - ) { - MovableElement(layoutImpl, scene, key, modifier, content) - } - override fun Modifier.punchHole( element: ElementKey, bounds: ElementKey, diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index 5eb339e4a5e4..84fade8937ff 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -22,9 +22,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect import androidx.compose.runtime.Stable -import androidx.compose.runtime.State import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.input.nestedscroll.NestedScrollConnection @@ -98,9 +98,9 @@ interface SceneTransitionLayoutScope { */ @DslMarker annotation class ElementDsl -@ElementDsl @Stable -interface SceneScope { +@ElementDsl +interface BaseSceneScope { /** The state of the [SceneTransitionLayout] in which this scene is contained. */ val layoutState: SceneTransitionLayoutState @@ -111,21 +111,74 @@ interface SceneScope { * that the element can be transformed and animated when the scene transitions in or out. * * Additionally, this [key] will be used to detect elements that are shared between scenes to - * automatically interpolate their size, offset and [shared values][animateSharedValueAsState]. + * automatically interpolate their size and offset. If you need to animate shared element values + * (i.e. values associated to this element that change depending on which scene it is composed + * in), use [Element] instead. * * Note that shared elements tagged using this function will be duplicated in each scene they * are part of, so any **internal** state (e.g. state created using `remember { * mutableStateOf(...) }`) will be lost. If you need to preserve internal state, you should use * [MovableElement] instead. * + * @see Element * @see MovableElement - * - * TODO(b/291566282): Migrate this to the new Modifier Node API and remove the @Composable - * constraint. */ fun Modifier.element(key: ElementKey): Modifier /** + * Create an element identified by [key]. + * + * Similar to [element], this creates an element that will be automatically shared when present + * in multiple scenes and that can be transformed during transitions, the same way that + * [element] does. + * + * The only difference with [element] is that the provided [ElementScope] allows you to + * [animate element values][ElementScope.animateElementValueAsState] or specify its + * [movable content][Element.movableContent] that will be "moved" and composed only once during + * transitions (as opposed to [element] that duplicates shared elements) so that any internal + * state is preserved during and after the transition. + * + * @see element + * @see MovableElement + */ + @Composable + fun Element( + key: ElementKey, + modifier: Modifier, + + // TODO(b/317026105): As discussed in http://shortn/_gJVdltF8Si, remove the @Composable + // scope here to make sure that callers specify the content in ElementScope.content {} or + // ElementScope.movableContent {}. + content: @Composable ElementScope<ElementContentScope>.() -> Unit, + ) + + /** + * Create a *movable* element identified by [key]. + * + * Similar to [Element], this creates an element that will be automatically shared when present + * in multiple scenes and that can be transformed during transitions, and you can also use the + * provided [ElementScope] to [animate element values][ElementScope.animateElementValueAsState]. + * + * The important difference with [element] and [Element] is that this element + * [content][ElementScope.content] will be "moved" and composed only once during transitions, as + * opposed to [element] and [Element] that duplicates shared elements, so that any internal + * state is preserved during and after the transition. + * + * @see element + * @see Element + */ + @Composable + fun MovableElement( + key: ElementKey, + modifier: Modifier, + + // TODO(b/317026105): As discussed in http://shortn/_gJVdltF8Si, remove the @Composable + // scope here to make sure that callers specify the content in ElementScope.content {} or + // ElementScope.movableContent {}. + content: @Composable ElementScope<MovableElementContentScope>.() -> Unit, + ) + + /** * Adds a [NestedScrollConnection] to intercept scroll events not handled by the scrollable * component. * @@ -150,82 +203,114 @@ interface SceneScope { ): Modifier /** - * Create a *movable* element identified by [key]. - * - * This creates an element that will be automatically shared when present in multiple scenes and - * that can be transformed during transitions, the same way that [element] does. The major - * difference with [element] is that elements created with [MovableElement] will be "moved" and - * composed only once during transitions (as opposed to [element] that duplicates shared - * elements) so that any internal state is preserved during and after the transition. + * Punch a hole in this [element] using the bounds of [bounds] in [scene] and the given [shape]. * - * @see element + * Punching a hole in an element will "remove" any pixel drawn by that element in the hole area. + * This can be used to make content drawn below an opaque element visible. For example, if we + * have [this lockscreen scene](http://shortn/_VYySFnJDhN) drawn below + * [this shade scene](http://shortn/_fpxGUk0Rg7) and punch a hole in the latter using the big + * clock time bounds and a RoundedCornerShape(10dp), [this](http://shortn/_qt80IvORFj) would be + * the result. */ - @Composable - fun MovableElement( - key: ElementKey, - modifier: Modifier, - content: @Composable MovableElementScope.() -> Unit, - ) + fun Modifier.punchHole(element: ElementKey, bounds: ElementKey, shape: Shape): Modifier + + /** + * Don't resize during transitions. This can for instance be used to make sure that scrollable + * lists keep a constant size during transitions even if its elements are growing/shrinking. + */ + fun Modifier.noResizeDuringTransitions(): Modifier +} +@Stable +@ElementDsl +interface SceneScope : BaseSceneScope { /** - * Animate some value of a shared element. + * Animate some value at the scene level. * * @param value the value of this shared value in the current scene. * @param key the key of this shared value. - * @param element the element associated with this value. If `null`, this value will be - * associated at the scene level, which means that [key] should be used maximum once in the - * same scene. * @param lerp the *linear* interpolation function that should be used to interpolate between * two different values. Note that it has to be linear because the [fraction] passed to this * interpolator is already interpolated. * @param canOverflow whether this value can overflow past the values it is interpolated * between, for instance because the transition is animated using a bouncy spring. - * @see animateSharedIntAsState - * @see animateSharedFloatAsState - * @see animateSharedDpAsState - * @see animateSharedColorAsState + * @see animateSceneIntAsState + * @see animateSceneFloatAsState + * @see animateSceneDpAsState + * @see animateSceneColorAsState */ @Composable - fun <T> animateSharedValueAsState( + fun <T> animateSceneValueAsState( value: T, key: ValueKey, - element: ElementKey?, lerp: (start: T, stop: T, fraction: Float) -> T, canOverflow: Boolean, - ): State<T> + ): AnimatedState<T> +} +@Stable +@ElementDsl +interface ElementScope<ContentScope> { /** - * Punch a hole in this [element] using the bounds of [bounds] in [scene] and the given [shape]. + * Animate some value associated to this element. * - * Punching a hole in an element will "remove" any pixel drawn by that element in the hole area. - * This can be used to make content drawn below an opaque element visible. For example, if we - * have [this lockscreen scene](http://shortn/_VYySFnJDhN) drawn below - * [this shade scene](http://shortn/_fpxGUk0Rg7) and punch a hole in the latter using the big - * clock time bounds and a RoundedCornerShape(10dp), [this](http://shortn/_qt80IvORFj) would be - * the result. + * @param value the value of this shared value in the current scene. + * @param key the key of this shared value. + * @param lerp the *linear* interpolation function that should be used to interpolate between + * two different values. Note that it has to be linear because the [fraction] passed to this + * interpolator is already interpolated. + * @param canOverflow whether this value can overflow past the values it is interpolated + * between, for instance because the transition is animated using a bouncy spring. + * @see animateElementIntAsState + * @see animateElementFloatAsState + * @see animateElementDpAsState + * @see animateElementColorAsState */ - fun Modifier.punchHole(element: ElementKey, bounds: ElementKey, shape: Shape): Modifier + @Composable + fun <T> animateElementValueAsState( + value: T, + key: ValueKey, + lerp: (start: T, stop: T, fraction: Float) -> T, + canOverflow: Boolean, + ): AnimatedState<T> /** - * Don't resize during transitions. This can for instance be used to make sure that scrollable - * lists keep a constant size during transitions even if its elements are growing/shrinking. + * The content of this element. + * + * Important: This must be called exactly once, after all calls to [animateElementValueAsState]. */ - fun Modifier.noResizeDuringTransitions(): Modifier + @Composable fun content(content: @Composable ContentScope.() -> Unit) } -// TODO(b/291053742): Add animateSharedValueAsState(targetValue) without any ValueKey and ElementKey -// arguments to allow sharing values inside a movable element. +/** + * The exact same scope as [androidx.compose.foundation.layout.BoxScope]. + * + * We can't reuse BoxScope directly because of the @LayoutScopeMarker annotation on it, which would + * prevent us from calling Modifier.element() and other methods of [SceneScope] inside any Box {} in + * the [content][ElementScope.content] of a [SceneScope.Element] or a [SceneScope.MovableElement]. + */ +@Stable @ElementDsl -interface MovableElementScope { - @Composable - fun <T> animateSharedValueAsState( - value: T, - debugName: String, - lerp: (start: T, stop: T, fraction: Float) -> T, - canOverflow: Boolean, - ): State<T> +interface ElementBoxScope { + /** @see [androidx.compose.foundation.layout.BoxScope.align]. */ + @Stable fun Modifier.align(alignment: Alignment): Modifier + + /** @see [androidx.compose.foundation.layout.BoxScope.matchParentSize]. */ + @Stable fun Modifier.matchParentSize(): Modifier } +/** The scope for "normal" (not movable) elements. */ +@Stable @ElementDsl interface ElementContentScope : SceneScope, ElementBoxScope + +/** + * The scope for the content of movable elements. + * + * Note that it extends [BaseSceneScope] and not [SceneScope] because movable elements should not + * call [SceneScope.animateSceneValueAsState], given that their content is not composed in all + * scenes. + */ +@Stable @ElementDsl interface MovableElementContentScope : BaseSceneScope, ElementBoxScope + /** An action performed by the user. */ sealed interface UserAction diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index 45e1a0fa8f77..0227aba94b53 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -36,6 +36,16 @@ import androidx.compose.ui.util.fastForEach import com.android.compose.ui.util.lerp import kotlinx.coroutines.CoroutineScope +/** + * The type for the content of movable elements. + * + * TODO(b/317972419): Revert back to make this movable content have a single @Composable lambda + * parameter. + */ +internal typealias MovableElementContent = + @Composable + (MovableElementContentScope, @Composable MovableElementContentScope.() -> Unit) -> Unit + @Stable internal class SceneTransitionLayoutImpl( internal val state: SceneTransitionLayoutStateImpl, @@ -56,16 +66,47 @@ internal class SceneTransitionLayoutImpl( /** * The map of [Element]s. * - * Note that this map is *mutated* directly during composition, so it is a [SnapshotStateMap] to - * make sure that mutations are reverted if composition is cancelled. + * Important: [Element]s from this map should never be accessed during composition because the + * Elements are added when the associated Modifier.element() node is attached to the Modifier + * tree, i.e. after composition. */ - internal val elements = SnapshotStateMap<ElementKey, Element>() + internal val elements = mutableMapOf<ElementKey, Element>() + + /** + * The map of contents of movable elements. + * + * Note that given that this map is mutated directly during a composition, it has to be a + * [SnapshotStateMap] to make sure that mutations are reverted if composition is cancelled. + */ + private var _movableContents: SnapshotStateMap<ElementKey, MovableElementContent>? = null + val movableContents: SnapshotStateMap<ElementKey, MovableElementContent> + get() = + _movableContents + ?: SnapshotStateMap<ElementKey, MovableElementContent>().also { + _movableContents = it + } + + /** + * The different values of a shared value keyed by a a [ValueKey] and the different elements and + * scenes it is associated to. + */ + private var _sharedValues: + MutableMap<ValueKey, MutableMap<ElementKey?, SnapshotStateMap<SceneKey, *>>>? = + null + internal val sharedValues: + MutableMap<ValueKey, MutableMap<ElementKey?, SnapshotStateMap<SceneKey, *>>> + get() = + _sharedValues + ?: mutableMapOf<ValueKey, MutableMap<ElementKey?, SnapshotStateMap<SceneKey, *>>>() + .also { _sharedValues = it } /** * The scenes that are "ready", i.e. they were composed and fully laid-out at least once. * * Note that this map is *read* during composition, so it is a [SnapshotStateMap] to make sure * that we recompose when modifications are made to this map. + * + * TODO(b/316901148): Remove this map. */ private val readyScenes = SnapshotStateMap<SceneKey, Boolean>() diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt index d1ba582d6c23..0607aa148157 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt @@ -92,6 +92,20 @@ sealed interface TransitionState { /** Whether user input is currently driving the transition. */ abstract val isUserInputOngoing: Boolean + + /** + * Whether we are transitioning. If [from] or [to] is empty, we will also check that they + * match the scenes we are animating from and/or to. + */ + fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean { + return (from == null || fromScene == from) && (to == null || toScene == to) + } + + /** Whether we are transitioning from [scene] to [other], or from [other] to [scene]. */ + fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean { + return isTransitioning(from = scene, to = other) || + isTransitioning(from = other, to = scene) + } } } @@ -111,13 +125,12 @@ internal class SceneTransitionLayoutStateImpl( override fun isTransitioning(from: SceneKey?, to: SceneKey?): Boolean { val transition = currentTransition ?: return false - return (from == null || transition.fromScene == from) && - (to == null || transition.toScene == to) + return transition.isTransitioning(from, to) } override fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean { - return isTransitioning(from = scene, to = other) || - isTransitioning(from = other, to = scene) + val transition = currentTransition ?: return false + return transition.isTransitioningBetween(scene, other) } /** Start a new [transition], instantly interrupting any ongoing transition if there was one. */ diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt index dfa2a9a18e91..dc8505c43889 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt @@ -119,14 +119,8 @@ interface TransitionBuilder : PropertyTransformationBuilder { * * @param enabled whether the matched element(s) should actually be shared in this transition. * Defaults to true. - * @param scenePicker the [SharedElementScenePicker] to use when deciding in which scene we - * should draw or compose this shared element. */ - fun sharedElement( - matcher: ElementMatcher, - enabled: Boolean = true, - scenePicker: SharedElementScenePicker = DefaultSharedElementScenePicker, - ) + fun sharedElement(matcher: ElementMatcher, enabled: Boolean = true) /** * Adds the transformations in [builder] but in reversed order. This allows you to partially @@ -136,44 +130,132 @@ interface TransitionBuilder : PropertyTransformationBuilder { fun reversed(builder: TransitionBuilder.() -> Unit) } -interface SharedElementScenePicker { +/** + * An interface to decide where we should draw shared Elements or compose MovableElements. + * + * @see DefaultElementScenePicker + * @see HighestZIndexScenePicker + * @see LowestZIndexScenePicker + * @see MovableElementScenePicker + */ +interface ElementScenePicker { /** * Return the scene in which [element] should be drawn (when using `Modifier.element(key)`) or - * composed (when using `MovableElement(key)`) during the transition from [fromScene] to - * [toScene]. + * composed (when using `MovableElement(key)`) during the given [transition]. + * + * Important: For [MovableElements][SceneScope.MovableElement], this scene picker will *always* + * be used during transitions to decide whether we should compose that element in a given scene + * or not. Therefore, you should make sure that the returned [SceneKey] contains the movable + * element, otherwise that element will not be composed in any scene during the transition. */ fun sceneDuringTransition( element: ElementKey, - fromScene: SceneKey, - toScene: SceneKey, - progress: () -> Float, + transition: TransitionState.Transition, fromSceneZIndex: Float, toSceneZIndex: Float, ): SceneKey + + /** + * Return [transition.fromScene] if it is in [scenes] and [transition.toScene] is not, or return + * [transition.toScene] if it is in [scenes] and [transition.fromScene] is not, otherwise throw + * an exception (i.e. if neither or both of fromScene and toScene are in [scenes]). + * + * This function can be useful when computing the scene in which a movable element should be + * composed. + */ + fun pickSingleSceneIn( + scenes: Set<SceneKey>, + transition: TransitionState.Transition, + element: ElementKey, + ): SceneKey { + val fromScene = transition.fromScene + val toScene = transition.toScene + val fromSceneInScenes = scenes.contains(fromScene) + val toSceneInScenes = scenes.contains(toScene) + if (fromSceneInScenes && toSceneInScenes) { + error( + "Element $element can be in both $fromScene and $toScene. You should add a " + + "special case for this transition before calling pickSingleSceneIn()." + ) + } + + if (!fromSceneInScenes && !toSceneInScenes) { + error( + "Element $element can be neither in $fromScene and $toScene. This either means " + + "that you should add one of them in the scenes set passed to " + + "pickSingleSceneIn(), or there is an internal error and this element was " + + "composed when it shouldn't be." + ) + } + + return if (fromSceneInScenes) { + fromScene + } else { + toScene + } + } } -object DefaultSharedElementScenePicker : SharedElementScenePicker { +/** An [ElementScenePicker] that draws/composes elements in the scene with the highest z-order. */ +object HighestZIndexScenePicker : ElementScenePicker { override fun sceneDuringTransition( element: ElementKey, - fromScene: SceneKey, - toScene: SceneKey, - progress: () -> Float, + transition: TransitionState.Transition, fromSceneZIndex: Float, toSceneZIndex: Float ): SceneKey { - // By default shared elements are drawn in the highest scene possible, unless it is a - // background. - return if ( - (fromSceneZIndex > toSceneZIndex && !element.isBackground) || - (fromSceneZIndex < toSceneZIndex && element.isBackground) - ) { - fromScene + return if (fromSceneZIndex > toSceneZIndex) { + transition.fromScene } else { - toScene + transition.toScene } } } +/** An [ElementScenePicker] that draws/composes elements in the scene with the lowest z-order. */ +object LowestZIndexScenePicker : ElementScenePicker { + override fun sceneDuringTransition( + element: ElementKey, + transition: TransitionState.Transition, + fromSceneZIndex: Float, + toSceneZIndex: Float + ): SceneKey { + return if (fromSceneZIndex < toSceneZIndex) { + transition.fromScene + } else { + transition.toScene + } + } +} + +/** + * An [ElementScenePicker] that draws/composes elements in the scene we are transitioning to, iff + * that scene is in [scenes]. + * + * This picker can be useful for movable elements whose content size depends on its content (because + * it wraps it) in at least one scene. That way, the target size of the MovableElement will be + * computed in the scene we are going to and, given that this element was probably already composed + * in the scene we are going from before starting the transition, the interpolated size of the + * movable element during the transition should be correct. + * + * The downside of this picker is that the zIndex of the element when going from scene A to scene B + * is not the same as when going from scene B to scene A, so it's not usable in situations where + * z-ordering during the transition matters. + */ +class MovableElementScenePicker(private val scenes: Set<SceneKey>) : ElementScenePicker { + override fun sceneDuringTransition( + element: ElementKey, + transition: TransitionState.Transition, + fromSceneZIndex: Float, + toSceneZIndex: Float, + ): SceneKey { + return if (scenes.contains(transition.toScene)) transition.toScene else transition.fromScene + } +} + +/** The default [ElementScenePicker]. */ +val DefaultElementScenePicker = HighestZIndexScenePicker + @TransitionDsl interface PropertyTransformationBuilder { /** diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt index 70468669297c..b96f9bebb08b 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt @@ -108,12 +108,8 @@ internal class TransitionBuilderImpl : TransitionBuilder { range = null } - override fun sharedElement( - matcher: ElementMatcher, - enabled: Boolean, - scenePicker: SharedElementScenePicker, - ) { - transformations.add(SharedElementTransformation(matcher, enabled, scenePicker)) + override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) { + transformations.add(SharedElementTransformation(matcher, enabled)) } override fun timestampRange( diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt index 40c814e0f25c..124ec290f42a 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt @@ -36,12 +36,12 @@ internal class AnchoredSize( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, transition: TransitionState.Transition, value: IntSize, ): IntSize { fun anchorSizeIn(scene: SceneKey): IntSize { - val size = layoutImpl.elements[anchor]?.sceneValues?.get(scene)?.targetSize + val size = layoutImpl.elements[anchor]?.sceneStates?.get(scene)?.targetSize return if (size != null && size != Element.SizeUnspecified) { IntSize( width = if (anchorWidth) size.width else value.width, diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt index a1d63193bc73..7aa702b0bbd2 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt @@ -35,13 +35,13 @@ internal class AnchoredTranslate( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, transition: TransitionState.Transition, value: Offset, ): Offset { val anchor = layoutImpl.elements[anchor] ?: return value fun anchorOffsetIn(scene: SceneKey): Offset? { - return anchor.sceneValues[scene]?.targetOffset?.takeIf { it.isSpecified } + return anchor.sceneStates[scene]?.targetOffset?.takeIf { it.isSpecified } } // [element] will move the same amount as [anchor] does. diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt index d1cf8ee6ad4a..6704a3bbeff2 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt @@ -39,7 +39,7 @@ internal class DrawScale( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, transition: TransitionState.Transition, value: Scale, ): Scale { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt index 70534dde4f6f..191a8fbcd009 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt @@ -34,12 +34,12 @@ internal class EdgeTranslate( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, transition: TransitionState.Transition, value: Offset ): Offset { val sceneSize = scene.targetSize - val elementSize = sceneValues.targetSize + val elementSize = sceneState.targetSize if (elementSize == Element.SizeUnspecified) { return value } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt index 17032dc288e0..41f626e24e79 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt @@ -30,7 +30,7 @@ internal class Fade( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, transition: TransitionState.Transition, value: Float ): Float { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt index 233ae597090b..f5207dc4d345 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt @@ -37,7 +37,7 @@ internal class ScaleSize( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, transition: TransitionState.Transition, value: IntSize, ): IntSize { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt index 0cd11b9914c9..04254fbb588b 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt @@ -20,7 +20,6 @@ import com.android.compose.animation.scene.Element import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.Scene import com.android.compose.animation.scene.SceneTransitionLayoutImpl -import com.android.compose.animation.scene.SharedElementScenePicker import com.android.compose.animation.scene.TransitionState /** A transformation applied to one or more elements during a transition. */ @@ -48,7 +47,6 @@ sealed interface Transformation { internal class SharedElementTransformation( override val matcher: ElementMatcher, internal val enabled: Boolean, - internal val scenePicker: SharedElementScenePicker, ) : Transformation /** A transformation that changes the value of an element property, like its size or offset. */ @@ -62,7 +60,7 @@ internal sealed interface PropertyTransformation<T> : Transformation { layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, transition: TransitionState.Transition, value: T, ): T diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt index 864b937a3fe0..04d5914bff69 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt @@ -35,7 +35,7 @@ internal class Translate( layoutImpl: SceneTransitionLayoutImpl, scene: Scene, element: Element, - sceneValues: Element.TargetValues, + sceneState: Element.SceneState, transition: TransitionState.Transition, value: Offset, ): Offset { diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt index 5473186c14ec..a116501a298c 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt @@ -18,10 +18,11 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween -import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.lerp @@ -32,6 +33,7 @@ import androidx.compose.ui.unit.lerp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.ui.util.lerp import com.google.common.truth.Truth.assertThat +import org.junit.Assert.assertThrows import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -62,17 +64,17 @@ class AnimatedSharedAsStateTest { onCurrentValueChanged: (Values) -> Unit, ) { val key = TestElements.Foo - Box(Modifier.element(key)) { - val int by animateSharedIntAsState(targetValues.int, TestValues.Value1, key) - val float by animateSharedFloatAsState(targetValues.float, TestValues.Value2, key) - val dp by animateSharedDpAsState(targetValues.dp, TestValues.Value3, key) - val color by - animateSharedColorAsState(targetValues.color, TestValues.Value4, element = null) + Element(key, Modifier) { + val int by animateElementIntAsState(targetValues.int, key = TestValues.Value1) + val float by animateElementFloatAsState(targetValues.float, key = TestValues.Value2) + val dp by animateElementDpAsState(targetValues.dp, key = TestValues.Value3) + val color by animateElementColorAsState(targetValues.color, key = TestValues.Value4) - // Make sure we read the values during composition, so that we recompose and call - // onCurrentValueChanged() with the latest values. - val currentValues = Values(int, float, dp, color) - SideEffect { onCurrentValueChanged(currentValues) } + content { + LaunchedEffect(Unit) { + snapshotFlow { Values(int, float, dp, color) }.collect(onCurrentValueChanged) + } + } } } @@ -83,30 +85,34 @@ class AnimatedSharedAsStateTest { ) { val key = TestElements.Foo MovableElement(key = key, Modifier) { - val int by - animateSharedIntAsState(targetValues.int, debugName = TestValues.Value1.debugName) - val float by - animateSharedFloatAsState( - targetValues.float, - debugName = TestValues.Value2.debugName - ) - val dp by - animateSharedDpAsState(targetValues.dp, debugName = TestValues.Value3.debugName) - val color by - animateSharedColorAsState( - targetValues.color, - debugName = TestValues.Value4.debugName - ) + val int by animateElementIntAsState(targetValues.int, key = TestValues.Value1) + val float by animateElementFloatAsState(targetValues.float, key = TestValues.Value2) + val dp by animateElementDpAsState(targetValues.dp, key = TestValues.Value3) + val color by animateElementColorAsState(targetValues.color, key = TestValues.Value4) + + LaunchedEffect(Unit) { + snapshotFlow { Values(int, float, dp, color) }.collect(onCurrentValueChanged) + } + } + } - // Make sure we read the values during composition, so that we recompose and call - // onCurrentValueChanged() with the latest values. - val currentValues = Values(int, float, dp, color) - SideEffect { onCurrentValueChanged(currentValues) } + @Composable + private fun SceneScope.SceneValues( + targetValues: Values, + onCurrentValueChanged: (Values) -> Unit, + ) { + val int by animateSceneIntAsState(targetValues.int, key = TestValues.Value1) + val float by animateSceneFloatAsState(targetValues.float, key = TestValues.Value2) + val dp by animateSceneDpAsState(targetValues.dp, key = TestValues.Value3) + val color by animateSceneColorAsState(targetValues.color, key = TestValues.Value4) + + LaunchedEffect(Unit) { + snapshotFlow { Values(int, float, dp, color) }.collect(onCurrentValueChanged) } } @Test - fun animateSharedValues() { + fun animateElementValues() { val fromValues = Values(int = 0, float = 0f, dp = 0.dp, color = Color.Red) val toValues = Values(int = 100, float = 100f, dp = 100.dp, color = Color.Blue) @@ -194,24 +200,183 @@ class AnimatedSharedAsStateTest { } at(16) { - // Given that we use MovableElement here, animateSharedXAsState is composed only - // once, in the highest scene (in this case, in toScene). - assertThat(lastValueInFrom).isEqualTo(fromValues) + assertThat(lastValueInFrom).isEqualTo(lerp(fromValues, toValues, fraction = 0.25f)) assertThat(lastValueInTo).isEqualTo(lerp(fromValues, toValues, fraction = 0.25f)) } at(32) { - assertThat(lastValueInFrom).isEqualTo(fromValues) + assertThat(lastValueInFrom).isEqualTo(lerp(fromValues, toValues, fraction = 0.5f)) assertThat(lastValueInTo).isEqualTo(lerp(fromValues, toValues, fraction = 0.5f)) } at(48) { - assertThat(lastValueInFrom).isEqualTo(fromValues) + assertThat(lastValueInFrom).isEqualTo(lerp(fromValues, toValues, fraction = 0.75f)) assertThat(lastValueInTo).isEqualTo(lerp(fromValues, toValues, fraction = 0.75f)) } after { + assertThat(lastValueInFrom).isEqualTo(toValues) + assertThat(lastValueInTo).isEqualTo(toValues) + } + } + } + + @Test + fun animateSceneValues() { + val fromValues = Values(int = 0, float = 0f, dp = 0.dp, color = Color.Red) + val toValues = Values(int = 100, float = 100f, dp = 100.dp, color = Color.Blue) + + var lastValueInFrom = fromValues + var lastValueInTo = toValues + + rule.testTransition( + fromSceneContent = { + SceneValues( + targetValues = fromValues, + onCurrentValueChanged = { lastValueInFrom = it } + ) + }, + toSceneContent = { + SceneValues(targetValues = toValues, onCurrentValueChanged = { lastValueInTo = it }) + }, + transition = { + // The transition lasts 64ms = 4 frames. + spec = tween(durationMillis = 16 * 4, easing = LinearEasing) + }, + fromScene = TestScenes.SceneA, + toScene = TestScenes.SceneB, + ) { + before { assertThat(lastValueInFrom).isEqualTo(fromValues) + + // to was not composed yet, so lastValueInTo was not set yet. + assertThat(lastValueInTo).isEqualTo(toValues) + } + + at(16) { + // Given that we use scene values here, animateSceneXAsState is composed in both + // scenes and values should be interpolated with the transition fraction. + val expectedValues = lerp(fromValues, toValues, fraction = 0.25f) + assertThat(lastValueInFrom).isEqualTo(expectedValues) + assertThat(lastValueInTo).isEqualTo(expectedValues) + } + + at(32) { + val expectedValues = lerp(fromValues, toValues, fraction = 0.5f) + assertThat(lastValueInFrom).isEqualTo(expectedValues) + assertThat(lastValueInTo).isEqualTo(expectedValues) + } + + at(48) { + val expectedValues = lerp(fromValues, toValues, fraction = 0.75f) + assertThat(lastValueInFrom).isEqualTo(expectedValues) + assertThat(lastValueInTo).isEqualTo(expectedValues) + } + + after { + assertThat(lastValueInFrom).isEqualTo(toValues) + assertThat(lastValueInTo).isEqualTo(toValues) + } + } + } + + @Test + fun readingAnimatedStateValueDuringCompositionThrows() { + assertThrows(IllegalStateException::class.java) { + rule.testTransition( + fromSceneContent = { animateSceneIntAsState(0, TestValues.Value1).value }, + toSceneContent = {}, + transition = {}, + ) {} + } + } + + @Test + fun readingAnimatedStateValueDuringCompositionIsStillPossible() { + @Composable + fun SceneScope.SceneValuesDuringComposition( + targetValues: Values, + onCurrentValueChanged: (Values) -> Unit, + ) { + val int by + animateSceneIntAsState(targetValues.int, key = TestValues.Value1) + .unsafeCompositionState(targetValues.int) + val float by + animateSceneFloatAsState(targetValues.float, key = TestValues.Value2) + .unsafeCompositionState(targetValues.float) + val dp by + animateSceneDpAsState(targetValues.dp, key = TestValues.Value3) + .unsafeCompositionState(targetValues.dp) + val color by + animateSceneColorAsState(targetValues.color, key = TestValues.Value4) + .unsafeCompositionState(targetValues.color) + + val values = Values(int, float, dp, color) + SideEffect { onCurrentValueChanged(values) } + } + + val fromValues = Values(int = 0, float = 0f, dp = 0.dp, color = Color.Red) + val toValues = Values(int = 100, float = 100f, dp = 100.dp, color = Color.Blue) + + var lastValueInFrom = fromValues + var lastValueInTo = toValues + + rule.testTransition( + fromSceneContent = { + SceneValuesDuringComposition( + targetValues = fromValues, + onCurrentValueChanged = { lastValueInFrom = it }, + ) + }, + toSceneContent = { + SceneValuesDuringComposition( + targetValues = toValues, + onCurrentValueChanged = { lastValueInTo = it }, + ) + }, + transition = { + // The transition lasts 64ms = 4 frames. + spec = tween(durationMillis = 16 * 4, easing = LinearEasing) + }, + ) { + before { + assertThat(lastValueInFrom).isEqualTo(fromValues) + + // to was not composed yet, so lastValueInTo was not set yet. + assertThat(lastValueInTo).isEqualTo(toValues) + } + + at(16) { + // Because we are using unsafeCompositionState(), values are one frame behind their + // expected progress so at this first frame we are at progress = 0% instead of 25%. + val expectedValues = lerp(fromValues, toValues, fraction = 0f) + assertThat(lastValueInFrom).isEqualTo(expectedValues) + assertThat(lastValueInTo).isEqualTo(expectedValues) + } + + at(32) { + // One frame behind, so 25% instead of 50%. + val expectedValues = lerp(fromValues, toValues, fraction = 0.25f) + assertThat(lastValueInFrom).isEqualTo(expectedValues) + assertThat(lastValueInTo).isEqualTo(expectedValues) + } + + at(48) { + // One frame behind, so 50% instead of 75%. + val expectedValues = lerp(fromValues, toValues, fraction = 0.5f) + assertThat(lastValueInFrom).isEqualTo(expectedValues) + assertThat(lastValueInTo).isEqualTo(expectedValues) + } + + after { + // from should have been last composed at progress = 100% before it is removed from + // composition, but given that we are one frame behind the last values are stuck at + // 75%. + assertThat(lastValueInFrom).isEqualTo(lerp(fromValues, toValues, fraction = 0.75f)) + + // The after {} block resumes the clock and will run as many frames as necessary so + // that the application is idle, so the toScene settle to the idle state and to the + // final values. assertThat(lastValueInTo).isEqualTo(toValues) } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementScenePickerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementScenePickerTest.kt new file mode 100644 index 000000000000..3b022e8adc72 --- /dev/null +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementScenePickerTest.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. + */ + +package com.android.compose.animation.scene + +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.unit.dp +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ElementScenePickerTest { + @get:Rule val rule = createComposeRule() + + @Test + fun highestZIndexPicker() { + val key = ElementKey("TestElement", scenePicker = HighestZIndexScenePicker) + rule.testTransition( + fromSceneContent = { Box(Modifier.element(key).size(10.dp)) }, + toSceneContent = { Box(Modifier.element(key).size(10.dp)) }, + transition = { spec = tween(4 * 16, easing = LinearEasing) }, + fromScene = TestScenes.SceneA, + toScene = TestScenes.SceneB, + ) { + before { + onElement(key, TestScenes.SceneA).assertIsDisplayed() + onElement(key, TestScenes.SceneB).assertDoesNotExist() + } + at(32) { + // Scene B has the highest index, so the element is placed only there. + onElement(key, TestScenes.SceneA).assertExists().assertIsNotDisplayed() + onElement(key, TestScenes.SceneB).assertIsDisplayed() + } + after { + onElement(key, TestScenes.SceneA).assertDoesNotExist() + onElement(key, TestScenes.SceneB).assertIsDisplayed() + } + } + } + + @Test + fun lowestZIndexPicker() { + val key = ElementKey("TestElement", scenePicker = LowestZIndexScenePicker) + rule.testTransition( + fromSceneContent = { Box(Modifier.element(key).size(10.dp)) }, + toSceneContent = { Box(Modifier.element(key).size(10.dp)) }, + transition = { spec = tween(4 * 16, easing = LinearEasing) }, + fromScene = TestScenes.SceneA, + toScene = TestScenes.SceneB, + ) { + before { + onElement(key, TestScenes.SceneA).assertIsDisplayed() + onElement(key, TestScenes.SceneB).assertDoesNotExist() + } + at(32) { + // Scene A has the lowest index, so the element is placed only there. + onElement(key, TestScenes.SceneA).assertIsDisplayed() + onElement(key, TestScenes.SceneB).assertExists().assertIsNotDisplayed() + } + after { + onElement(key, TestScenes.SceneA).assertDoesNotExist() + onElement(key, TestScenes.SceneB).assertIsDisplayed() + } + } + } +} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt index da5a0a04ed63..54c5de710f77 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt @@ -306,7 +306,7 @@ class ElementTest { assertThat(layoutImpl.elements.keys).containsExactly(key) val element = layoutImpl.elements.getValue(key) - assertThat(element.sceneValues.keys).containsExactly(TestScenes.SceneB) + assertThat(element.sceneStates.keys).containsExactly(TestScenes.SceneB) // Scene C, state 0: the same element is reused. currentScene = TestScenes.SceneC @@ -315,7 +315,7 @@ class ElementTest { assertThat(layoutImpl.elements.keys).containsExactly(key) assertThat(layoutImpl.elements.getValue(key)).isSameInstanceAs(element) - assertThat(element.sceneValues.keys).containsExactly(TestScenes.SceneC) + assertThat(element.sceneStates.keys).containsExactly(TestScenes.SceneC) // Scene C, state 1: the same element is reused. sceneCState = 1 @@ -323,7 +323,7 @@ class ElementTest { assertThat(layoutImpl.elements.keys).containsExactly(key) assertThat(layoutImpl.elements.getValue(key)).isSameInstanceAs(element) - assertThat(element.sceneValues.keys).containsExactly(TestScenes.SceneC) + assertThat(element.sceneStates.keys).containsExactly(TestScenes.SceneC) // Scene D, state 0: the same element is reused. currentScene = TestScenes.SceneD @@ -332,7 +332,7 @@ class ElementTest { assertThat(layoutImpl.elements.keys).containsExactly(key) assertThat(layoutImpl.elements.getValue(key)).isSameInstanceAs(element) - assertThat(element.sceneValues.keys).containsExactly(TestScenes.SceneD) + assertThat(element.sceneStates.keys).containsExactly(TestScenes.SceneD) // Scene D, state 1: the same element is reused. sceneDState = 1 @@ -340,13 +340,13 @@ class ElementTest { assertThat(layoutImpl.elements.keys).containsExactly(key) assertThat(layoutImpl.elements.getValue(key)).isSameInstanceAs(element) - assertThat(element.sceneValues.keys).containsExactly(TestScenes.SceneD) + assertThat(element.sceneStates.keys).containsExactly(TestScenes.SceneD) // Scene D, state 2: the element is removed from the map. sceneDState = 2 rule.waitForIdle() - assertThat(element.sceneValues).isEmpty() + assertThat(element.sceneStates).isEmpty() assertThat(layoutImpl.elements).isEmpty() } @@ -442,7 +442,7 @@ class ElementTest { // There is only Foo in the elements map. assertThat(layoutImpl.elements.keys).containsExactly(TestElements.Foo) val fooElement = layoutImpl.elements.getValue(TestElements.Foo) - assertThat(fooElement.sceneValues.keys).containsExactly(TestScenes.SceneA) + assertThat(fooElement.sceneStates.keys).containsExactly(TestScenes.SceneA) key = TestElements.Bar @@ -450,8 +450,8 @@ class ElementTest { rule.waitForIdle() assertThat(layoutImpl.elements.keys).containsExactly(TestElements.Bar) val barElement = layoutImpl.elements.getValue(TestElements.Bar) - assertThat(barElement.sceneValues.keys).containsExactly(TestScenes.SceneA) - assertThat(fooElement.sceneValues).isEmpty() + assertThat(barElement.sceneStates.keys).containsExactly(TestScenes.SceneA) + assertThat(fooElement.sceneStates).isEmpty() } @Test @@ -505,7 +505,7 @@ class ElementTest { // There is only Foo in the elements map. assertThat(layoutImpl.elements.keys).containsExactly(TestElements.Foo) val element = layoutImpl.elements.getValue(TestElements.Foo) - val sceneValues = element.sceneValues + val sceneValues = element.sceneStates assertThat(sceneValues.keys).containsExactly(TestScenes.SceneA) // Get the ElementModifier node that should be reused later on when coming back to this @@ -528,7 +528,7 @@ class ElementTest { assertThat(layoutImpl.elements.keys).containsExactly(TestElements.Foo) val newElement = layoutImpl.elements.getValue(TestElements.Foo) - val newSceneValues = newElement.sceneValues + val newSceneValues = newElement.sceneStates assertThat(newElement).isNotEqualTo(element) assertThat(newSceneValues).isNotEqualTo(sceneValues) assertThat(newSceneValues.keys).containsExactly(TestScenes.SceneA) @@ -579,11 +579,11 @@ class ElementTest { fun foo() = layoutImpl().elements[TestElements.Foo] ?: error("Foo not in elements map") - fun Element.lastSharedOffset() = lastSharedValues.offset.toDpOffset() + fun Element.lastSharedOffset() = lastSharedState.offset.toDpOffset() fun Element.lastOffsetIn(scene: SceneKey) = - (sceneValues[scene] ?: error("$scene not in sceneValues map")) - .lastValues + (sceneStates[scene] ?: error("$scene not in sceneValues map")) + .lastState .offset .toDpOffset() diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementScenePickerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementScenePickerTest.kt new file mode 100644 index 000000000000..fb46a34e3cab --- /dev/null +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementScenePickerTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.compose.animation.scene + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class MovableElementScenePickerTest { + @Test + fun toSceneInScenes() { + val picker = MovableElementScenePicker(scenes = setOf(TestScenes.SceneA, TestScenes.SceneB)) + assertThat( + picker.sceneDuringTransition( + TestElements.Foo, + transition(from = TestScenes.SceneA, to = TestScenes.SceneB), + fromSceneZIndex = 0f, + toSceneZIndex = 1f, + ) + ) + .isEqualTo(TestScenes.SceneB) + } + + @Test + fun toSceneNotInScenes() { + val picker = MovableElementScenePicker(scenes = emptySet()) + assertThat( + picker.sceneDuringTransition( + TestElements.Foo, + transition(from = TestScenes.SceneA, to = TestScenes.SceneB), + fromSceneZIndex = 0f, + toSceneZIndex = 1f, + ) + ) + .isEqualTo(TestScenes.SceneA) + } +} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt index 3cd65cde274e..35cb691e6e37 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt @@ -28,19 +28,24 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsNotDisplayed +import androidx.compose.ui.test.assertPositionInRootIsEqualTo import androidx.compose.ui.test.hasParent import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onAllNodesWithText +import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.test.assertSizeIsEqualTo import com.google.common.truth.Truth.assertThat +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -58,7 +63,7 @@ class MovableElementTest { @Composable private fun SceneScope.MovableCounter(key: ElementKey, modifier: Modifier) { - MovableElement(key, modifier) { Counter() } + MovableElement(key, modifier) { content { Counter() } } } @Test @@ -142,39 +147,37 @@ class MovableElementTest { @Test fun movableElementIsMovedAndComposedOnlyOnce() { - rule.testTransition( - fromSceneContent = { MovableCounter(TestElements.Foo, Modifier.size(50.dp)) }, - toSceneContent = { MovableCounter(TestElements.Foo, Modifier.size(100.dp)) }, - transition = { - spec = tween(durationMillis = 16 * 4, easing = LinearEasing) - sharedElement( - TestElements.Foo, - scenePicker = - object : SharedElementScenePicker { - override fun sceneDuringTransition( - element: ElementKey, - fromScene: SceneKey, - toScene: SceneKey, - progress: () -> Float, - fromSceneZIndex: Float, - toSceneZIndex: Float - ): SceneKey { - assertThat(fromScene).isEqualTo(TestScenes.SceneA) - assertThat(toScene).isEqualTo(TestScenes.SceneB) - assertThat(fromSceneZIndex).isEqualTo(0) - assertThat(toSceneZIndex).isEqualTo(1) + val key = + ElementKey( + "Foo", + scenePicker = + object : ElementScenePicker { + override fun sceneDuringTransition( + element: ElementKey, + transition: TransitionState.Transition, + fromSceneZIndex: Float, + toSceneZIndex: Float + ): SceneKey { + assertThat(transition.fromScene).isEqualTo(TestScenes.SceneA) + assertThat(transition.toScene).isEqualTo(TestScenes.SceneB) + assertThat(fromSceneZIndex).isEqualTo(0) + assertThat(toSceneZIndex).isEqualTo(1) - // Compose Foo in Scene A if progress < 0.65f, otherwise compose it - // in Scene B. - return if (progress() < 0.65f) { - TestScenes.SceneA - } else { - TestScenes.SceneB - } + // Compose Foo in Scene A if progress < 0.65f, otherwise compose it + // in Scene B. + return if (transition.progress < 0.65f) { + TestScenes.SceneA + } else { + TestScenes.SceneB } } - ) - }, + } + ) + + rule.testTransition( + fromSceneContent = { MovableCounter(key, Modifier.size(50.dp)) }, + toSceneContent = { MovableCounter(key, Modifier.size(100.dp)) }, + transition = { spec = tween(durationMillis = 16 * 4, easing = LinearEasing) }, fromScene = TestScenes.SceneA, toScene = TestScenes.SceneB, ) { @@ -257,4 +260,73 @@ class MovableElementTest { } } } + + @Test + @Ignore("b/317972419#comment2") + fun movableElementContentIsRecomposedIfContentParametersChange() { + @Composable + fun SceneScope.MovableFoo(text: String, modifier: Modifier = Modifier) { + MovableElement(TestElements.Foo, modifier) { content { Text(text) } } + } + + rule.testTransition( + fromSceneContent = { MovableFoo(text = "fromScene") }, + toSceneContent = { MovableFoo(text = "toScene") }, + transition = { spec = tween(durationMillis = 16 * 4, easing = LinearEasing) }, + fromScene = TestScenes.SceneA, + toScene = TestScenes.SceneB, + ) { + // Before the transition, only fromScene is composed. + before { + rule.onNodeWithText("fromScene").assertIsDisplayed() + rule.onNodeWithText("toScene").assertDoesNotExist() + } + + // During the transition, the element is composed in toScene. + at(32) { + rule.onNodeWithText("fromScene").assertDoesNotExist() + rule.onNodeWithText("toScene").assertIsDisplayed() + } + + // At the end of the transition, the element is composed in toScene. + after { + rule.onNodeWithText("fromScene").assertDoesNotExist() + rule.onNodeWithText("toScene").assertIsDisplayed() + } + } + } + + @Test + fun elementScopeExtendsBoxScope() { + rule.setContent { + TestSceneScope { + Element(TestElements.Foo, Modifier.size(200.dp)) { + content { + Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd)) + Box(Modifier.testTag("matchParentSize").matchParentSize()) + } + } + } + } + + rule.onNodeWithTag("bottomEnd").assertPositionInRootIsEqualTo(200.dp, 200.dp) + rule.onNodeWithTag("matchParentSize").assertSizeIsEqualTo(200.dp, 200.dp) + } + + @Test + fun movableElementScopeExtendsBoxScope() { + rule.setContent { + TestSceneScope { + MovableElement(TestElements.Foo, Modifier.size(200.dp)) { + content { + Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd)) + Box(Modifier.testTag("matchParentSize").matchParentSize()) + } + } + } + } + + rule.onNodeWithTag("bottomEnd").assertPositionInRootIsEqualTo(200.dp, 200.dp) + rule.onNodeWithTag("matchParentSize").assertSizeIsEqualTo(200.dp, 200.dp) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt index c5b8d9ae0d10..75dee47a91cd 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt @@ -50,13 +50,4 @@ class SceneTransitionLayoutStateTest { assertThat(state.isTransitioning(to = TestScenes.SceneA)).isFalse() assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue() } - - private fun transition(from: SceneKey, to: SceneKey): TransitionState.Transition { - return object : TransitionState.Transition(from, to) { - override val currentScene: SceneKey = from - override val progress: Float = 0f - override val isInitiatedByUserInput: Boolean = false - override val isUserInputOngoing: Boolean = false - } - } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt index ebbd5006be55..649e4991434e 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt @@ -113,25 +113,21 @@ class SceneTransitionLayoutTest { @Composable private fun SceneScope.SharedFoo(size: Dp, childOffset: Dp, modifier: Modifier = Modifier) { - Box( - modifier - .size(size) - .background(Color.Red) - .element(TestElements.Foo) - .testTag(TestElements.Foo.debugName) - ) { + Element(TestElements.Foo, modifier.size(size).background(Color.Red)) { // Offset the single child of Foo by some animated shared offset. - val offset by animateSharedDpAsState(childOffset, TestValues.Value1, TestElements.Foo) - - Box( - Modifier.offset { - val pxOffset = offset.roundToPx() - IntOffset(pxOffset, pxOffset) - } - .size(30.dp) - .background(Color.Blue) - .testTag(TestElements.Bar.debugName) - ) + val offset by animateElementDpAsState(childOffset, TestValues.Value1) + + content { + Box( + Modifier.offset { + val pxOffset = offset.roundToPx() + IntOffset(pxOffset, pxOffset) + } + .size(30.dp) + .background(Color.Blue) + .testTag(TestElements.Bar.debugName) + ) + } } } diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt new file mode 100644 index 000000000000..238b21e1ea37 --- /dev/null +++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.compose.animation.scene + +/** A utility to easily create a [TransitionState.Transition] in tests. */ +fun transition( + from: SceneKey, + to: SceneKey, + progress: () -> Float = { 0f }, + isInitiatedByUserInput: Boolean = false, + isUserInputOngoing: Boolean = false, +): TransitionState.Transition { + return object : TransitionState.Transition(from, to) { + override val currentScene: SceneKey = from + override val progress: Float = progress() + override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput + override val isUserInputOngoing: Boolean = isUserInputOngoing + } +} diff --git a/packages/SystemUI/docs/imgs/ribbon.png b/packages/SystemUI/docs/imgs/ribbon.png Binary files differnew file mode 100644 index 000000000000..9f5765232aed --- /dev/null +++ b/packages/SystemUI/docs/imgs/ribbon.png diff --git a/packages/SystemUI/docs/scene.md b/packages/SystemUI/docs/scene.md new file mode 100644 index 000000000000..3e4a1b4a05c7 --- /dev/null +++ b/packages/SystemUI/docs/scene.md @@ -0,0 +1,297 @@ +# The Scene Framework + +Known internally as "Flexiglass", this framework defines a graph where each node +is a "scene" and each edge between the scenes is a transition. The scenes are +the main components of System UI, on phones these are: the lockscreen, bouncer, +shade, and quick settings panels/views/screens). Each scene is a standalone +experience. + +The **main goal** of the framework is to increase code health by applying +[Separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) +over several dimensions: + +1. Each scene is a standalone piece of UI; their code doesn't need to concern + itself with either transition animations or anything in other scenes. This + frees the developer to be able to focus only on the content of the UI for + that scene. +2. Transition definitions (which scene leads to which other scene following + which user action) are pulled out and separated from the content of the UI. +3. Transition animations (the effects that happen alongside the gradual change + from one scene to another) are also pulled out and separated from the + content of the UI. + +In addition to the above, some of the **secondary goals** are: 4. Make +**customization easier**: by separating scenes to standalone pieces, it becomes +possible for variant owners and OEMs to exclude or replace certain scenes or to +add brand-new scenes. 5. **Enable modularization**: by separating scenes to +standalone pieces, it becomes possible to break down System UI into smaller +codebases, each one of which could be built on its own. Note: this isn't part of +the scene framework itself but is something that can be done more easily once +the scene framework is in place. + +## Terminology + +* **Scene** a collection of UI elements in a layout that, together, make up a + "screen" or "page" that is as large as the container. Scenes can be + navigated between / transition to/from. To learn more, please see + [this section](#Defining-a-scene). +* **Element** (or "UI element") a single unit of UI within a scene. One scene + can arrange multiple elements within a layout structure. +* **Transition** the gradual switching from one scene to another scene. There + are two kinds: [user-driven](Scene-navigation) and + [automatic](Automatic-scene-transitions) scene transitions. +* **Transition animation** the set of UI effects that occurs while/during a + transition. These can apply to the entire scene or to specific elements in + the scene. To learn more, please see + [this section](#Scene-transition-animations). +* **Scene container** (or just "container") the root piece of UI (typically a + `@Composable` function) that sets up all the scenes, their transitions, etc. + To learn more, please see [this section](#Scene-container). +* **Container configuration** (or just "configuration") the collection of + scenes and some added information about the desired behaviour of a + container. To learn more, please see + [this section](#Scene-container-configuration). + +## Enabling the framework + +As of the end of 2023, the scene framework is under development; as such, it is +disabled by default. For those who are interested in a preview, please follow +the instructions below to turn it on. + +NOTE: in case these instructions become stale and don't actually enable the +framework, please make sure `SceneContainerFlag.isEnabled` in the +[`SceneContainerFlags.kt`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt) +file evalutes to `true`. + +1. Set **`SCENE_CONTAINER_ENABLED`** to `true` in the + [`Flags.kt`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/flags/Flags.kt) + file +2. Set the **`migrate_keyguard_status_bar_view`** classic flag to `true` by + running: `console $ adb shell statusbar cmd migrate_keyguard_status_bar_view + true` +3. Set a collection of **aconfig flags** to `true` by running the following + commands: `console $ adb shell device_config put systemui + com.android.systemui.scene_container true $ adb shell device_config put + systemui com.android.systemui.keyguard_bottom_area_refactor true $ adb shell + device_config put systemui + com.android.systemui.keyguard_shade_migration_nssl true $ adb shell + device_config put systemui com.android.systemui.media_in_scene_container + true` +4. **Restart** System UI by issuing the following command: `console $ adb shell + am crash com.android.systemui` +5. **Verify** that the scene framework was turned on. There are two ways to do + this: + + *(a)* look for the sash/ribbon UI at the bottom-right corner of the display: +  + + NOTE: this will be removed proper to the actual release of the framework. + + *(b)* Turn on logging and look for the logging statements in `logcat`: + ```console + + # Turn on logging from the framework: + + $ adb shell cmd statusbar echo -b SceneFramework:verbose + +# Look for the log statements from the framework: + +$ adb logcat -v time SceneFramework:* *:S ``` + +To **disable** the framework, simply turn off the main aconfig flag: `console $ +adb shell device_config put systemui com.android.systemui.scene_container false` + +## Defining a scene + +Each scene is defined as an implementation of the +[`ComposableScene`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt) +interface, which has three parts: 1. The `key` property returns the +[`SceneKey`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneKey.kt) +that uniquely identifies that scene 2. The `destinationScenes` `Flow` returns +the (potentially ever-changing) set of navigation edges to other scenes, based +on user-actions, which is how the navigation graph is defined (see +[the Scene navigation](#Scene-navigation) section for more) 3. The `Content` +function which uses +[Jetpack Compose](https://developer.android.com/jetpack/compose) to declare of +the UI itself. This is the UI "at rest", e.g. once there is no transition +between any two scenes. The Scene Framework has other ways to define how the +content of your UI changes with and throughout a transition to learn more please +see the [Scene transition animations](#Scene-transition-animations) section + +For example: ```kotlin @SysUISingleton class YourScene @Inject constructor( // +your dependencies here ) : ComposableScene { override val key = +SceneKey.YourScene + +``` +override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> = + MutableStateFlow<Map<UserAction, SceneModel>>( + mapOf( + // This is where scene navigation is defined, more on that below. + ) + ).asStateFlow() + +@Composable +override fun SceneScope.Content( + modifier: Modifier, +) { + // This is where the UI is defined using Jetpack Compose. +} +``` + +} ``` + +### Injecting scenes + +Scenes are injected into the Dagger dependency graph from the +[`SceneModule`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt;l=35-50;drc=564f233d5b597aedf06961c76e582464eebe8ba6). + +## Scene navigation + +As seen above, each scene is responsible for providing an observable `Flow` of a +`Map` that connects `UserAction` (for example: swipe down, swipe up, back +button/gesture, etc.) keys to `SceneModel` destinations. This is how the scene +navigation graph is defined. + +NOTE: this controls *only* user-input based navigation. To learn about the other +type of scene navigation, please see the +[Automatic scene transitions](#Automatic-scene-transitions) section. + +Because this is a `Flow`, scene implemetations should feel free to emit new +values over time. For example, the `Lockscreen` scene ties the "swipe up" user +action to go to the `Bouncer` scene if the device is still locked or to go to +the `Gone` scene if the device is unlocked, allowing the user to dismiss the +lockscreen UI when not locked. + +## Scene transition animations + +The Scene Framework separates transition animations from content UI declaration +by placing the definition of the former in a different location. This way, +there's no longer a need to contaminate the content UI declaration with +animation logic, a practice that becomes unscalable over time. + +Under the hood, the Scene Framework uses +[`SceneTransitionLayout`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt), +a `@Composable` function designed with scene graph and transitions in mind. In +fact, the Scene Framework is merely a shallow wrapper around +`SceneTransitionLayout`. + +The `SceneTransitionLayout` API requires the transitions to be passed-in +separately from the scenes themselves. In System UI, the transitions can be +found in +[`SceneContainerTransitions`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt). +As you can see, each possible scene-to-scene transition has its own builder, +here's one example: + +```kotlin +fun TransitionBuilder.lockscreenToShadeTransition() { + spec = tween(durationMillis = 500) + + punchHole(Shade.Elements.QuickSettings, bounds = Shade.Elements.Scrim, Shade.Shapes.Scrim) + translate(Shade.Elements.Scrim, Edge.Top, startsOutsideLayoutBounds = false) + fractionRange(end = 0.5f) { + fade(Shade.Elements.ScrimBackground) + translate( + QuickSettings.Elements.CollapsedGrid, + Edge.Top, + startsOutsideLayoutBounds = false, + ) + } + fractionRange(start = 0.5f) { fade(Notifications.Elements.Notifications) } +} +``` + +Going through the example code: * The `spec` is the animation that should be +invoked, in the example above, we use a `tween` animation with a duration of 500 +milliseconds * Then there's a series of function calls: `punchHole` applies a +clip mask to the `Scrim` element in the destination scene (in this case it's the +`Shade` scene) which has the position and size determined by the `bounds` +parameter and the shape passed into the `shape` parameter. This lets the +`Lockscreen` scene render "through" the `Shade` scene * The `translate` call +shifts the `Scrim` element to/from the `Top` edge of the scene container * The +first `fractionRange` wrapper tells the system to apply its contained functions +only during the first half of the transition. Inside of it, we see a `fade` of +the `ScrimBackground` element and a `translate` o the `CollpasedGrid` element +to/from the `Top` edge * The second `fractionRange` only starts at the second +half of the transition (e.g. when the previous one ends) and applies a `fade` on +the `Notifications` element + +You can find the actual documentation for this API +[here](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt). + +### Tagging elements + +As demonstrated above, elements within a scene can be addressed from transition +defintions. In order to "tag" an element with a specific `ElementKey`, the +[`element` modifier](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt) +must be used on the composable that declared that element's UI: + +```kotlin +Text( + text = "Some text", + modifier = Modifier.element(MyElements.SomeText), +) +``` + +In addition to the ability to refer to a tagged element in transition +definitions, if the same `ElementKey` is used for one element in the current +scene and another element in the destination scene, the element is considered to +be a **shared element**. As such, the framework automatically translates and +scales the bounds of the shared element from its current bounds in the source +scene to its final bounds in the destination scene. + +## Scene container + +To set up a scene framework instance, a scene container must be declared. This +is the root of an entire scene graph that puts together the scenes, their +transitions, and the configuration. The container is then added to a parent +`@Composable` or `View` so it can be displayed. + +The default scene container in System UI is defined in the +[`SceneContainer.kt` file](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt). + +### Scene container configuration + +The `SceneContainer` function is passed a few parameters including a view-model +and a set of scenes. The exact details of what gets passed in depends on the +[`SceneContainerConfig` object](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt) +which is injected into the Dagger dependency graph +[here](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt). + +## Automatic scene transitions + +The scene framework supports the ability for scenes to change automatically +based on device state or events other than direct user input. For example: when +the device is locked, there's an automatic scene transition to the `Lockscreen` +scene. + +This logic is contained within the +[`SceneContainerStartable`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt) +class. + +## Side-effects + +Similarly to [the above](#Automatic-scene-transitions), the +`SceneContainerStartable` also handles side-effects by updating other parts of +the System UI codebase whenever internal scene framework state changes. As an +example: the visibility of the `View` that contains our +[scene container](#Scene-container) is updated every time there's a transition +to or from the `Gone` scene. + +## Observing scene transition state + +There are a couple of ways to observe the transition state: + +1. [Easiest] using the `SceneScope` of the scene container, simply use the + `animateSharedXAsState` API, the full list is + [here](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateSharedAsState.kt). +2. [Harder] if outside the `SceneScope` of the scene container, observe + [`SceneInteractor.transitionState`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt;l=88;drc=af57d5e49431c6728e7cf192bada88e0541ebf0c). + +## Dependency Injection + +The entire framework is provided into the Dagger dependency graph from the +top-level Dagger module at +[`SceneContainerFrameworkModule`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt) +this puts together the scenes from `SceneModule`, the configuration from +`SceneContainerConfigModule`, and the startable from +`SceneContainerStartableModule`. diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt index 3fbcf6d77f82..15190214e06e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt @@ -24,6 +24,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.util.LatencyTracker import com.android.internal.widget.LockPatternUtils +import com.android.systemui.Flags as AconfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.flags.FakeFeatureFlags @@ -90,8 +91,8 @@ class KeyguardPasswordViewControllerTest : SysuiTestCase() { .thenReturn(mock(ImageView::class.java)) `when`(keyguardPasswordView.resources).thenReturn(context.resources) val fakeFeatureFlags = FakeFeatureFlags() - fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) fakeFeatureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) + mSetFlagsRule.enableFlags(AconfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES) keyguardPasswordViewController = KeyguardPasswordViewController( keyguardPasswordView, diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index 74c922561343..e2bdc49d590c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -24,6 +24,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.util.LatencyTracker import com.android.internal.widget.LockPatternUtils +import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollectorFake @@ -75,8 +76,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory - @Mock - private lateinit var mSelectedUserInteractor: SelectedUserInteractor + @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor @Mock private lateinit var mKeyguardMessageAreaController: @@ -95,7 +95,6 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { whenever(mKeyguardMessageAreaControllerFactory.create(any())) .thenReturn(mKeyguardMessageAreaController) fakeFeatureFlags = FakeFeatureFlags() - fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, false) fakeFeatureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) mKeyguardPatternView = View.inflate(mContext, R.layout.keyguard_pattern_view, null) as KeyguardPatternView @@ -166,7 +165,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { @Test fun withFeatureFlagOn_oldMessage_isHidden() { - fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) + mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES) mKeyguardPatternViewController.onViewAttached() diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index d41c2497b230..e89316997fb2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -35,7 +35,6 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.flags.FakeFeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.res.R; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; @@ -103,8 +102,7 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { when(mPinBasedInputView.getResources()).thenReturn(getContext().getResources()); FakeFeatureFlags featureFlags = new FakeFeatureFlags(); - featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true); - + mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_REVAMPED_BOUNCER_MESSAGES); mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener, diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index f1701356c134..1fc2843b1cb8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -36,6 +36,7 @@ import com.android.internal.logging.UiEventLogger import com.android.internal.widget.LockPatternUtils import com.android.keyguard.KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback import com.android.keyguard.KeyguardSecurityModel.SecurityMode +import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate import com.android.systemui.biometrics.SideFpsController @@ -196,12 +197,12 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { whenever(deviceProvisionedController.isUserSetup(anyInt())).thenReturn(true) featureFlags = FakeFeatureFlags() - featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) featureFlags.set(Flags.BOUNCER_USER_SWITCHER, false) featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false) featureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) + mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES) keyguardPasswordViewController = KeyguardPasswordViewController( keyguardPasswordView, diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt index 84d735430edd..cbcca55f6a34 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt @@ -24,10 +24,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.util.LatencyTracker import com.android.internal.widget.LockPatternUtils +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.res.R import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.mockito.any @@ -81,8 +81,8 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { LayoutInflater.from(context).inflate(R.layout.keyguard_sim_pin_view, null) as KeyguardSimPinView val fakeFeatureFlags = FakeFeatureFlags() - fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) + mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES) underTest = KeyguardSimPinViewController( simPinView, diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt index 7b1f302da6e8..45a60199984b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt @@ -24,10 +24,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.util.LatencyTracker import com.android.internal.widget.LockPatternUtils +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.res.R import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.mockito.any @@ -75,8 +75,7 @@ class KeyguardSimPukViewControllerTest : SysuiTestCase() { LayoutInflater.from(context).inflate(R.layout.keyguard_sim_puk_view, null) as KeyguardSimPukView val fakeFeatureFlags = FakeFeatureFlags() - fakeFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) - + mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES) underTest = KeyguardSimPukViewController( simPukView, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/SysuiTestCaseSelfTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/SysuiTestCaseSelfTest.kt new file mode 100644 index 000000000000..be6bb9c39299 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/SysuiTestCaseSelfTest.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.google.common.truth.Truth +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class SysuiTestCaseSelfTest : SysuiTestCase() { + private val contextBeforeSetup = context + + // cf b/311612168 + @Test + fun captureCorrectContextBeforeSetupRuns() { + Truth.assertThat(contextBeforeSetup).isEqualTo(context) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt index c961be946f79..b9759cc145f2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt @@ -57,6 +57,7 @@ class AuthenticationRepositoryTest : SysuiTestCase() { @Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode> @Mock private lateinit var tableLogger: TableLogBuffer + @Mock private lateinit var devicePolicyManager: DevicePolicyManager private val testUtils = SceneTestUtils(this) private val testScope = testUtils.testScope @@ -87,6 +88,7 @@ class AuthenticationRepositoryTest : SysuiTestCase() { getSecurityMode = getSecurityMode, userRepository = userRepository, lockPatternUtils = lockPatternUtils, + devicePolicyManager = devicePolicyManager, broadcastDispatcher = fakeBroadcastDispatcher, mobileConnectionsRepository = mobileConnectionsRepository, ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt index c113b3744bc0..10c16bd2f3ed 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.authentication.domain.interactor import android.app.admin.DevicePolicyManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.None @@ -26,6 +27,7 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pattern import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pin import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate +import com.android.systemui.authentication.shared.model.AuthenticationWipeModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.scene.SceneTestUtils import com.google.common.truth.Truth.assertThat @@ -404,6 +406,55 @@ class AuthenticationInteractorTest : SysuiTestCase() { } @Test + fun upcomingWipe() = + testScope.runTest { + val upcomingWipe by collectLastValue(underTest.upcomingWipe) + utils.authenticationRepository.setAuthenticationMethod(Pin) + val correctPin = FakeAuthenticationRepository.DEFAULT_PIN + val wrongPin = FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 } + + underTest.authenticate(correctPin) + assertThat(upcomingWipe).isNull() + + var expectedFailedAttempts = 0 + var remainingFailedAttempts = + utils.authenticationRepository.getMaxFailedUnlockAttemptsForWipe() + assertThat(remainingFailedAttempts) + .isGreaterThan(LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) + + // Make many wrong attempts, until wipe is triggered: + repeat(remainingFailedAttempts) { attemptIndex -> + underTest.authenticate(wrongPin) + expectedFailedAttempts++ + remainingFailedAttempts-- + if (underTest.lockoutEndTimestamp != null) { + // If there's a lockout, wait it out: + advanceTimeBy(FakeAuthenticationRepository.LOCKOUT_DURATION_SECONDS.seconds) + } + + if (attemptIndex < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { + // No risk of wipe. + assertThat(upcomingWipe).isNull() + } else { + // Wipe grace period started; Make additional wrong attempts, confirm the + // warning is shown each time: + assertThat(upcomingWipe) + .isEqualTo( + AuthenticationWipeModel( + wipeTarget = AuthenticationWipeModel.WipeTarget.WholeDevice, + failedAttempts = expectedFailedAttempts, + remainingAttempts = remainingFailedAttempts + ) + ) + } + } + + // Unlock successfully, no more risk of upcoming wipe: + assertSucceeded(underTest.authenticate(correctPin)) + assertThat(upcomingWipe).isNull() + } + + @Test fun hintedPinLength_withoutAutoConfirm_isNull() = testScope.runTest { val hintedPinLength by collectLastValue(underTest.hintedPinLength) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt index 4be9b0a49a69..47bbe6f49a5e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt @@ -21,6 +21,11 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.None +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Password +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pattern +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pin +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Sim import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.Flags import com.android.systemui.scene.SceneTestUtils @@ -47,7 +52,6 @@ class BouncerViewModelTest : SysuiTestCase() { private val utils = SceneTestUtils(this) private val testScope = utils.testScope private val authenticationInteractor = utils.authenticationInteractor() - private val actionButtonInteractor = utils.bouncerActionButtonInteractor() private val bouncerInteractor = utils.bouncerInteractor( authenticationInteractor = authenticationInteractor, @@ -56,7 +60,6 @@ class BouncerViewModelTest : SysuiTestCase() { utils.bouncerViewModel( bouncerInteractor = bouncerInteractor, authenticationInteractor = authenticationInteractor, - actionButtonInteractor = actionButtonInteractor, ) @Test @@ -136,7 +139,7 @@ class BouncerViewModelTest : SysuiTestCase() { fun message() = testScope.runTest { val message by collectLastValue(underTest.message) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) + utils.authenticationRepository.setAuthenticationMethod(Pin) assertThat(message?.isUpdateAnimated).isTrue() repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT) { @@ -154,7 +157,7 @@ class BouncerViewModelTest : SysuiTestCase() { testScope.runTest { val authMethodViewModel by collectLastValue(underTest.authMethodViewModel) val message by collectLastValue(underTest.message) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) + utils.authenticationRepository.setAuthenticationMethod(Pin) assertThat(utils.authenticationRepository.lockoutEndTimestamp).isNull() assertThat(authMethodViewModel?.lockoutMessageId).isNotNull() @@ -189,7 +192,7 @@ class BouncerViewModelTest : SysuiTestCase() { authViewModel?.isInputEnabled ?: emptyFlow() } ) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) + utils.authenticationRepository.setAuthenticationMethod(Pin) assertThat(isInputEnabled).isTrue() repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT) { @@ -203,21 +206,22 @@ class BouncerViewModelTest : SysuiTestCase() { } @Test - fun dialogMessage() = + fun dialogViewModel() = testScope.runTest { val authMethodViewModel by collectLastValue(underTest.authMethodViewModel) - val dialogMessage by collectLastValue(underTest.dialogMessage) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) + val dialogViewModel by collectLastValue(underTest.dialogViewModel) + utils.authenticationRepository.setAuthenticationMethod(Pin) assertThat(authMethodViewModel?.lockoutMessageId).isNotNull() repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT) { - assertThat(dialogMessage).isNull() + assertThat(dialogViewModel).isNull() bouncerInteractor.authenticate(WRONG_PIN) } - assertThat(dialogMessage).isNotEmpty() + assertThat(dialogViewModel).isNotNull() + assertThat(dialogViewModel?.text).isNotEmpty() - underTest.onDialogDismissed() - assertThat(dialogMessage).isNull() + dialogViewModel?.onDismiss?.invoke() + assertThat(dialogViewModel).isNull() } @Test @@ -225,20 +229,16 @@ class BouncerViewModelTest : SysuiTestCase() { testScope.runTest { val isSideBySideSupported by collectLastValue(underTest.isSideBySideSupported) utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) + utils.authenticationRepository.setAuthenticationMethod(Pin) assertThat(isSideBySideSupported).isTrue() - utils.authenticationRepository.setAuthenticationMethod( - AuthenticationMethodModel.Password - ) + utils.authenticationRepository.setAuthenticationMethod(Password) assertThat(isSideBySideSupported).isTrue() utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, false) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) + utils.authenticationRepository.setAuthenticationMethod(Pin) assertThat(isSideBySideSupported).isTrue() - utils.authenticationRepository.setAuthenticationMethod( - AuthenticationMethodModel.Password - ) + utils.authenticationRepository.setAuthenticationMethod(Password) assertThat(isSideBySideSupported).isFalse() } @@ -246,27 +246,17 @@ class BouncerViewModelTest : SysuiTestCase() { fun isFoldSplitRequired() = testScope.runTest { val isFoldSplitRequired by collectLastValue(underTest.isFoldSplitRequired) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) + utils.authenticationRepository.setAuthenticationMethod(Pin) assertThat(isFoldSplitRequired).isTrue() - utils.authenticationRepository.setAuthenticationMethod( - AuthenticationMethodModel.Password - ) + utils.authenticationRepository.setAuthenticationMethod(Password) assertThat(isFoldSplitRequired).isFalse() - utils.authenticationRepository.setAuthenticationMethod( - AuthenticationMethodModel.Pattern - ) + utils.authenticationRepository.setAuthenticationMethod(Pattern) assertThat(isFoldSplitRequired).isTrue() } private fun authMethodsToTest(): List<AuthenticationMethodModel> { - return listOf( - AuthenticationMethodModel.None, - AuthenticationMethodModel.Pin, - AuthenticationMethodModel.Password, - AuthenticationMethodModel.Pattern, - AuthenticationMethodModel.Sim, - ) + return listOf(None, Pin, Password, Pattern, Sim) } private fun assertTryAgainMessage( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt index ed7609999804..83d1938c93be 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt @@ -303,7 +303,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { fun onDragEnd_whenPatternTooShort() = testScope.runTest { val message by collectLastValue(bouncerViewModel.message) - val dialogMessage by collectLastValue(bouncerViewModel.dialogMessage) + val dialogViewModel by collectLastValue(bouncerViewModel.dialogViewModel) lockDeviceAndOpenPatternBouncer() // Enter a pattern that's too short more than enough times that would normally trigger @@ -326,7 +326,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { underTest.onDragEnd() assertWithMessage("Attempt #$attempt").that(message?.text).isEqualTo(WRONG_PATTERN) - assertWithMessage("Attempt #$attempt").that(dialogMessage).isNull() + assertWithMessage("Attempt #$attempt").that(dialogViewModel).isNull() } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index 1f8e29adc983..62084aa0d981 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -28,6 +28,7 @@ import com.android.systemui.communal.data.repository.FakeCommunalRepository import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel +import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.communal.shared.model.CommunalWidgetContentModel import com.android.systemui.communal.widgets.EditWidgetsActivityStarter @@ -169,6 +170,109 @@ class CommunalInteractorTest : SysuiTestCase() { } @Test + fun smartspaceDynamicSizing_oneCard_fullSize() = + testSmartspaceDynamicSizing( + totalTargets = 1, + expectedSizes = + listOf( + CommunalContentSize.FULL, + ) + ) + + @Test + fun smartspace_dynamicSizing_twoCards_halfSize() = + testSmartspaceDynamicSizing( + totalTargets = 2, + expectedSizes = + listOf( + CommunalContentSize.HALF, + CommunalContentSize.HALF, + ) + ) + + @Test + fun smartspace_dynamicSizing_threeCards_thirdSize() = + testSmartspaceDynamicSizing( + totalTargets = 3, + expectedSizes = + listOf( + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + ) + ) + + @Test + fun smartspace_dynamicSizing_fourCards_oneFullAndThreeThirdSize() = + testSmartspaceDynamicSizing( + totalTargets = 4, + expectedSizes = + listOf( + CommunalContentSize.FULL, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + ) + ) + + @Test + fun smartspace_dynamicSizing_fiveCards_twoHalfAndThreeThirdSize() = + testSmartspaceDynamicSizing( + totalTargets = 5, + expectedSizes = + listOf( + CommunalContentSize.HALF, + CommunalContentSize.HALF, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + ) + ) + + @Test + fun smartspace_dynamicSizing_sixCards_allThirdSize() = + testSmartspaceDynamicSizing( + totalTargets = 6, + expectedSizes = + listOf( + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + CommunalContentSize.THIRD, + ) + ) + + private fun testSmartspaceDynamicSizing( + totalTargets: Int, + expectedSizes: List<CommunalContentSize>, + ) = + testScope.runTest { + // Keyguard showing, and tutorial completed. + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setKeyguardOccluded(false) + tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + + val targets = mutableListOf<SmartspaceTarget>() + for (index in 0 until totalTargets) { + val target = mock(SmartspaceTarget::class.java) + whenever(target.smartspaceTargetId).thenReturn("target$index") + whenever(target.featureType).thenReturn(SmartspaceTarget.FEATURE_TIMER) + whenever(target.remoteViews).thenReturn(mock(RemoteViews::class.java)) + targets.add(target) + } + + smartspaceRepository.setCommunalSmartspaceTargets(targets) + + val smartspaceContent by collectLastValue(underTest.smartspaceContent) + assertThat(smartspaceContent?.size).isEqualTo(totalTargets) + for (index in 0 until totalTargets) { + assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index]) + } + } + + @Test fun umo_mediaPlaying_showsUmo() = testScope.runTest { // Tutorial completed. diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt index 477f4555ea65..032979447861 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,20 +12,19 @@ * WITHOUT WARRANTIES 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.quickaffordance import android.app.Activity import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.ui.ControlsUiController +import com.android.systemui.res.R import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat @@ -37,17 +36,17 @@ import kotlinx.coroutines.test.runBlockingTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.Parameterized -import org.junit.runners.Parameterized.Parameter -import org.junit.runners.Parameterized.Parameters import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.Parameter +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @SmallTest -@RunWith(Parameterized::class) +@RunWith(ParameterizedAndroidJunit4::class) class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTestCase() { companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index d6d5b23a311d..941d67f0a34e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -56,7 +56,6 @@ import com.android.systemui.coroutines.collectValues import com.android.systemui.display.data.repository.FakeDisplayRepository import com.android.systemui.display.data.repository.display import com.android.systemui.dump.DumpManager -import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.KEYGUARD_WM_STATE_REFACTOR import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor @@ -73,6 +72,7 @@ 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.log.SessionTracker +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.power.data.repository.FakePowerRepository diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt index 9daf1860ebb8..e7037a682cca 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt @@ -94,7 +94,7 @@ class AlternateBouncerToAodTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(6) + assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt new file mode 100644 index 000000000000..83782e214780 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelTest.kt @@ -0,0 +1,108 @@ +/* + * 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.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +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.kosmos.testScope +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class AodAlphaViewModelTest : SysuiTestCase() { + + @Mock + private lateinit var occludedToLockscreenTransitionViewModel: + OccludedToLockscreenTransitionViewModel + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val keyguardRepository = kosmos.fakeKeyguardRepository + private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + private val occludedToLockscreenAlpha = MutableStateFlow(0f) + + private lateinit var underTest: AodAlphaViewModel + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(occludedToLockscreenTransitionViewModel.lockscreenAlpha) + .thenReturn(occludedToLockscreenAlpha) + kosmos.occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel + + underTest = kosmos.aodAlphaViewModel + } + + @Test + fun alpha() = + testScope.runTest { + val alpha by collectLastValue(underTest.alpha) + + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.OFF, + to = KeyguardState.LOCKSCREEN, + testScope = testScope, + ) + + keyguardRepository.setKeyguardAlpha(0.1f) + assertThat(alpha).isEqualTo(0.1f) + keyguardRepository.setKeyguardAlpha(0.5f) + assertThat(alpha).isEqualTo(0.5f) + keyguardRepository.setKeyguardAlpha(0.2f) + assertThat(alpha).isEqualTo(0.2f) + keyguardRepository.setKeyguardAlpha(0f) + assertThat(alpha).isEqualTo(0f) + occludedToLockscreenAlpha.value = 0.8f + assertThat(alpha).isEqualTo(0.8f) + } + + @Test + fun alpha_whenGone_equalsZero() = + testScope.runTest { + val alpha by collectLastValue(underTest.alpha) + + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + testScope = testScope, + ) + + keyguardRepository.setKeyguardAlpha(0.1f) + assertThat(alpha).isEqualTo(0f) + keyguardRepository.setKeyguardAlpha(0.5f) + assertThat(alpha).isEqualTo(0f) + keyguardRepository.setKeyguardAlpha(1f) + assertThat(alpha).isEqualTo(0f) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt new file mode 100644 index 000000000000..0543bc257440 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt @@ -0,0 +1,290 @@ +/* + * 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.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.domain.interactor.BurnInInteractor +import com.android.systemui.keyguard.domain.interactor.burnInInteractor +import com.android.systemui.keyguard.shared.model.BurnInModel +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.kosmos.testScope +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Answers +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class AodBurnInViewModelTest : SysuiTestCase() { + + @Mock private lateinit var burnInInteractor: BurnInInteractor + @Mock private lateinit var goneToAodTransitionViewModel: GoneToAodTransitionViewModel + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var clockController: ClockController + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + private lateinit var underTest: AodBurnInViewModel + + private var burnInParameters = + BurnInParameters( + clockControllerProvider = { clockController }, + ) + private val burnInFlow = MutableStateFlow(BurnInModel()) + private val enterFromTopAnimationAlpha = MutableStateFlow(0f) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(burnInInteractor.keyguardBurnIn).thenReturn(burnInFlow) + kosmos.burnInInteractor = burnInInteractor + whenever(goneToAodTransitionViewModel.enterFromTopAnimationAlpha) + .thenReturn(enterFromTopAnimationAlpha) + whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt())) + .thenReturn(emptyFlow()) + kosmos.goneToAodTransitionViewModel = goneToAodTransitionViewModel + + underTest = kosmos.aodBurnInViewModel + } + + @Test + fun translationY_initializedToZero() = + testScope.runTest { + val translationY by collectLastValue(underTest.translationY(burnInParameters)) + assertThat(translationY).isEqualTo(0) + } + + @Test + fun translationAndScale_whenNotDozing() = + testScope.runTest { + val translationX by collectLastValue(underTest.translationX(burnInParameters)) + val translationY by collectLastValue(underTest.translationY(burnInParameters)) + val scale by collectLastValue(underTest.scale(burnInParameters)) + + // Set to not dozing (on lockscreen) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + value = 1f, + transitionState = TransitionState.FINISHED + ), + validateStep = false, + ) + + // Trigger a change to the burn-in model + burnInFlow.value = + BurnInModel( + translationX = 20, + translationY = 30, + scale = 0.5f, + ) + + assertThat(translationX).isEqualTo(0) + assertThat(translationY).isEqualTo(0) + assertThat(scale) + .isEqualTo( + BurnInScaleViewModel( + scale = 1f, + scaleClockOnly = true, + ) + ) + } + + @Test + fun translationAndScale_whenFullyDozing() = + testScope.runTest { + burnInParameters = burnInParameters.copy(statusViewTop = 100) + val translationX by collectLastValue(underTest.translationX(burnInParameters)) + val translationY by collectLastValue(underTest.translationY(burnInParameters)) + val scale by collectLastValue(underTest.scale(burnInParameters)) + + // Set to dozing (on AOD) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 1f, + transitionState = TransitionState.FINISHED + ), + validateStep = false, + ) + // Trigger a change to the burn-in model + burnInFlow.value = + BurnInModel( + translationX = 20, + translationY = 30, + scale = 0.5f, + ) + + assertThat(translationX).isEqualTo(20) + assertThat(translationY).isEqualTo(30) + assertThat(scale) + .isEqualTo( + BurnInScaleViewModel( + scale = 0.5f, + scaleClockOnly = true, + ) + ) + + // Set to the beginning of GONE->AOD transition + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 0f, + transitionState = TransitionState.STARTED + ), + validateStep = false, + ) + assertThat(translationX).isEqualTo(0) + assertThat(translationY).isEqualTo(0) + assertThat(scale) + .isEqualTo( + BurnInScaleViewModel( + scale = 1f, + scaleClockOnly = true, + ) + ) + } + + @Test + fun translationAndScale_whenFullyDozing_staysOutOfTopInset() = + testScope.runTest { + burnInParameters = + burnInParameters.copy( + statusViewTop = 100, + topInset = 80, + ) + val translationX by collectLastValue(underTest.translationX(burnInParameters)) + val translationY by collectLastValue(underTest.translationY(burnInParameters)) + val scale by collectLastValue(underTest.scale(burnInParameters)) + + // Set to dozing (on AOD) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 1f, + transitionState = TransitionState.FINISHED + ), + validateStep = false, + ) + + // Trigger a change to the burn-in model + burnInFlow.value = + BurnInModel( + translationX = 20, + translationY = -30, + scale = 0.5f, + ) + assertThat(translationX).isEqualTo(20) + // -20 instead of -30, due to inset of 80 + assertThat(translationY).isEqualTo(-20) + assertThat(scale) + .isEqualTo( + BurnInScaleViewModel( + scale = 0.5f, + scaleClockOnly = true, + ) + ) + + // Set to the beginning of GONE->AOD transition + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 0f, + transitionState = TransitionState.STARTED + ), + validateStep = false, + ) + assertThat(translationX).isEqualTo(0) + assertThat(translationY).isEqualTo(0) + assertThat(scale) + .isEqualTo( + BurnInScaleViewModel( + scale = 1f, + scaleClockOnly = true, + ) + ) + } + + @Test + fun translationAndScale_useScaleOnly() = + testScope.runTest { + whenever(clockController.config.useAlternateSmartspaceAODTransition).thenReturn(true) + + val translationX by collectLastValue(underTest.translationX(burnInParameters)) + val translationY by collectLastValue(underTest.translationY(burnInParameters)) + val scale by collectLastValue(underTest.scale(burnInParameters)) + + // Set to dozing (on AOD) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 1f, + transitionState = TransitionState.FINISHED + ), + validateStep = false, + ) + + // Trigger a change to the burn-in model + burnInFlow.value = + BurnInModel( + translationX = 20, + translationY = 30, + scale = 0.5f, + ) + + assertThat(translationX).isEqualTo(0) + assertThat(translationY).isEqualTo(0) + assertThat(scale).isEqualTo(BurnInScaleViewModel(scale = 0.5f, scaleClockOnly = false)) + } + + @Test + fun alpha() = + testScope.runTest { + val alpha by collectLastValue(underTest.alpha) + + enterFromTopAnimationAlpha.value = 0.2f + assertThat(alpha).isEqualTo(0.2f) + + enterFromTopAnimationAlpha.value = 1f + assertThat(alpha).isEqualTo(1f) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt index 53bca483f73f..e141c2b3107f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt @@ -55,6 +55,28 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { private val underTest = kosmos.dreamingToLockscreenTransitionViewModel @Test + fun shortcutsAlpha_bothShortcutsReceiveLastValue() = + testScope.runTest { + val valuesLeft by collectValues(underTest.shortcutsAlpha) + val valuesRight by collectValues(underTest.shortcutsAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.3f), + step(0.5f), + step(0.6f), + step(0.8f), + step(1f), + ), + testScope, + ) + + assertThat(valuesLeft.last()).isEqualTo(1f) + assertThat(valuesRight.last()).isEqualTo(1f) + } + + @Test fun dreamOverlayTranslationY() = testScope.runTest { val pixels = 100 @@ -73,7 +95,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(7) + assertThat(values.size).isEqualTo(6) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } } @@ -95,7 +117,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(4) + assertThat(values.size).isEqualTo(3) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } @@ -210,7 +232,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt index 3c07034f0e12..897ce6d305b6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt @@ -61,7 +61,7 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { // Only three values should be present, since the dream overlay runs for a small // fraction of the overall animation time - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } @@ -84,7 +84,7 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt new file mode 100644 index 000000000000..7c3dc972cfd0 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -0,0 +1,207 @@ +/* + * 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.keyguard.ui.viewmodel + +import android.view.View +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags as AConfigFlags +import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository +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.kosmos.testScope +import com.android.systemui.statusbar.notification.data.repository.fakeNotificationsKeyguardViewStateRepository +import com.android.systemui.statusbar.phone.dozeParameters +import com.android.systemui.statusbar.phone.screenOffAnimationController +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.ui.isAnimating +import com.android.systemui.util.ui.stopAnimating +import com.android.systemui.util.ui.value +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class KeyguardRootViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + private val screenOffAnimationController = kosmos.screenOffAnimationController + private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository + private val fakeNotificationsKeyguardViewStateRepository = + kosmos.fakeNotificationsKeyguardViewStateRepository + private val dozeParameters = kosmos.dozeParameters + private val underTest = kosmos.keyguardRootViewModel + + @Before + fun setUp() { + mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR) + mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION) + mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) + } + + @Test + fun burnInLayerVisibility() = + testScope.runTest { + val burnInLayerVisibility by collectLastValue(underTest.burnInLayerVisibility) + + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + value = 0f, + transitionState = TransitionState.STARTED + ), + validateStep = false, + ) + assertThat(burnInLayerVisibility).isEqualTo(View.VISIBLE) + } + + @Test + fun iconContainer_isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.OFF, + to = KeyguardState.GONE, + testScope, + ) + whenever(screenOffAnimationController.shouldShowAodIconsWhenShade()).thenReturn(false) + runCurrent() + + assertThat(isVisible?.value).isFalse() + assertThat(isVisible?.isAnimating).isFalse() + } + + @Test + fun iconContainer_isVisible_bypassEnabled() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + deviceEntryRepository.setBypassEnabled(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + } + + @Test + fun iconContainer_isNotVisible_pulseExpanding_notBypassing() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(true) + deviceEntryRepository.setBypassEnabled(false) + runCurrent() + + assertThat(isVisible?.value).isEqualTo(false) + } + + @Test + fun iconContainer_isVisible_notifsFullyHidden_bypassEnabled() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(true) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isTrue() + } + + @Test + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParameters.alwaysOn).thenReturn(false) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isFalse() + } + + @Test + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParameters.alwaysOn).thenReturn(true) + whenever(dozeParameters.displayNeedsBlanking).thenReturn(true) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isFalse() + } + + @Test + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParameters.alwaysOn).thenReturn(true) + whenever(dozeParameters.displayNeedsBlanking).thenReturn(false) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isTrue() + } + + @Test + fun isIconContainerVisible_stopAnimation() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParameters.alwaysOn).thenReturn(true) + whenever(dozeParameters.displayNeedsBlanking).thenReturn(false) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.isAnimating).isEqualTo(true) + isVisible?.stopAnimating() + runCurrent() + + assertThat(isVisible?.isAnimating).isEqualTo(false) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt index d07836d3abce..74d309c1d359 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -26,6 +28,7 @@ import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.util.mockito.mock 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 @@ -94,7 +97,6 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { KeyguardLongPressViewModel( interactor = mock(), ), - keyguardRoot = utils.keyguardRootViewModel(), notifications = utils.notificationsPlaceholderViewModel(), ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt index a346e8b45795..4843f8ba4249 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt @@ -75,7 +75,7 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { // Only three values should be present, since the dream overlay runs for a small // fraction of the overall animation time - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } @@ -98,10 +98,10 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { testScope = testScope, ) - assertThat(values.size).isEqualTo(6) + assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } // Validate finished value - assertThat(values[5]).isEqualTo(0f) + assertThat(values[4]).isEqualTo(0f) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt index 274bde1ccfdf..a1b8aab402a7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt @@ -76,7 +76,7 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { ) // Only 3 values should be present, since the dream overlay runs for a small fraction // of the overall animation time - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } @@ -99,7 +99,7 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { ), testScope = testScope, ) - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } } @@ -121,11 +121,11 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { ), testScope = testScope, ) - assertThat(values.size).isEqualTo(4) + assertThat(values.size).isEqualTo(3) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } // Cancel will reset the translation - assertThat(values[3]).isEqualTo(0) + assertThat(values[2]).isEqualTo(0) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt index d419d4a2534c..2111ad5d975e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt @@ -95,7 +95,7 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt index f027bc849e51..90b83620084c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -95,7 +95,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(3) + assertThat(values.size).isEqualTo(1) values.forEach { assertThat(it).isEqualTo(0f) } } @@ -107,7 +107,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) keyguardTransitionRepository.sendTransitionStep(step(1f)) - assertThat(values.size).isEqualTo(2) + assertThat(values.size).isEqualTo(1) values.forEach { assertThat(it).isEqualTo(0f) } } @@ -121,7 +121,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) keyguardTransitionRepository.sendTransitionStep(step(1f)) - assertThat(values.size).isEqualTo(2) + assertThat(values.size).isEqualTo(1) values.forEach { assertThat(it).isEqualTo(1f) } } @@ -135,7 +135,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) keyguardTransitionRepository.sendTransitionStep(step(1f)) - assertThat(values.size).isEqualTo(2) + assertThat(values.size).isEqualTo(1) values.forEach { assertThat(it).isEqualTo(1f) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt index 92c2d743c262..4a39ba234c67 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/logging/QSTileLoggerTest.kt @@ -21,9 +21,9 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon -import com.android.systemui.dump.LogcatEchoTrackerAlways import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogBufferFactory +import com.android.systemui.log.LogcatEchoTrackerAlways import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.viewmodel.QSTileState diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index 224903ff36b8..efd4f9bdf449 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -153,7 +153,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { KeyguardLongPressViewModel( interactor = mock(), ), - keyguardRoot = utils.keyguardRootViewModel(), notifications = utils.notificationsPlaceholderViewModel(), ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java index 53cb8a7eb81b..7a78b366dd7f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -25,15 +25,14 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.graphics.Point; import android.os.PowerManager; -import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.View; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; @@ -68,7 +67,7 @@ import java.util.Collections; import java.util.HashSet; @SmallTest -@RunWith(AndroidTestingRunner.class) +@RunWith(AndroidJUnit4.class) @RunWithLooper(setAsMainLooper = true) public class DozeServiceHostTest extends SysuiTestCase { @@ -181,6 +180,7 @@ public class DozeServiceHostTest extends SysuiTestCase { DozeLog.PULSE_REASON_DOCKING, DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE, DozeLog.REASON_SENSOR_QUICK_PICKUP, + DozeLog.PULSE_REASON_FINGERPRINT_ACTIVATED, DozeLog.REASON_SENSOR_TAP)); HashSet<Integer> reasonsThatDontPulse = new HashSet<>( Arrays.asList(DozeLog.REASON_SENSOR_PICKUP, @@ -232,7 +232,7 @@ public class DozeServiceHostTest extends SysuiTestCase { public void onSlpiTap_doesnt_pass_negative_values() { mDozeServiceHost.onSlpiTap(-1, 200); mDozeServiceHost.onSlpiTap(100, -2); - verifyZeroInteractions(mDozeInteractor); + verify(mDozeInteractor, never()).setLastTapToWakePosition(any()); } @Test public void dozeTimeTickSentToDozeInteractor() { diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index fba6d21d8324..db4cca3087bc 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skermopname"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Begin"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Neem kwessie op"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Begin"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Watter deel van jou toestelervaring is geraak?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Kies soort kwessie"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skermopname"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Werkverrigting"</item> + <item msgid="1627504621139124393">"Gebruikerkoppelvlak"</item> + <item msgid="8309220355268900335">"Battery"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swiep links om die gemeenskaplike tutoriaal te begin"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Maak die legstukredigeerder oop"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwyder"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Voeg legstuk by"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aftrekkieslys"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tik om Batterybespaarder te skeduleer"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Skakel aan wanneer battery waarskynlik sal leegloop"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nee, dankie"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Stort SysUI-hoop"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In gebruik"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programme gebruik tans jou <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string> <string name="install_app" msgid="5066668100199613936">"Installeer app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Sinkroniseer wedersyds na eksterne skerm?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Enige Dual Screen-aktiwiteit wat tans loop sal gestop word"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Sinkroniseer skerm wedersyds"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Maak toe"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Skerm is gekoppel"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 12276f567478..74e92ba8b14f 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"የማያ ቀረጻ"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ጀምር"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"አቁም"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ችግርን ቅዳ"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"ጀምር"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"አቁም"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"የትኛው የመሣሪያዎ ተሞክሮ ክፍል ተጎድቷል?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"የችግሩን አይነት ይምረጡ"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"የማያ መቅረጫ"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"አፈጻጸም"</item> + <item msgid="1627504621139124393">"የተጠቃሚ በይነገፅ"</item> + <item msgid="8309220355268900335">"ባትሪ"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ኃይል በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"የጋራ አጋዥ ሥልጠናውን ለመጀመር ወደ ግራ ያንሸራትቱ።"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"የምግብር አርታዒውን ይክፈቱ"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"አስወግድ"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ምግብር አክል"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ተከናውኗል"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ወደታች ተጎታች ምናሌ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ለባትሪ ቆጣቢ መርሐግብርን ለማስያዝ መታ ያድርጉ"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ባትሪው የማለቅ ዕድሉ ከፍ ያለ ከሆነ ያብሩት"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"አይ፣ አመሰግናለሁ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI Heap አራግፍ"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"በጥቅም ላይ"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"መተግበሪያዎች የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> እየተጠቀሙ ነው።"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"፣ "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string> <string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ወደ ውጫዊ ማሳያ ይንጸባረቅ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"በአሁኑ ጊዜ እያሄደ ያለው ማንኛውም የDual Screen እንቅስቃሴ ይቆማል"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ማሳያን አንጸባርቅ"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"አሰናብት"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ማሳያ ተገናኝቷል"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index ac76ed06e72b..8aeeaf73bbb2 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -336,6 +336,14 @@ <skip /> <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> <skip /> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ما هو الجانب الذي تأثّر في تجربة استخدام الجهاز؟"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"اختيار نوع المشكلة"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"تسجيل الشاشة"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"الأداء"</item> + <item msgid="1627504621139124393">"واجهة المستخدم"</item> + <item msgid="8309220355268900335">"البطارية"</item> + </string-array> <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> @@ -465,7 +473,7 @@ <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"محو جميع الإشعارات الصامتة"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"تم إيقاف الإشعارات مؤقتًا وفقًا لإعداد \"عدم الإزعاج\""</string> <string name="media_projection_action_text" msgid="3634906766918186440">"البدء الآن"</string> - <string name="empty_shade_text" msgid="8935967157319717412">"ليس هناك أي اشعارات"</string> + <string name="empty_shade_text" msgid="8935967157319717412">"ما مِن إشعارات."</string> <string name="no_unseen_notif_text" msgid="395512586119868682">"ما مِن إشعارات جديدة"</string> <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"افتَح قفل الشاشة لعرض الإشعارات الأقدم."</string> <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"يتولّى أحد الوالدين إدارة هذا الجهاز."</string> @@ -867,7 +875,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"انقر لجدولة \"توفير شحن البطارية\"."</string> <string name="auto_saver_text" msgid="3214960308353838764">"فعِّل الميزة إذا كان من المرجح نفاد شحن البطارية."</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"لا، شكرًا"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"تفريغ ذاكرة SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"قيد الاستخدام"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"تستخدم التطبيقات <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string> @@ -1207,7 +1214,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string> <string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"هل تريد بث محتوى جهازك على الشاشة الخارجية؟"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"بث المحتوى على الشاشة"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"إغلاق"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 21da3872cddf..a1b538934236 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"স্ক্ৰীন ৰেকৰ্ড কৰা"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"আৰম্ভ কৰক"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ কৰক"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ৰেকৰ্ড সম্পৰ্কীয় সমস্যা"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"আৰম্ভ কৰক"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"বন্ধ কৰক"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"আপোনাৰ ডিভাইচৰ অভিজ্ঞতাৰ কোনটো অংশ প্ৰভাৱিত হৈছিল?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"সমস্যাৰ প্ৰকাৰ বাছনি কৰক"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"স্ক্ৰীন ৰেকৰ্ড"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"কাৰ্যদক্ষতা"</item> + <item msgid="1627504621139124393">"ব্যৱহাৰকাৰীৰ ইণ্টাৰফে’চ"</item> + <item msgid="8309220355268900335">"বেটাৰী"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"সম্প্ৰদায় সম্পৰ্কীয় নিৰ্দেশনা আৰম্ভ কৰিবলৈ বাওঁফালে ছোৱাইপ কৰক"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ৱিজেট সম্পাদকটো খোলক"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"আঁতৰাওক"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ৱিজেট যোগ দিয়ক"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"কৰা হ’ল"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুল-ডাউনৰ মেনু"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"বেটাৰী সঞ্চয়কাৰীৰ সময়সূচী সক্ৰিয় কৰিবলৈ টিপক"</string> <string name="auto_saver_text" msgid="3214960308353838764">"বেটাৰী শেষ হোৱাৰ সম্ভাৱনা থাকিলে অন কৰক"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"নালাগে, ধন্যবাদ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI হীপ ডাম্প কৰক"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ব্যৱহাৰ হৈ আছে"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"এপ্লিকেশ্বনসমূহে আপোনাৰ <xliff:g id="TYPES_LIST">%s</xliff:g> ব্যৱহাৰ কৰি আছে।"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string> <string name="install_app" msgid="5066668100199613936">"এপ্টো ইনষ্টল কৰক"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"বাহ্যিক ডিছপ্লে’লৈ মিৰ’ৰ কৰিবনে?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"বৰ্তমান চলি থকা যিকোনো দ্বৈত স্ক্ৰীনৰ কাৰ্যকলাপ বন্ধ কৰা হ’ব"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ডিছপ্লে’ মিৰ’ৰ কৰক"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"অগ্ৰাহ্য কৰক"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ডিছপ্লে’ সংযোগ কৰা হৈছে"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index ec4d71240b69..2a9a9cfe2624 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekran yazması"</string> <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> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Qeyd problemi"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Başlayın"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Dayandırın"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz istifadəsinə necə təsir etdi?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problem növü seçin"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran qeydəalma"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performans"</item> + <item msgid="1627504621139124393">"İstifadəçi interfeysi"</item> + <item msgid="8309220355268900335">"Batareya"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj edilir • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> sonra dolacaq"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"İcma təlimatını başlatmaq üçün sola sürüşdürün"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Vidcet redaktorunu açın"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Silin"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidcet əlavə edin"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hazırdır"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aşağı çəkilən menyu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Batareya Qənaətini planlaşdırmaq üçün klikləyin"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Batareya bitmək üzrə olduqda aktiv edin"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Xeyr, təşəkkür"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"İstifadə olunur"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Tətbiqlər <xliff:g id="TYPES_LIST">%s</xliff:g> istifadə edir."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string> <string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Xarici displeyə əks etdirilsin?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Davam edən istənilən dual screen fəaliyyəti dayandırılacaq"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Displeyi əks etdirin"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"İmtina edin"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Displey qoşulub"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 1320d0a3eb10..47468ffb033d 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Snimanje ekrana"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Počnite"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavite"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Evidentirajte problem"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Pokreni"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zaustavi"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na koji deo doživljaja na uređaju je ovo uticalo?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Izaberite tip problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje ekrana"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Učinak"</item> + <item msgid="1627504621139124393">"Korisnički interfejs"</item> + <item msgid="8309220355268900335">"Baterija"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Puni se • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Prevucite ulevo da biste započeli zajednički vodič"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otvori uređivač vidžeta"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj vidžet"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Dodirnite da biste napravili raspored za uštedu baterije"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Uključite ako će baterija verovatno da se isprazni"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji SysUI mem."</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"U upotrebi"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string> <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li da preslikate na spoljnji ekran?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Biće zaustavljena svaka aktivnost dvojnog ekrana koja je u toku"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Ekran je povezan"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 570acc81f16d..3bc6269a71b0 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Запіс экрана"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Пачаць"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Спыніць"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Запіс праблемы"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Пачынайце"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Спыніцеся"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"З чым была звязана праблема, якая вам сустрэлася?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберыце тып праблемы"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запіс экрана"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Прадукцыйнасць"</item> + <item msgid="1627504621139124393">"Карыстальніцкі інтэрфейс"</item> + <item msgid="8309220355268900335">"Акумулятар"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Правядзіце пальцам па экране ўлева, каб азнаёміцца з дапаможнікам"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Адкрыць рэдактар віджэтаў"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Выдаліць"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Дадаць віджэт"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Гатова"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"высоўнае меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Націсніце, каб уключыць рэжым эканоміі зараду"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Уключыце, калі зарад акумулятара заканчваецца"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Не, дзякуй"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Выкарыстоўваецца"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Праграмы выкарыстоўваюць: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string> <string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Адлюстраваць на знешнім дысплэі?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Функцыя адначасовага выкарыстання двух экранаў будзе спынена, калі яна актыўная"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Адлюстраваць дысплэй"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Закрыць"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Дысплэй падключаны"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index e52b7935992d..1fe96a674e54 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Запис на екрана"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Старт"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Стоп"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Записване на проблем"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Стартиране"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Спиране"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С какво имахте проблем?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис на екрана"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Ефективност"</item> + <item msgid="1627504621139124393">"Потребителски интерфейс"</item> + <item msgid="8309220355268900335">"Батерия"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарежда се • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до пълно зареждане"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Прекарайте пръст наляво, за да стартирате общия урок"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Отваряне на редактора на приспособлението"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Премахване"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавяне на приспособление"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падащо меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Докоснете, за да активирате автоматичния режим за запазване на батерията"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Включване, когато е вероятно батерията да се изтощи"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Не, благодаря"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Използва се"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Някои приложения използват <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string> <string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се дублира ли на външния екран?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Всяка текуща активност с функцията Dual Screen ще бъде спряна"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Дублиране на дисплея"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Отхвърляне"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Свързан е екран"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 5e658300bf07..fa301313dc81 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"স্ক্রিন রেকর্ড"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"শুরু করুন"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ করুন"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"রেকর্ডিংয়ে সমস্যা"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"শুরু করুন"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"বন্ধ করুন"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ডিভাইস ব্যবহার করার সময় কোথায় অসুবিধা হয়েছিল?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"সমস্যার প্রকার বেছে নিন"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"স্ক্রিন রেকর্ড"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"পারফর্ম্যান্স"</item> + <item msgid="1627504621139124393">"ইউজার ইন্টারফেস"</item> + <item msgid="8309220355268900335">"ব্যাটারি"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চার্জ হচ্ছে • পুরো চার্জ হতে আরও <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> সময় লাগবে"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"কমিউনিটি টিউটোরিয়াল চালু করতে বাঁদিকে সোয়াইপ করুন"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"উইজেট এডিটর খুলুন"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"সরান"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"উইজেট যোগ করুন"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"হয়ে গেছে"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুলডাউন মেনু"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ব্যাটারি সেভার চালু হওয়ার সময় সেট করতে ট্যাপ করুন"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ব্যাটারির চার্জ শেষ হয়ে যাওয়ার সম্ভাবনা দেখা দিলে চালু করুন"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"না থাক"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ব্যবহার হচ্ছে"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"অ্যাপ্লিকেশনগুলি আপনার <xliff:g id="TYPES_LIST">%s</xliff:g> ব্যবহার করছে।"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string> <string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"এক্সটার্নাল ডিসপ্লেতে মিরর করবেন?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"ডিসপ্লে দেখান"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"বাতিল করুন"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index f320d400a0d1..db5987fb869a 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Snimanje ekrana"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Započnite"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavite"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Snimite problem"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Pokrenite"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zaustavite"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Koji dio uređaja je imao problem?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje ekrana"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performanse"</item> + <item msgid="1627504621139124393">"Korisnički interfejs"</item> + <item msgid="8309220355268900335">"Baterija"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Prevucite ulijevo da pokrenete zajednički vodič"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otvaranje uređivača vidžeta"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Uklanjanje"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajte vidžet"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Dodirnite da zakažete Uštedu baterije"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Uključite ako je vjerovatno da će se baterija istrošiti"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji SysUI mem."</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"U upotrebi"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string> <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Preslikati na vanjski ekran?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Bilo koja trenutno pokrenuta aktivnost na dvostrukom ekranu se zaustaviti"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Ekran je povezan"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index a8e908f83c16..af4492bbb6b3 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravació de pantalla"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inicia"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Atura"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Registra el problema"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Inicia"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Atura"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"L\'experiència amb el dispositiu s\'ha vist afectada?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipus de problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravació de pantalla"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Rendiment"</item> + <item msgid="1627504621139124393">"Interfície d\'usuari"</item> + <item msgid="8309220355268900335">"Bateria"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • S\'està carregant • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Llisca cap a l\'esquerra per iniciar el tutorial de la comunitat"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Obre l\'editor de widgets"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Suprimeix"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Afegeix un widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fet"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Toca per programar l\'estalvi de bateria"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Activa\'l quan sigui probable que et quedis sense bateria"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No, gràcies"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Aboca el monticle de SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En ús"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Algunes aplicacions estan fent servir el següent: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string> <string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Replicar a la pantalla externa?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Qualsevol activitat de pantalla dual que s\'estigui executant en aquests moments s\'aturarà"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Replica la pantalla"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Ignora"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Pantalla connectada"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 79aa0291814a..25fcf99ffd21 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rekordér obrazovky"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Spustit"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončit"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Zaznamenat problém"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Spustit"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Ukončit"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Co v zařízení bylo ovlivněno?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte druh problém"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Záznam obrazovky"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Výkon"</item> + <item msgid="1627504621139124393">"Uživatelské rozhraní"</item> + <item msgid="8309220355268900335">"Baterie"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Přejetím doleva spustíte komunitní výukový program"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otevřít editor widgetů"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstranit"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Přidat widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hotovo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbalovací nabídka"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Klepnutím naplánujete aktivování spořiče baterie"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Zapnout, když bude pravděpodobné, že se vybije baterie"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, díky"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Výpis haldy SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Používá se"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikace využívají tato oprávnění: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string> <string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Zrcadlit na externí displej?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Běžící aktivita Dual Screen bude ukončena"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Zrcadlit displej"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Zavřít"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Displej připojen"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index b418ce81e7a8..91c223a7ed50 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -200,7 +200,7 @@ <string name="accessibility_bluetooth_device_settings_see_all" msgid="9111952496905423543">"Klik for at se alle enheder"</string> <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="2435184865793496966">"Klik for at parre en ny enhed"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriniveauet er ukendt."</string> - <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tilsluttet <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> + <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Forbundet med <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> <string name="accessibility_cast_name" msgid="7344437925388773685">"Forbundet til <xliff:g id="CAST">%s</xliff:g>."</string> <string name="accessibility_not_connected" msgid="4061305616351042142">"Ikke tilsluttet."</string> <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string> @@ -293,8 +293,8 @@ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Administrer brugere"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Udfør"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Luk"</string> - <string name="quick_settings_connected" msgid="3873605509184830379">"Tilsluttet"</string> - <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Tilsluttet – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="quick_settings_connected" msgid="3873605509184830379">"Forbundet"</string> + <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Forbundet – batteriniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="quick_settings_connecting" msgid="2381969772953268809">"Opretter forbindelse…"</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Aktiverer…"</string> @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skærmoptagelse"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Optag problem"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del af din enhedsoplevelse blev påvirket?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vælg problemtype"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skærmoptagelse"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Ydeevne"</item> + <item msgid="1627504621139124393">"Brugerflade"</item> + <item msgid="8309220355268900335">"Batteri"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndstilstand"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Stryg mod venstre for at starte den fælles vejledning"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Åbn redigeringsværktøjet til widgets"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tilføj widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Udfør"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullemenu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tryk for at fastsætte en tidsplan for batterisparefunktionen"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Aktivér, når det ser ud til, at batteriet løber tør"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nej tak"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Gem SysUI-heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"I brug"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps anvender enhedens <xliff:g id="TYPES_LIST">%s</xliff:g>"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string> <string name="install_app" msgid="5066668100199613936">"Installer app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du spejle til ekstern skærm?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Al aktivitet, der i øjeblikket anvender funktioner til brug af to skærme, stoppes"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Spejl skærm"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Luk"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Skærmen er tilsluttet"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index a6bc4d4c1b13..29b70184b82b 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -253,7 +253,7 @@ <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Keine gekoppelten Geräte verfügbar"</string> <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Zum Verbinden oder Trennen eines Geräts tippen"</string> <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Neues Gerät koppeln"</string> - <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Alle ansehen"</string> + <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Alle anzeigen"</string> <string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth verwenden"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Verbunden"</string> <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Gespeichert"</string> @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Bildschirmaufzeichnung"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Beenden"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Problem aufnehmen"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Aufnahme starten"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Aufnahme beenden"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Welche Bereiche des Geräts waren betroffen?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Art des Problems auswählen"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Bildschirmaufnahme"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Leistung"</item> + <item msgid="1627504621139124393">"Benutzeroberfläche"</item> + <item msgid="8309220355268900335">"Akku"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhandmodus"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Wische nach links, um das gemeinsame Tutorial zu starten"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Widget-Editor öffnen"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Entfernen"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget hinzufügen"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fertig"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tippen zum Planen des Energiesparmodus"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Aktivieren, wenn der Akku wahrscheinlich nicht mehr lange hält"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nein danke"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In Verwendung"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps verwenden gerade Folgendes: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string> <string name="install_app" msgid="5066668100199613936">"App installieren"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Auf externen Bildschirm spiegeln?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Alle momentan ausgeführten Dual-Screen-Aktivitäten werden angehalten"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Bildschirm spiegeln"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Schließen"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Bildschirm verbunden"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index dd6422bc192d..dd24ca678f1a 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Εγγραφή οθόνης"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Έναρξη"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Διακοπή"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Εγγραφή προβλήματος"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Έναρξη"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Διακοπή"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ποιο κομμάτι της εμπειρίας συσκευής επηρεάστηκε;"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Επιλογή τύπου προβλήματος"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Εγγραφή οθόνης"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Απόδοση"</item> + <item msgid="1627504621139124393">"Διεπαφή χρήστη"</item> + <item msgid="8309220355268900335">"Μπαταρία"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Σύρετε προς τα αριστερά για να ξεκινήσετε τον κοινόχρηστο οδηγό"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Άνοιγμα προγράμ. επεξεργασίας γραφικών στοιχείων"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Κατάργηση"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Προσθήκη γραφικού στοιχείου"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Τέλος"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"αναπτυσσόμενο μενού"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Πατήστε για προγραμματισμό της Εξοικονόμησης μπαταρίας"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Ενεργοποίηση όταν υπάρχει σημαντική πιθανότητα εξάντλησης της μπαταρίας"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Όχι, ευχαριστώ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Στιγμ. μνήμης SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Χρησιμοποιείται"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Οι εφαρμογές χρησιμοποιούν τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string> <string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Κατοπτρισμός σε εξωτερική οθόνη;"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Τυχόν τρέχουσα δραστηριότητα Dual Screen θα διακοπεί"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Κατοπτρισμός οθόνης"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Παράβλεψη"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Η οθόνη είναι συνδεδεμένη"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 46cdc0f6ca46..2d052919c5b1 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -333,6 +333,14 @@ <string name="qs_record_issue_label" msgid="8166290137285529059">"Record issue"</string> <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string> <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performance"</item> + <item msgid="1627504621139124393">"User interface"</item> + <item msgid="8309220355268900335">"Battery"</item> + </string-array> <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> @@ -861,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tap to schedule Battery Saver"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No, thanks"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1201,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Any dual screen activity currently running will be stopped"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Display connected"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 9acd568b71b0..c043b2c50972 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -333,6 +333,14 @@ <string name="qs_record_issue_label" msgid="8166290137285529059">"Record Issue"</string> <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string> <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performance"</item> + <item msgid="1627504621139124393">"User Interface"</item> + <item msgid="8309220355268900335">"Battery"</item> + </string-array> <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> @@ -861,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tap to schedule Battery Saver"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No thanks"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1201,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Any dual screen activity currently running will be stopped"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Display connected"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 46cdc0f6ca46..2d052919c5b1 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -333,6 +333,14 @@ <string name="qs_record_issue_label" msgid="8166290137285529059">"Record issue"</string> <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string> <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performance"</item> + <item msgid="1627504621139124393">"User interface"</item> + <item msgid="8309220355268900335">"Battery"</item> + </string-array> <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> @@ -861,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tap to schedule Battery Saver"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No, thanks"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1201,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Any dual screen activity currently running will be stopped"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Display connected"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 46cdc0f6ca46..2d052919c5b1 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -333,6 +333,14 @@ <string name="qs_record_issue_label" msgid="8166290137285529059">"Record issue"</string> <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string> <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performance"</item> + <item msgid="1627504621139124393">"User interface"</item> + <item msgid="8309220355268900335">"Battery"</item> + </string-array> <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> @@ -861,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tap to schedule Battery Saver"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No, thanks"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1201,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Any dual screen activity currently running will be stopped"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Display connected"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 9cd30143e015..3691b2c3aaf0 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -333,6 +333,14 @@ <string name="qs_record_issue_label" msgid="8166290137285529059">"Record Issue"</string> <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string> <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performance"</item> + <item msgid="1627504621139124393">"User Interface"</item> + <item msgid="8309220355268900335">"Battery"</item> + </string-array> <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> @@ -861,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tap to schedule Battery Saver"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Turn on when battery is likely to run out"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No thanks"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In use"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1201,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Any dual screen activity currently running will be stopped"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Dismiss"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Display connected"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 4be14e9b90dc..6a4818e1f3e1 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Grabación de pantalla"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Grabar error"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Detener"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu exp. del disp. se vio afectada?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Seleccionar tipo de problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabadora de pant."</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Rendimiento"</item> + <item msgid="1627504621139124393">"Interfaz de usuario"</item> + <item msgid="8309220355268900335">"Batería"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Desliza el dedo a la izquierda para iniciar el instructivo comunal"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir el editor de widget"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Agregar widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Listo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú expandible"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Presiona para programar el Ahorro de batería"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Actívalo cuando la batería se esté por acabar"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No, gracias"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar pila de SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En uso"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que están usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string> <string name="install_app" msgid="5066668100199613936">"Instalar app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Quieres duplicar en la pantalla externa?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Se detendrá cualquier actividad en la pantalla doble que se esté ejecutando en ese momento."</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Duplicar pantalla"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Descartar"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Pantalla conectada"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 5d88d643fe50..4e41db3ef4b1 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -252,7 +252,7 @@ <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string> <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hay dispositivos vinculados disponibles"</string> <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toca para conectar o desconectar un dispositivo"</string> - <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Empareja un nuevo dispositivo"</string> + <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Emparejar un nuevo dispositivo"</string> <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Ver todos"</string> <string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectado"</string> @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Grabar pantalla"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Problema de grabación"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Detener"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu experiencia se ha visto afectada?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipo de problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabar pantalla"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Rendimiento"</item> + <item msgid="1627504621139124393">"Interfaz de usuario"</item> + <item msgid="8309220355268900335">"Batería"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • Carga completa en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Desliza hacia la izquierda para iniciar el tutorial de la comunidad"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir editor de widgets"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Añadir widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hecho"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tocar para programar el modo Ahorro de batería"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Activar cuando sea probable que se quede sin batería"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No, gracias"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar montículo de SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En uso"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que usan tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string> <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Proyectar a pantalla externa?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Cualquier actividad de pantalla dual que se esté ejecutando en estos momentos se detendrá"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Proyectar pantalla"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Cerrar"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Pantalla conectada"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 258bd4deab2d..231ddebb7b8a 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekraanisalvestus"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Alustage"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Peatage"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Probleemi salvestamine"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Alusta"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Peata"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Millist seadme kasutuskogemuse osa see mõjutas?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valige probleemi tüüp"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekraanisalvestus"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Toimivus"</item> + <item msgid="1627504621139124393">"Kasutajaliides"</item> + <item msgid="8309220355268900335">"Aku"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ühekäerežiim"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrastsus"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Tavaline"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Ühise õpetuse käivitamiseks pühkige vasakule"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Vidina redaktori avamine"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Eemalda"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisa vidin"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Valmis"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rippmenüü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Puudutage akusäästja ajastamiseks"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Lülitatakse sisse, kui aku hakkab tühjaks saama"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Tänan, ei"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Kasutusel"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Rakendused kasutavad järgmisi: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string> <string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kas peegeldada välisekraanile?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Kõik praegu käimas olevad kahe ekraaniga tegevused peatatakse"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Peegelda ekraani"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Loobu"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Kuvar on ühendatud"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 54290f77d1a8..20bf71b0a6a3 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Pantaila-grabaketa"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hasi"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Gelditu"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Arazo bat dago grabaketarekin"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Hasi"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Gelditu"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Gailuaren erabileraren zer alderdiri eragin dio?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Hautatu arazo mota"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pantaila-grabagailua"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Errendimendua"</item> + <item msgid="1627504621139124393">"Erabiltzaile-interfazea"</item> + <item msgid="8309220355268900335">"Bateria"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Tutorial komuna hasteko, pasatu hatza ezkerrera"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Ireki widget-editorea"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Kendu"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Gehitu widget bat"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Eginda"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"zabaldu menua"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Sakatu bateria-aurreztailea noiz aktibatu programatzeko"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Aktibatu aurreztailea bateria agortzeko arriskua dagoenean"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ez, eskerrik asko"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Erabiltzen ari da"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikazio batzuk <xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari dira."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string> <string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kanpoko pantailan islatu nahi duzu?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Une honetan exekutatzen ari diren pantaila bikoitzeko jarduera guztiak geldituko dira"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Islatu pantaila"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Baztertu"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Konektatutako pantaila"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 03058879b876..e161d7adb35f 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ضبط صفحهنمایش"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"متوقف کردن"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ضبط مشکل"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"شروع"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"توقف"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"کدام بخش تجربه استفاده از دستگاه تحتتأثیر قرار گرفت؟"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"انتخاب نوع مشکل"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ضبط صفحهنمایش"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"عملکرد"</item> + <item msgid="1627504621139124393">"واسط کاربر"</item> + <item msgid="8309220355268900335">"باتری"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ شدن • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"برای شروع آموزش گامبهگام عمومی، تند بهچپ بکشید"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"باز کردن ویرایشگر ابزارک"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"برداشتن"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"افزودن ابزارک"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"تمام"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"منوی پایینپر"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامهها و دادههای این جلسه حذف خواهد شد."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"برای زمانبندی «بهینهسازی باتری» ضربه بزنید"</string> <string name="auto_saver_text" msgid="3214960308353838764">"وقتی باتری روبهاتمام است، بهینهسازی باتری را روشن کنید"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"نه متشکرم"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"استفاده شده"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"برنامهها از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده میکنند."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string> @@ -1206,9 +1207,10 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"حضور کاربر شناسایی میشود"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیشفرض یادداشت را در «تنظیمات» تنظیم کنید"</string> <string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string> - <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"در نمایشگر خارجی پخش شود؟"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"همه فعالیتهای Dual Screen که درحال اجرا است متوقف خواهد شد"</string> - <string name="mirror_display" msgid="2515262008898122928">"بازتاباندن صفحهنمایش"</string> + <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"روی نمایشگر خارجی قرینهسازی شود؟"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> + <string name="mirror_display" msgid="2515262008898122928">"قرینهسازی نمایشگر"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"بستن"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"نمایشگر متصل شد"</string> <string name="privacy_dialog_title" msgid="7839968133469098311">"میکروفون و دوربین"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index ae92aaab4ff0..240607b5ebba 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Näytön tallennus"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Aloita"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Lopeta"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Tallenna ongelma"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Aloita"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Lopeta"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Mitä osaa käyttökokemuksesta ongelma koski?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valitse ongelman tyyppi"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Näytön tallentaja"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Suorituskyky"</item> + <item msgid="1627504621139124393">"Käyttöliittymä"</item> + <item msgid="8309220355268900335">"Akku"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Yhden käden moodi"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrasti"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Tavallinen"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Aloita yhteisöesittely pyyhkäisemällä vasemmalle"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Avaa widgetien muokkaaja"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Poista"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisää widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Valmis"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Ajoita virransäästö napauttamalla"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Ota käyttöön, jos akku todennäköisesti loppuu"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ei kiitos"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Luo SysUI-keon vedos"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Käytössä"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"<xliff:g id="TYPES_LIST">%s</xliff:g> ovat sovellusten käytössä."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string> <string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Peilataanko ulkoiselle näytölle?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Kaikki käynnissä oleva kahden näytön toiminta lopetetaan"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Peilaa näyttö"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Ohita"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Näyttö yhdistetty"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index fc4c22f4fe50..82a56f5511ca 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -265,7 +265,7 @@ <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string> <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Prothèses auditives"</string> <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation en cours…"</string> - <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation automatique"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation auto"</string> <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string> <string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string> <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Écran de veille"</string> @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Enregistrement d\'écran"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Rapporter le problème"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Commencer"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Arrêter"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quelle composante de l\'appareil a été affectée?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionner un type"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement écran"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performance"</item> + <item msgid="1627504621139124393">"Interface utilisateur"</item> + <item msgid="8309220355268900335">"Pile"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode Une main"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge en cours… • Se terminera dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Balayer l\'écran vers la gauche pour démarrer le tutoriel communautaire"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Ouvrir l\'éditeur de widget"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Terminé"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Toucher pour activer la fonction Économiseur de pile"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Activer si la pile est susceptible de s\'épuiser totalement"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Non merci"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Copier mémoire SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En cours d\'utilisation"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string> <string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer l\'écran sur un moniteur externe?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Fermer"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml index 8df62113b674..b96984173d37 100644 --- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml @@ -147,7 +147,7 @@ <item msgid="8998632451221157987">"Activé"</item> </string-array> <string-array name="tile_states_controls"> - <item msgid="8199009425335668294">"Non disponible"</item> + <item msgid="8199009425335668294">"Non disponibles"</item> <item msgid="4544919905196727508">"Désactivées"</item> <item msgid="3422023746567004609">"Activées"</item> </string-array> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 462ee6c0d4c4..c35f9eeaadff 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Enregistrement de l\'écran"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Enregistrer le problème"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Début"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Arrêter"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quel problème avez-vous rencontré avec votre appareil ?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionnez un type de problème"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement de l\'écran"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performances"</item> + <item msgid="1627504621139124393">"Interface utilisateur"</item> + <item msgid="8309220355268900335">"Batterie"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode une main"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge • Temps restant : <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Balayer vers la gauche pour démarrer le tutoriel collectif"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Ouvrir l\'éditeur de widgets"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Supprimer"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"OK"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Appuyez ici pour programmer l\'économiseur de batterie"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Activer l\'économiseur de batterie si l\'autonomie restante risque d\'être insuffisante"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Non, merci"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Copier mémoire SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En cours d\'utilisation"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string> <string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer sur l\'écran externe ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Toute activité en cours sur double écran sera interrompue."</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Fermer"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Écran connecté"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index bfbb82526882..9cf968e883c3 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravar pantalla"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Deter"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Rexistrar problema"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Deter"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cal foi o problema na experiencia co dispositivo?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona o tipo de problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravación de pant."</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Rendemento"</item> + <item msgid="1627504621139124393">"Interface de usuario"</item> + <item msgid="8309220355268900335">"Batería"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo dunha soa man"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Contraste"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Nivel estándar"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Pasa o dedo cara á esquerda para iniciar o titorial comunitario"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir o editor de widgets"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engadir widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Feito"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú despregable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tocar para programar a función Aforro de batería"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Activa a función se prevés que a batería pode esgotarse"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Non, grazas"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Baleirado mem. SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"En uso"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hai aplicacións que están utilizando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string> <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Queres proxectar contido nunha pantalla externa?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Deterase toda a actividade que se estea executando nunha pantalla dual"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Proxectar pantalla"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Pechar"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Pantalla conectada"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 4095f71e90f0..df7b203a0deb 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"સ્ક્રીન રેકૉર્ડ"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"શરૂ કરો"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"રોકો"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"રેકોર્ડિંગમાં સમસ્યા"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"શરૂ કરો"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"રોકો"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ડિવાઇસ સંબંધી તમારા અનુભવના કયા ભાગને અસર થઈ હતી?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"સમસ્યાનો પ્રકાર પસંદ કરો"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"સ્ક્રીન રેકોર્ડ કરો"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"પર્ફોર્મન્સ"</item> + <item msgid="1627504621139124393">"યૂઝર ઇન્ટરફેસ"</item> + <item msgid="8309220355268900335">"બૅટરી"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં પૂરું ચાર્જ થઈ જશે"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"કૉમ્યુનલ ટ્યૂટૉરિઅલ શરૂ કરવા માટે ડાબે સ્વાઇપ કરો"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"વિજેટ એડિટર ખોલો"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"કાઢી નાખો"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"વિજેટ ઉમેરો"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"થઈ ગયું"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"પુલડાઉન મેનૂ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"બૅટરી સેવર શેડ્યૂલ કરવા માટે ટૅપ કરો"</string> <string name="auto_saver_text" msgid="3214960308353838764">"જ્યારે બૅટરી સંભવિત રૂપે પૂરી થવામાં હોય ત્યારે બૅટરી સેવર ચાલુ કરો"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"ના, આભાર"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ઉપયોગમાં છે"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ઍપ્લિકેશન તમારા <xliff:g id="TYPES_LIST">%s</xliff:g>નો ઉપયોગ કરી રહી છે."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string> <string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"શું બાહ્ય ડિસ્પ્લે પર મિરર કરીએ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"હાલમાં ડ્યૂઅલ સ્ક્રીન પર ચાલી રહેલી કોઈપણ પ્રવૃત્તિ રોકવામાં આવશે"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"મિરર ડિસ્પ્લે"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"છોડી દો"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Display કનેક્ટેડ છે"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 6db1f083591b..eec3078af9fb 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"स्क्रीन रिकॉर्डर"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"शुरू करें"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोकें"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"समस्या रिकॉर्ड करें"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"शुरू करें"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"रोकें"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"आपके डिवाइस की कौनसी सुविधा पर असर पड़ा था?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्या का टाइप चुनें"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रिकॉर्डर"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"परफ़ॉर्मेंस"</item> + <item msgid="1627504621139124393">"यूज़र इंटरफ़ेस"</item> + <item msgid="8309220355268900335">"बैटरी"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"कम्यूनिटी ट्यूटोरियल शुरू करने के लिए, बाईं ओर स्वाइप करें"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"विजेट एडिटर खोलें"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाएं"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोड़ें"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"हो गया"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेन्यू"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सेशन के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"बैटरी सेवर शेड्यूल करने के लिए टैप करें"</string> <string name="auto_saver_text" msgid="3214960308353838764">"जब बैटरी खत्म होने वाली हो तब \'बैटरी सेवर\' चालू करें"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"जी नहीं, शुक्रिया"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"इस्तेमाल किया जा रहा है"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ऐप्लिकेशन आपकी <xliff:g id="TYPES_LIST">%s</xliff:g> का इस्तेमाल कर रहे हैं."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string> <string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"क्या आपको किसी बाहरी डिवाइस पर डिसप्ले करना है?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"ड्यूअल स्क्रीन पर चल रही गतिविधि बंद हो जाएगी"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"डिसप्ले करें"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"खारिज करें"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"डिसप्ले कनेक्ट किया गया"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index d14f9a705980..f0ed40036156 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Snimanje zaslona"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Početak"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavi"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Zabilježi poteškoću"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Početak"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zaustavi"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na koji dio doživljaja na uređaju to utjecalo?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje zaslona"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Izvedba"</item> + <item msgid="1627504621139124393">"Korisničko sučelje"</item> + <item msgid="8309220355268900335">"Baterija"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Prijeđite prstom ulijevo da biste pokrenuli zajednički vodič"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otvaranje alata za uređivanje widgeta"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući izbornik"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Izbrisat će se sve aplikacije i podaci u ovoj sesiji."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Dodirnite za zakazivanje štednje baterije"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Uključite kad bi se baterija mogla isprazniti"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji mem. SysUI-a"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"U upotrebi"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string> <string name="install_app" msgid="5066668100199613936">"Instalacija"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li zrcaliti na vanjski zaslon?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Sva aktivnost dvostrukog zaslona koja je u tijeku će se zaustaviti"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Zrcaljenje zaslona"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Odbaci"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Zaslon je povezan"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 1c4e00fc59e8..30d296190f6a 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Képernyőrögzítés"</string> <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> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Probléma rögzítése"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Indítás"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Leállítás"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Az eszközhasználati élmény mely része érintett?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problématípus kiválasztása"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Képernyőrögzítés"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Teljesítmény"</item> + <item msgid="1627504621139124393">"Kezelőfelület"</item> + <item msgid="8309220355268900335">"Akkumulátor"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Egykezes mód"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontraszt"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Normál"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Csúsztasson gyorsan balra a közösségi útmutató elindításához"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"A modulszerkesztő megnyitása"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Eltávolítás"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Modul hozzáadása"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Kész"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"lehúzható menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Koppintson az akkumulátorkímélő mód ütemezéséhez"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Kapcsolja be, ha az akkumulátor hamarosan lemerül"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nem"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI-memória-kiírás"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Használatban"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Több alkalmazás használja a következőket: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string> <string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tükrözi a kijelzőt a külső képernyőre?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"A jelenleg futó kétképernyős tevékenységek le fognak állni"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Kijelző tükrözése"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Elvetés"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Kijelző csatlakoztatva"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 1cfed6d3e064..bbdeb1683c64 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Էկրանի տեսագրում"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Սկսել"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Կանգնեցնել"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Ձայնագրել"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Սկսել"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Կանգնեցնել"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Սարքի ո՞ր մասի հետ է կապված խնդիրը։"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Ընտրեք խնդրի տեսակը"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Էկրանի տեսագրում"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Աշխատանք"</item> + <item msgid="1627504621139124393">"Միջերես"</item> + <item msgid="8309220355268900335">"Մարտկոց"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Թերթեք ձախ՝ ուղեցույցը գործարկելու համար"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Բացել վիջեթների խմբագրիչը"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Հեռացնել"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ավելացնել վիջեթ"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Պատրաստ է"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"իջնող ընտրացանկ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Հպեք՝ մարտկոցի տնտեսման ռեժիմը կարգավորելու համար"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Միացնել էներգախնայումը, երբ մարտկոցի լիցքը գրեթե սպառված է"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ոչ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Օգտագործվում է"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Հավելվածներն օգտագործում են ձեր <xliff:g id="TYPES_LIST">%s</xliff:g>:"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string> <string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Հայելապատճենե՞լ արտաքին էկրանին"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"Հայելապատճենել էկրանը"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Փակել"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 65c7c1d647ab..f2ed0e7f9159 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Perekam layar"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mulai"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Mencatat Masalah"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Mulai"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Berhenti"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bagian pengalaman perangkat mana yang terpengaruh?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Perekaman layar"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performa"</item> + <item msgid="1627504621139124393">"Antarmuka Pengguna"</item> + <item msgid="8309220355268900335">"Baterai"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengisi daya • Penuh dalam waktu <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Geser ke kiri untuk memulai tutorial komunal"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Buka editor widget"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Hapus"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Selesai"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pulldown"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data dalam sesi ini akan dihapus."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Ketuk untuk menjadwalkan Penghemat Baterai"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Aktifkan jika daya baterai kemungkinan akan habis"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Tidak, terima kasih"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Hapus Heap SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Sedang digunakan"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string> <string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Cerminkan ke layar eksternal?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Aktivitas dua layar yang sedang berjalan akan dihentikan"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Cerminkan layar"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Tutup"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Layar terhubung"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 29b149d832af..f1f1b0f5cbfc 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skjáupptaka"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hefja"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stöðva"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Vandamál tengt upptöku"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Byrja"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stöðva"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvað í tækjaupplifuninni varð fyrir áhrifum?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Veldu gerð vandamáls"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjáupptaka"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Afköst"</item> + <item msgid="1627504621139124393">"Notandaviðmót"</item> + <item msgid="8309220355268900335">"Rafhlaða"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhent stilling"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Birtuskil"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Staðlað"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Í hleðslu • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Strjúktu til vinstri til að hefja samfélagsleiðsögnina"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Opna græjuritilinn"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjarlægja"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Bæta græju við"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Lokið"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Fellivalmynd"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Pikka til að stilla rafhlöðusparnað"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Kveikja þegar rafhlaða er við það að klárast"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nei, takk"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Vista SysUI-gögn"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Í notkun"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Forrit eru að nota <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string> <string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spegla yfir á ytri skjá?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Virkni sem kann að vera í gangi á tveimur skjám verður stöðvuð"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Spegla skjá"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Hunsa"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Skjár tengdur"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 733b0b6df40f..223e39faef37 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Registrazione dello schermo"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inizia"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Interrompi"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Registra problema"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Avvia"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Interrompi"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quali problemi ha l\'esperienza del dispositivo?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Seleziona il tipo di problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Regis. dello schermo"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Prestazioni"</item> + <item msgid="1627504621139124393">"Interfaccia utente"</item> + <item msgid="8309220355268900335">"Batteria"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • In carica • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Scorri a sinistra per iniziare il tutorial della community"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Apri l\'editor del widget"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Rimuovi"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Aggiungi widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fine"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu a discesa"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tocca per programmare il Risparmio energetico"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Attiva questa funzionalità se è probabile che la batteria si scarichi"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"No, grazie"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump heap SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In uso"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string> <string name="install_app" msgid="5066668100199613936">"Installa app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vuoi eseguire il mirroring al display esterno?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Qualsiasi attività in modalità Dual Screen in esecuzione viene interrotta"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Esegui il mirroring del display"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Chiudi"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Display collegato"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 7072a322e541..44fd608df981 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"הקלטת המסך"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"התחלה"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"עצירה"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"תיעוד הבעיה"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"התחלה"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"עצירה"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"איזה חלק בחוויית השימוש שלך במכשיר הושפע?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"בחירה בסוג הבעיה"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"הקלטת המסך"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"ביצועים"</item> + <item msgid="1627504621139124393">"ממשק משתמש"</item> + <item msgid="8309220355268900335">"סוללה"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • בטעינה • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> עד לסיום"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"אפשר להחליק שמאלה כדי להפעיל את המדריך המשותף"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"פתיחה של הכלי לעריכת ווידג\'טים"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"הסרה"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"הוספת ווידג\'ט"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"סיום"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"תפריט במשיכה למטה"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"יש להקיש כדי לתזמן את מצב החיסכון בסוללה"</string> <string name="auto_saver_text" msgid="3214960308353838764">"מומלץ להפעיל את התכונה כשיש סבירות גבוהה שהסוללה תתרוקן"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"לא תודה"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"בשימוש"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"אפליקציות משתמשות ב<xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -938,7 +939,7 @@ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"העברה מהשוליים והצגה"</string> <string name="accessibility_floating_button_action_remove_menu" msgid="6730432848162552135">"הסרה"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"החלפת מצב"</string> - <string name="quick_controls_title" msgid="6839108006171302273">"פקדי מכשירים"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"לחצני מכשירים"</string> <string name="controls_providers_title" msgid="6879775889857085056">"יש לבחור אפליקציה כדי להוסיף פקדים"</string> <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{נוסף אמצעי בקרה אחד (#).}one{נוספו # אמצעי בקרה.}two{נוספו # אמצעי בקרה.}other{נוספו # אמצעי בקרה.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"הוסר"</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string> <string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"לשקף למסך חיצוני?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"כל פעילות של מסך מפוצל שרצה כרגע תופסק"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"תצוגת מראה"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"סגירה"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"המסך מחובר"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index ca68f66be790..38f2dc86e94c 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"スクリーン レコード"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"録音に関する問題"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"開始"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"停止"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"デバイスのどの部分が影響を受けましたか?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"問題の種類を選択する"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"スクリーン レコード"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"パフォーマンス"</item> + <item msgid="1627504621139124393">"ユーザー インターフェース"</item> + <item msgid="8309220355268900335">"バッテリー"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 充電中 • フル充電まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"左にスワイプすると、コミュニティ チュートリアルが開始します"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ウィジェット エディタを開く"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"削除"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ウィジェットを追加"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完了"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"プルダウン メニュー"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"タップしてバッテリー セーバーのスケジュールを設定"</string> <string name="auto_saver_text" msgid="3214960308353838764">"電池切れになる可能性が高くなると有効になります"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"いいえ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ヒープのダンプ"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"使用中"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"アプリは<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しています。"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string> <string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"外部ディスプレイにミラーリングしますか?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"現在実行中のデュアル スクリーンのアクティビティは停止されます"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ディスプレイをミラーリングする"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"閉じる"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ディスプレイに接続しました"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index cc6f2826aa5c..bb21f3f9f75f 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ეკრანის ჩანაწერი"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"დაწყება"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"შეწყვეტა"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ჩაწერასთან დაკავშირებული პრობლემა"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"დაწყება"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"გაჩერება"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"თქვენი მოწყობილობის გამოცდილების რა ნაწილზე მოხდა ზეგავლენა?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"აირჩიეთ პრობლემის ტიპი"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ეკრანის ჩანაწერი"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"ეფექტურობა"</item> + <item msgid="1627504621139124393">"სამომხმარებლო ინტერფეისი"</item> + <item msgid="8309220355268900335">"ბატარეა"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • იტენება • სრულ დატენვამდე <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"გადაფურცლეთ მარცხნივ, რათა დაიწყოთ საერთო სახელმძღვანელო"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"გახსენით ვიჯეტის რედაქტორი"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"ამოშლა"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ვიჯეტის დამატება"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"მზადაა"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ჩამოშლადი მენიუ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"შეეხეთ ბატარეის დამზოგის დასაგეგმად"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ჩაირთოს, როცა ბატარეა დაცლის პირას არის"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"არა, გმადლობთ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI გროვის გამოტანა"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"გამოიყენება"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"აპლიკაციების მიერ გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string> <string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"აირეკლოს გარე ეკრანზე?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"ორმაგ ეკრანზე ნებისმიერი მიმდინარე აქტივობა შეჩერდება"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ეკრანის არეკვლა"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"დახურვა"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ეკრანი დაკავშირებულია"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 2a9be81ee882..b39d5a553b86 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Экранды жазу"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Бастау"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Тоқтату"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Ақауды жазу"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Бастау"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Тоқтату"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Құрылғы қызметінің қандай түріне әсер етті?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Мәселе түрін таңдаңыз."</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экранды жазу"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Өнімділік"</item> + <item msgid="1627504621139124393">"Пайдаланушы интерфейсі"</item> + <item msgid="8309220355268900335">"Батарея"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядталып жатыр. • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Ортақ оқулықты ашу үшін солға қарай сырғытыңыз."</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Виджет редакторын ашу"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Өшіру"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет қосу"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Дайын"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ашылмалы мәзір"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданба мен дерек жойылады."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Түймені түртіп, Батареяны үнемдеу режимін реттеңіз"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Батареяның заряды бітуге жақындағанда қосыңыз."</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Жоқ, рақмет"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Қолданыста"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Қолданбаларда <xliff:g id="TYPES_LIST">%s</xliff:g> пайдаланылуда."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string> <string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Сыртқы экран арқылы да көрсету керек пе?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Екі экранда қазір орындалып жатқан кез келген әрекет тоқтатылады."</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Көрсету"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Жабу"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Дисплей қосылды"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index feb3af03e870..e989a9d8b242 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ការថតវីដេអូអេក្រង់"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ចាប់ផ្ដើម"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ឈប់"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"កត់ត្រាបញ្ហា"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"ចាប់ផ្ដើម"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"បញ្ឈប់"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"តើផ្នែកអ្វីនៃបទពិសោធប្រើប្រាស់ឧបករណ៍របស់អ្នកបានរងការប៉ះពាល់?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ជ្រើសរើសប្រភេទបញ្ហា"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ការថតវីដេអូអេក្រង់"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"ប្រតិបត្តិការ"</item> + <item msgid="1627504621139124393">"ផ្ទៃប៉ះ"</item> + <item msgid="8309220355268900335">"ថ្ម"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"អូសទៅឆ្វេង ដើម្បីចាប់ផ្ដើមមេរៀនសហគមន៍"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"បើកកម្មវិធីកែធាតុក្រាហ្វិក"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"ដកចេញ"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"បញ្ចូលធាតុក្រាហ្វិក"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"រួចរាល់"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរអ្នកប្រើ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ម៉ឺនុយទាញចុះ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យទាំងអស់ក្នុងវគ្គនេះនឹងត្រូវលុប។"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ចុចដើម្បីកំណត់កាលវិភាគមុខងារសន្សំថ្ម"</string> <string name="auto_saver_text" msgid="3214960308353838764">"បើកនៅពេលថ្មទំនងជាអស់"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"ទេ អរគុណ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"កំពុងប្រើ"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"កម្មវិធីកំពុងប្រើ <xliff:g id="TYPES_LIST">%s</xliff:g> របស់អ្នក។"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string> <string name="install_app" msgid="5066668100199613936">"ដំឡើងកម្មវិធី"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"បញ្ចាំងទៅផ្ទាំងអេក្រង់ខាងក្រៅឬ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"បច្ចុប្បន្ន រាល់សកម្មភាពអេក្រង់ទ្វេដែលកំពុងដំណើរការនឹងត្រូវបានបញ្ឈប់"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"បញ្ចាំងទៅផ្ទាំងអេក្រង់"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"ច្រានចោល"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ផ្ទាំងអេក្រង់ត្រូវបានភ្ជាប់"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index fa35189cd6fc..39b14685cbca 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ಪ್ರಾರಂಭಿಸಿ"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ನಿಲ್ಲಿಸಿ"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ರೆಕಾರ್ಡ್ ದೋಷ"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"ಪ್ರಾರಂಭಿಸಿ"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"ನಿಲ್ಲಿಸಿ"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ಸಾಧನ ಬಳಸುವಾಗ ನೀವು ಯಾವ ರೀತಿಯ ಸಮಸ್ಯೆ ಎದುರಿಸುತ್ತೀರಿ?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ಸಮಸ್ಯೆಯ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"ಕಾರ್ಯಕ್ಷಮತೆ"</item> + <item msgid="1627504621139124393">"ಬಳಕೆದಾರರ ಇಂಟರ್ಫೇಸ್"</item> + <item msgid="8309220355268900335">"ಬ್ಯಾಟರಿ"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ದಲ್ಲಿ ಪೂರ್ಣಗೊಳ್ಳುತ್ತದೆ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"ಸಮುದಾಯದ ಟ್ಯುಟೋರಿಯಲ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಲು ಎಡಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ವಿಜೆಟ್ ಎಡಿಟರ್ ಅನ್ನು ತೆರೆಯಿರಿ"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"ತೆಗೆದುಹಾಕಿ"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಿ"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ಮುಗಿದಿದೆ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ಪುಲ್ಡೌನ್ ಮೆನು"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಅನ್ನು ನಿಗದಿಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ಬ್ಯಾಟರಿ ಖಾಲಿಯಾಗುವ ಸಾಧ್ಯತೆ ಇದ್ದಾಗ ಆನ್ ಮಾಡಿ"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"ಬೇಡ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ಬಳಕೆಯಲ್ಲಿದೆ"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ನಿಮ್ಮ <xliff:g id="TYPES_LIST">%s</xliff:g> ಅನ್ನು ಆ್ಯಪ್ಗಳು ಬಳಸುತ್ತಿವೆ."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string> <string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಬೇಕೆ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"ಪ್ರಸ್ತುತ ಚಾಲನೆಯಲ್ಲಿರುವ ಯಾವುದೇ ಡ್ಯುಯಲ್ ಸ್ಕ್ರೀನ್ ಚಟುವಟಿಕೆಯನ್ನು ನಿಲ್ಲಿಸಲಾಗುತ್ತದೆ"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ಮಿರರ್ ಡಿಸ್ಪ್ಲೇ"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"ವಜಾಗೊಳಿಸಿ"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ಡಿಸ್ಪ್ಲೇ ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 3ccbed35d3c7..7bd6e6f95e0b 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"화면 녹화"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"시작"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"중지"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"문제 기록"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"시작"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"중지"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"기기 경험의 어떤 부분에 영향이 있었나요?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"문제 유형 선택"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"화면 녹화"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"성능"</item> + <item msgid="1627504621139124393">"사용자 인터페이스"</item> + <item msgid="8309220355268900335">"배터리"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 충전 중 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"공동 튜토리얼을 시작하려면 왼쪽으로 스와이프하세요"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"위젯 편집기 열기"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"삭제"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"위젯 추가"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"완료"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"풀다운 메뉴"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"탭하여 절전 모드 예약"</string> <string name="auto_saver_text" msgid="3214960308353838764">"배터리가 소진될 것 같으면 사용 설정"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"사용 안함"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"사용 중"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"애플리케이션이 <xliff:g id="TYPES_LIST">%s</xliff:g>을(를) 사용 중입니다."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string> <string name="install_app" msgid="5066668100199613936">"앱 설치"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"외부 디스플레이로 미러링하시겠습니까?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"실행 중인 모든 듀얼 화면이 중지됩니다."</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"디스플레이 미러링"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"닫기"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"디스플레이 연결됨"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 76d38096cdcb..d4974e800a4b 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Экранды жаздыруу"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Баштадык"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Токтотуу"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Маселени жаздыруу"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Баштоо"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Токтотуу"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Түзмөгүңүздүн кайсы бөлүгүнө кедергиси тийди?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Маселенин түрүн тандоо"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экрандан видео жаздырып алуу"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Иштин майнаптуулугу"</item> + <item msgid="1627504621139124393">"Колдонуучунун интерфейси"</item> + <item msgid="8309220355268900335">"Батарея"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Кубатталууда • Толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> калды"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Жалпы үйрөткүчтү иштетүү үчүн солго сүрүңүз"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Виджет түзөткүчтү ачуу"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Өчүрүү"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет кошуу"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Бүттү"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ылдый түшүүчү меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана аларга байланыштуу нерселер өчүрүлөт."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Батареяны үнөмдөгүчтүн тартибин жөндөө үчүн басыңыз"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Батареянын кубаты түгөнүп калганда, күйгүзүлсүн"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Жок, рахмат"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Колдонулууда"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Колдонмолор төмөнкүлөрдү пайдаланып жатышат: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string> <string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Тышкы экранга чыгарасызбы?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Учурда иштеп жаткан бардык кош экран аракеттери токтотулат"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Тышкы экран"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Жабуу"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Экран туташтырылды"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index cf5ef3ae55d8..431b77b2ebd9 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ບັນທຶກໜ້າຈໍ"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ເລີ່ມ"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ຢຸດ"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ບັນຫາກ່ຽວກັບການບັນທຶກ"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"ເລີ່ມ"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"ຢຸດ"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ສ່ວນໃດຂອງປະສົບການອຸປະກອນຂອງທ່ານໄດ້ຮັບຜົນກະທົບ?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ເລືອກປະເພດບັນຫາ"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ບັນທຶກໜ້າຈໍ"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"ປະສິດທິພາບ"</item> + <item msgid="1627504621139124393">"ສ່ວນຕິດຕໍ່ຜູ້ໃຊ້"</item> + <item msgid="8309220355268900335">"ແບັດເຕີຣີ"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"ປັດຊ້າຍເພື່ອເລີ່ມບົດແນະນຳສ່ວນກາງ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ເປີດຕົວແກ້ໄຂວິດເຈັດ"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"ລຶບອອກ"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ເພີ່ມວິດເຈັດ"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ແລ້ວໆ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ເມນູແບບດຶງລົງ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯແລະຂໍ້ມູນທັງໝົດໃນເຊດຊັນນີ້ຈະຖືກລຶບອອກ."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ແຕະເພື່ອຕັ້ງການເປີດຕົວປະຢັດແບັດເຕີຣີ"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ເປີດໃຊ້ເມື່ອແບັດເຕີຣີໜ້າຈະໃກ້ໝົດ"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"ບໍ່, ຂອບໃຈ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ກຳລັງນຳໃຊ້ຢູ່"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ແອັບພລິເຄຊັນກຳລັງໃຊ້ <xliff:g id="TYPES_LIST">%s</xliff:g> ຂອງທ່ານ."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string> <string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ສາຍໃສ່ຈໍສະແດງຜົນພາຍນອກບໍ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"ການເຄື່ອນໄຫວໃດກໍຕາມທີ່ກຳລັງດຳເນີນການຢູ່ Dual Screen ຈະຢຸດລົງ"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ຈໍສະແດງຜົນແບບສະທ້ອນ"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"ປິດໄວ້"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ເຊື່ອມຕໍ່ຈໍແລ້ວ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index ddad0bec7ed9..a0eaea2e9aed 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekrano įrašas"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Pradėti"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stabdyti"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Įrašyti problemą"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Pradėti"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stabdyti"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuri įrenginio funkcija buvo paveikta?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pasirinkite problemos tipą"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrano įrašas"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Našumas"</item> + <item msgid="1627504621139124393">"Naudotojo sąsaja"</item> + <item msgid="8309220355268900335">"Akumuliatorius"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienos rankos režimas"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrastas"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Įprastas"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Įkraunama • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Perbraukite kairėn, paleistumėte bendruomenės mokomąją medžiagą"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Atidaryti valdiklio redagavimo programą"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Pašalinti"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridėti valdiklį"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Atlikta"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"išplečiamasis meniu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Palietę planuokite akumuliatoriaus tausojimo priemonės veikimą"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Įjunkite, jei akumuliatorius gali greitai išsekti"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, ačiū"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Pat. „SysUI“ krūvą"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Naudojama"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programos naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string> <string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Bendrinti ekrano vaizdą išoriniame ekrane?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Bet kokia šiuo metu vykdoma dvigubo ekrano veikla bus sustabdyta"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Bendrinti ekrano vaizdą"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Atsisakyti"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Ekranas prijungtas"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 707c656e4fc6..a419f877f075 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekrāna ierakstīšana"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Sākt"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Apturēt"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Problēmas ierakstīšana"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Sākt"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Apturēt"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuras ierīces funkcijas tika ietekmētas?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Atlasiet problēmas veidu"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrāna ierakstīšana"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Veiktspēja"</item> + <item msgid="1627504621139124393">"Lietotāja saskarne"</item> + <item msgid="8309220355268900335">"Akumulators"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienas rokas režīms"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrasts"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standarta"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Notiek uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Velciet pa kreisi, lai palaistu kopienas pamācību."</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Atvērt logrīku redaktoru"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Noņemt"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pievienot logrīku"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gatavs"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"novelkamā izvēlne"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Pieskarieties, lai iestatītu akumulatora enerģijas taupīšanas režīma grafiku"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Ieslēgt, ja akumulators var izlādēties"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nē, paldies"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Pašlaik izmanto"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Lietojumprogrammas izmanto šādas funkcijas: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string> <string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vai spoguļot ārējā displejā?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Visas pašlaik aktīvās divu ekrānu darbības tiks apturētas"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Spoguļot displeju"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Nerādīt"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Pievienots displejs"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 24cd49a7ad29..ca9fe9e91c9b 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Снимање екран"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Започни"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Сопри"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Евидентирајте проблем"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Започнете"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Сопрете"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Кој дел од доживувањето на уредот беше засегнат?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екран"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Изведба"</item> + <item msgid="1627504621139124393">"Кориснички интерфејс"</item> + <item msgid="8309220355268900335">"Батерија"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Повлечете налево за да го започнете заедничкото упатство"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Го отвора уредникот на виџети"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Отстранува"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додајте виџет"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"паѓачко мени"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Допрете за да закажете „Штедач на батерија“"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Вклучи ако е веројатно дека батеријата ќе се испразни"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Не, фала"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Извади SysUI-слика"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Во употреба"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликациите користат <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string> <string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се преслика на надворешниот екран?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Секоја активност што тековно се извршува на Dual Screen ќе се сопре"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Отфрли"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Екранот е поврзан"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 1f153c585220..5ff465672a0b 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"സ്ക്രീൻ റെക്കോർഡ്"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ആരംഭിക്കുക"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"നിര്ത്തുക"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"പ്രശ്നം റെക്കോർഡ് ചെയ്യുക"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"ആരംഭിക്കുക"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"നിർത്തുക"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"നിങ്ങളുടെ ഉപകരണ അനുഭവത്തിന്റെ ഏത് ഭാഗമാണ് ബാധിച്ചത്?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"പ്രശ്ന തരം തിരഞ്ഞെടുക്കുക"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"സ്ക്രീൻ റെക്കോർഡ്"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"പ്രകടനം"</item> + <item msgid="1627504621139124393">"ഉപയോക്തൃ ഇന്റര്ഫേസ്"</item> + <item msgid="8309220355268900335">"ബാറ്ററി"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ചാർജ് ചെയ്യുന്നു • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-ൽ പൂർത്തിയാകും"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"കമ്മ്യൂണൽ ട്യൂട്ടോറിയൽ ആരംഭിക്കാൻ ഇടത്തോട്ട് സ്വൈപ്പ് ചെയ്യുക"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"വിജറ്റ് എഡിറ്റർ തുറക്കുക"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"നീക്കം ചെയ്യുക"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"വിജറ്റ് ചേർക്കുക"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"പൂർത്തിയായി"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ഉപയോക്താവ് മാറുക"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"പുൾഡൗൺ മെനു"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ബാറ്ററി ലാഭിക്കൽ ഷെഡ്യൂൾ ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ബാറ്ററി ചാർജ് തീരാൻ സാധ്യതയുണ്ടെങ്കിൽ ഓണാക്കുക"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"വേണ്ട"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ഹീപ്പ് ഡമ്പ് ചെയ്യുക"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ഉപയോഗത്തിലാണ്"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ആപ്പുകൾ നിങ്ങളുടെ <xliff:g id="TYPES_LIST">%s</xliff:g> ഉപയോഗിക്കുന്നു."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string> <string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ബാഹ്യ ഡിസ്പ്ലേയിലേക്ക് മിറർ ചെയ്യണോ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"നിലവിൽ റൺ ചെയ്യുന്ന ഏതൊരു ഡ്യുവൽ സ്ക്രീൻ ആക്റ്റിവിറ്റിയും നിർത്തും"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"മിറർ ഡിസ്പ്ലേ"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"ഡിസ്മിസ് ചെയ്യുക"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ഡിസ്പ്ലേ കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 91f7180551ff..a71aca289ab5 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Дэлгэцийн үйлдэл бичих"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Эхлүүлэх"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зогсоох"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Асуудлыг бичих"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Эхлүүлэх"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Зогсоох"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Таны төхөөрөмжийн хэрэглээний аль хэсэгт нөлөөлсөн бэ?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Асуудлын төрөл сонгоно уу"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Дэлгэцийн бичлэг"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Гүйцэтгэл"</item> + <item msgid="1627504621139124393">"Хэрэглэгчийн интерфейс"</item> + <item msgid="8309220355268900335">"Батарей"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Нийтийн практик хичээлийг эхлүүлэхийн тулд зүүн тийш шударна уу"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Виджет засварлагчийг нээх"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Хасах"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет нэмэх"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Болсон"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"эвхмэл цэс"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Батарей хэмнэгч онцлогийг хуваарилахын тулд товших"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Батарей дуусах гэж байгаа үед асаана уу"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Үгүй, баярлалаа"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Ашиглаж байгаа"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Аппууд таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string> <string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Гадны дэлгэцэд тусгал үүсгэх үү?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Одоо ажиллаж буй аливаа хос дэлгэцийн үйл ажиллагааг зогсооно"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Дэлгэцийн тусгал үүсгэх"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Хаах"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Дэлгэц холбогдсон"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 39e2c5c6a641..9dfaa00d0e55 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"स्क्रीन रेकॉर्ड"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरू"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"थांबा"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"समस्या रेकॉर्ड करा"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"सुरुवात करा"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"थांबवा"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"तुमच्या डिव्हाइसबाबत कोणत्या अनुभवावर परिणाम झाला?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्येचा प्रकार निवडा"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रेकॉर्ड"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"परफॉर्मन्स"</item> + <item msgid="1627504621139124393">"यूझर इंटरफेस"</item> + <item msgid="8309220355268900335">"बॅटरी"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज होत आहे • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मध्ये पूर्ण होईल"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"सामुदायिक ट्यूटोरियल सुरू करण्यासाठी डावीकडे स्वाइप करा"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"विजेट संपादक उघडा"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"काढून टाका"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोडा"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"पूर्ण झाले"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनू"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अॅप्स आणि डेटा हटवला जाईल."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"बॅटरी सेव्हर शेड्यूल करण्यासाठी टॅप करा"</string> <string name="auto_saver_text" msgid="3214960308353838764">"बॅटरी संपण्याची शक्यता असल्यास सुरू करा"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"नाही नको"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI हीप डंप करा"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"वापरात आहे"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ॲप्लिकेशन्स तुमचे <xliff:g id="TYPES_LIST">%s</xliff:g> वापरत आहे."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अॅप सेट करा"</string> <string name="install_app" msgid="5066668100199613936">"अॅप इंस्टॉल करा"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेवर मिरर करायचे आहे का?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"सध्या सुरू असलेली कोणतीही ड्युअल स्क्रीन अॅक्टिव्हिटी थांबवली जाईल"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर करा"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"डिसमिस करा"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"डिस्प्ले कनेक्ट केला आहे"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 732a18061167..553d221463b9 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rakam skrin"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mula"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Rekodkan masalah"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Mula"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Hentikan"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Pengalaman peranti yang manakah yang terjejas?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rakam skrin"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Prestasi"</item> + <item msgid="1627504621139124393">"Antara Muka Pengguna"</item> + <item msgid="8309220355268900335">"Bateri"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Leret ke kiri untuk memulakan tutorial umum"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Buka editor widget"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Alih keluar"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Selesai"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu tarik turun"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Ketik untuk menjadualkan Penjimat Bateri"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Hidupkan apabila bateri berkemungkinan habis"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Tidak perlu"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"DumpSys"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Sedang digunakan"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi sedang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> anda."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string> <string name="install_app" msgid="5066668100199613936">"Pasang apl"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Paparkan pada paparan luaran?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Sebarang aktiviti dwiskrin yang sedang dijalankan akan dihentikan"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Segerakkan paparan"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Ketepikan"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Paparan disambungkan"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 069a833c18c8..d3f1badbb64b 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"စခရင် ရိုက်ကူးရန်"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"စတင်ရန်"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ရပ်ရန်"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ပြဿနာကို မှတ်တမ်းတင်ခြင်း"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"စတင်ပါ"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"ရပ်ပါ"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"စက်အသုံးပြုမှု၏ မည်သည့်အပိုင်းကို သက်ရောက်သလဲ။"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ပြဿနာအမျိုးအစား ရွေးရန်"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ဖန်သားပြင်ရိုက်ကူးရန်"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"စွမ်းဆောင်ရည်"</item> + <item msgid="1627504621139124393">"သုံးသူအတွက် ကြားခံစနစ်"</item> + <item msgid="8309220355268900335">"ဘက်ထရီ"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • အားသွင်းနေသည် • အားပြည့်ရန် <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> လိုသည်"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"အများသုံးရှင်းလင်းပို့ချချက် စတင်ရန် ဘယ်သို့ပွတ်ဆွဲပါ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ဝိဂျက်တည်းဖြတ်စနစ် ဖွင့်ရန်"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"ဖယ်ရှားရန်"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ဝိဂျက်ထည့်ရန်"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ပြီးပြီ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ဆွဲချမီနူး"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string> @@ -465,7 +467,7 @@ <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"အသံတိတ် အကြောင်းကြားချက်များအားလုံးကို ရှင်းလင်းရန်"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"အကြောင်းကြားချက်များကို \'မနှောင့်ယှက်ရ\' က ခေတ္တရပ်ထားသည်"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ယခု စတင်ပါ"</string> - <string name="empty_shade_text" msgid="8935967157319717412">"အကြောင်းကြားချက်များ မရှိ"</string> + <string name="empty_shade_text" msgid="8935967157319717412">"အကြောင်းကြားချက် မရှိပါ"</string> <string name="no_unseen_notif_text" msgid="395512586119868682">"အကြောင်းကြားချက်သစ် မရှိပါ"</string> <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"အကြောင်းကြားချက်ဟောင်းကြည့်ရန် လော့ခ်ဖွင့်ပါ"</string> <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ဤစက်ပစ္စည်းကို သင့်မိဘက စီမံခန့်ခွဲသည်"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"\'ဘက်ထရီ အားထိန်း\' အချိန်သတ်မှတ်ရန် အတွက် တို့ပါ"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ဘက်ထရီကုန်ခါနီးတွင် ဖွင့်ပါ"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"မလိုပါ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"အသုံးပြုနေသည်"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"အပလီကေးရှင်းများက သင်၏ <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသည်။"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"၊ "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string> <string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ပြင်ပဖန်သားပြင်သို့ စကရင်ပွားမလား။"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"လက်ရှိလုပ်ဆောင်နေသော Dual Screen လုပ်ဆောင်ချက်များ ရပ်သွားပါမည်"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ဖန်သားပြင်ကို စကရင်ပွားရန်"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"ပယ်ရန်"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ဖန်သားပြင်ကို ချိတ်ဆက်လိုက်ပါပြီ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 0b5a0b237ab7..234e725e5164 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skjermopptak"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stopp"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Registrer problem"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stopp"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del av enhetsopplevelsen din ble påvirket?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Velg problemtype"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjermopptak"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Ytelse"</item> + <item msgid="1627504621139124393">"Brukergrensesnitt"</item> + <item msgid="8309220355268900335">"Batteri"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndsmodus"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Sveip til venstre for å starte fellesveiledningen"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Åpne redigeringsverktøyet for moduler"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Legg til modul"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Ferdig"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullegardinmeny"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apper og data i denne økten blir slettet."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Trykk for å planlegge batterisparing"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Slå på når det er sannsynlig at du går tom for batteri"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nei takk"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI-heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"I bruk"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apper bruker <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string> <string name="install_app" msgid="5066668100199613936">"Installer appen"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du speile til en ekstern skjerm?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Eventuell nåværende aktivitet på to skjermer stoppes"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Speil skjermen"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Lukk"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"En skjerm er koblet til"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 9c6ffc59177f..51839dbe5fc7 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -269,8 +269,8 @@ <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रिन स्वतःघुम्ने"</string> <string name="quick_settings_location_label" msgid="2621868789013389163">"लोकेसन"</string> <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"स्क्रिन सेभर"</string> - <string name="quick_settings_camera_label" msgid="5612076679385269339">"क्यामेरा प्रयोग गर्ने अनुमति"</string> - <string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक प्रयोग गर्ने अनुमति"</string> + <string name="quick_settings_camera_label" msgid="5612076679385269339">"क्यामेरा एक्सेस"</string> + <string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक एक्सेस"</string> <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध छ"</string> <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ब्लक गरिएको छ"</string> <string name="quick_settings_media_device_label" msgid="8034019242363789941">"मिडिया उपकरण"</string> @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"स्क्रिन रेकर्ड"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरु गर्नुहोस्"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोक्नुहोस्"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"समस्या रेकर्ड गर्नुहोस्"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"सुरु गर्नुहोस्"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"रोक्नुहोस्"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"तपाईंको डिभाइसको कुन चाहिँ सुविधा प्रभावित भएको छ?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्याको प्रकार चयन गर्नुहोस्"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रिन रेकर्ड"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"पर्फर्मेन्स"</item> + <item msgid="1627504621139124393">"युजर इन्टरफेस"</item> + <item msgid="8309220355268900335">"ब्याट्री"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा फुल चार्ज हुने छ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"कम्युनल ट्युटोरियल सुरु गर्न बायाँतिर स्वाइप गर्नुहोस्"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"विजेट एडिटर खोल्नुहोस्"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाउनुहोस्"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट हाल्नुहोस्"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"पूरा भयो"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनु"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ब्याट्री सेभरको समयतालिका बनाउन ट्याप गर्नुहोस्"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ब्याट्री सकिने सम्भावना भएमा अन गर्नुहोस्"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"पर्दैन, धन्यवाद"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"प्रयोगमा छ"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"एपहरूले तपाईंको <xliff:g id="TYPES_LIST">%s</xliff:g> प्रयोग गर्दै छन्।"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string> <string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेमा मिरर गर्ने हो?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"डुअल स्क्रिनसम्बन्धी हाल चलिरहेको कुनै पनि गतिविधि रोकिने छ"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर गर्नुहोस्"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"खारेज गर्नुहोस्"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"डिस्प्ले कनेक्ट गरिएको छ"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 4dae2906a3e8..f66b4e1972db 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -253,7 +253,7 @@ <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Geen gekoppelde apparaten beschikbaar"</string> <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tik om een apparaat te verbinden of de verbinding te verbreken"</string> <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Nieuw apparaat koppelen"</string> - <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Alles bekijken"</string> + <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Alles tonen"</string> <string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth gebruiken"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Verbonden"</string> <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Opgeslagen"</string> @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Schermopname"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppen"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Probleem vastleggen"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Starten"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stoppen"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Op welk onderdeel van de apparaatfunctionaliteit had dit effect?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Probleemtype selecteren"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Schermopname"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Prestaties"</item> + <item msgid="1627504621139124393">"Gebruikersinterface"</item> + <item msgid="8309220355268900335">"Batterij"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swipe naar links om de communitytutorial te starten"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"De widget-editor openen"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwijderen"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget toevoegen"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pull-downmenu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tikken om Batterijbesparing aan te zetten"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Aanzetten als de batterij waarschijnlijk leeg raakt"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nee, bedankt"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In gebruik"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps gebruiken je <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string> <string name="install_app" msgid="5066668100199613936">"App installeren"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spiegelen naar extern scherm?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Alle dual screen-activiteiten die actief zijn, worden gestopt"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Scherm spiegelen"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Sluiten"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Scherm verbonden"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index bc599ba3cc70..0a457696c4a3 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ସ୍କ୍ରିନ ରେକର୍ଡ"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ଆରମ୍ଭ କରନ୍ତୁ"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ବନ୍ଦ କରନ୍ତୁ"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ସମସ୍ୟାର ରେକର୍ଡ କରନ୍ତୁ"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"ଆରମ୍ଭ କରନ୍ତୁ"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"ବନ୍ଦ କରନ୍ତୁ"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ଆପଣଙ୍କ ଡିଭାଇସ ଅନୁଭୂତିର କେଉଁ ଅଂଶ ପ୍ରଭାବିତ ହୋଇଛି?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ସମସ୍ୟାର ପ୍ରକାର ଚୟନ କରନ୍ତୁ"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ସ୍କ୍ରିନ ରେକର୍ଡ"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"ପରଫରମାନ୍ସ"</item> + <item msgid="1627504621139124393">"ୟୁଜର ଇଣ୍ଟରଫେସ"</item> + <item msgid="8309220355268900335">"ବେଟେରୀ"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"କମ୍ୟୁନାଲ ଟ୍ୟୁଟୋରିଆଲ ଆରମ୍ଭ କରିବା ପାଇଁ ବାମକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ୱିଜେଟ ଏଡିଟର ଖୋଲନ୍ତୁ"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"କାଢ଼ି ଦିଅନ୍ତୁ"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ହୋଇଗଲା"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍ ବଦଳାନ୍ତୁ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ପୁଲଡାଉନ ମେନୁ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅନ୍ ହେବାର ସମୟ ସେଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ବ୍ୟାଟେରୀ ସରିବାକୁ ଥିବା ସମୟରେ ଚାଲୁ କରନ୍ତୁ"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"ନାହିଁ, ଥାଉ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ହିପ୍ ଡମ୍ପ୍ କରନ୍ତୁ"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ବ୍ୟବହାର ହେଉଛି"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ଆପ୍ଲିକେସନ୍ଗୁଡିକ ଆପଣଙ୍କ <xliff:g id="TYPES_LIST">%s</xliff:g> ବ୍ୟବହାର କରୁଛନ୍ତି।"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string> <string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେକୁ ମିରର କରିବେ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"ବର୍ତ୍ତମାନ ଚାଲୁଥିବା ଯେ କୌଣସି ଡୁଆଲ ସ୍କ୍ରିନ କାର୍ଯ୍ୟକଳାପ ବନ୍ଦ ହୋଇଯିବ"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ଡିସପ୍ଲେ ମିରର କରନ୍ତୁ"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"ଖାରଜ କରନ୍ତୁ"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ଡିସପ୍ଲେ କନେକ୍ଟ କରାଯାଇଛି"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index a0718abc422a..c83659f733d4 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ਸ਼ੁਰੂ ਕਰੋ"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ਰੋਕੋ"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ਸਮੱਸਿਆ ਰਿਕਾਰਡ ਕਰੋ"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"ਸ਼ੁਰੂ ਕਰੋ"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"ਬੰਦ ਕਰੋ"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਿਹੜੀ ਸੁਵਿਧਾ ਪ੍ਰਭਾਵਿਤ ਹੋਈ ਸੀ?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ਸਮੱਸਿਆ ਦੀ ਕਿਸਮ ਚੁਣੋ"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"ਕਾਰਗੁਜ਼ਾਰੀ"</item> + <item msgid="1627504621139124393">"ਯੂਜ਼ਰ ਇੰਟਰਫ਼ੇਸ"</item> + <item msgid="8309220355268900335">"ਬੈਟਰੀ"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"ਭਾਈਚਾਰਕ ਟਿਊਟੋਰੀਅਲ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਖੱਬੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ਵਿਜੇਟ ਸੰਪਾਦਕ ਖੋਲ੍ਹੋ"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"ਹਟਾਓ"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ਹੋ ਗਿਆ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ਪੁੱਲਡਾਊਨ ਮੀਨੂ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿਚਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"ਬੈਟਰੀ ਸੇਵਰ ਦੀ ਸਮਾਂ-ਸੂਚੀ ਤਿਆਰ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="auto_saver_text" msgid="3214960308353838764">"ਬੈਟਰੀ ਖਤਮ ਹੋਣ ਦੀ ਸੰਭਾਵਨਾ \'ਤੇ ਚਾਲੂ ਹੁੰਦਾ ਹੈ"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"ਨਹੀਂ ਧੰਨਵਾਦ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ਹੀਪ ਡੰਪ ਕਰੋ"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ਵਰਤੋਂ ਵਿੱਚ"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੁਹਾਡੇ <xliff:g id="TYPES_LIST">%s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀਆਂ ਹਨ।"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string> <string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ਕੀ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰਨਾ ਹੈ?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀ ਕਿਸੇ ਵੀ Dual Screen ਸਰਗਰਮੀ ਬੰਦ ਕਰ ਦਿੱਤਾ ਜਾਵੇਗਾ"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ਡਿਸਪਲੇ ਨੂੰ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰੋ"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"ਖਾਰਜ ਕਰੋ"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ਡਿਸਪਲੇ ਨੂੰ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 4585c1bcb9a0..91f2c7817ed6 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Nagrywanie ekranu"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Rozpocznij"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zatrzymaj"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Zarejestruj problem"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Rozpocznij"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zatrzymaj"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Którego aspektu korzystania z urządzenia dotyczył problem?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Wybierz typ problemu"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Nagrywanie ekranu"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Wydajność"</item> + <item msgid="1627504621139124393">"Interfejs"</item> + <item msgid="8309220355268900335">"Bateria"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tryb jednej ręki"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardowy"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Aby uruchomić wspólny samouczek, przeciągnij palcem w lewo"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otwórz edytor widżetów"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Usuń"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widżet"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotowe"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Kliknij, by zaplanować działanie oszczędzania baterii"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Oszczędzanie baterii włącza się, jeśli bateria jest prawie wyczerpana"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nie, dziękuję"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Zrzut stosu SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"W użyciu"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacje używają: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string> <string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Powielić na wyświetlaczu zewnętrznym?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Każda aktualnie uruchomiona aktywność na dwóch ekranach zostanie zatrzymana"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Powielaj obraz"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Zamknij"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Wyświetlacz podłączony"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 81ddb63f0322..9fe372b66c6c 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravação de tela"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Problema na gravação"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Parar"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Desempenho"</item> + <item msgid="1627504621139124393">"Interface do usuário"</item> + <item msgid="8309220355268900335">"Bateria"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Deslize para a esquerda para iniciar o tutorial compartilhado"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir o editor de widgets"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluído"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Toque para programar o recurso Economia de bateria"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Ativada quando há possibilidade de a bateria acabar"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Não"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar heap SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Em uso"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicativos estão usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string> <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Qualquer atividade em tela dupla que esteja sendo executada no momento será interrompida"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Dispensar"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Tela conectada"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index b519a7d92231..3bf9c7b906ec 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -333,6 +333,14 @@ <string name="qs_record_issue_label" msgid="8166290137285529059">"Registar problema"</string> <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string> <string name="qs_record_issue_stop" msgid="3531747965741982657">"Parar"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da experiência do disposit. foi afetada?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecione o tipo de problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de ecrã"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Desempenho"</item> + <item msgid="1627504621139124393">"Interface do utilizador"</item> + <item msgid="8309220355268900335">"Bateria"</item> + </string-array> <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> @@ -861,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tocar para agendar a Poupança de bateria"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Ativar quando for provável que a bateria se esgote"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Não"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar pilha SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Em utilização"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"As aplicações estão a utilizar o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1201,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string> <string name="install_app" msgid="5066668100199613936">"Instalar app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para o ecrã externo?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Qualquer atividade de Dual Screen atualmente em curso vai ser interrompida"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Espelhar ecrã"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Ignorar"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Ecrã ligado"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 81ddb63f0322..9fe372b66c6c 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravação de tela"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Problema na gravação"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Parar"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Desempenho"</item> + <item msgid="1627504621139124393">"Interface do usuário"</item> + <item msgid="8309220355268900335">"Bateria"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Deslize para a esquerda para iniciar o tutorial compartilhado"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir o editor de widgets"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluído"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Toque para programar o recurso Economia de bateria"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Ativada quando há possibilidade de a bateria acabar"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Não"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar heap SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Em uso"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicativos estão usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string> <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Qualquer atividade em tela dupla que esteja sendo executada no momento será interrompida"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Dispensar"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Tela conectada"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index bc3fbe9e5cb7..18aa668d2fa5 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Înregistrarea ecranului"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Începe"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Oprește"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Problemă legată de înregistrare"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Începe"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Oprește"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ce parte a experienței pe dispozitiv a fost afectată?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selectează tipul problemei"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Înregistrarea ecranului"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performanță"</item> + <item msgid="1627504621139124393">"Interfața de utilizare"</item> + <item msgid="8309220355268900335">"Baterie"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Se încarcă • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> până la încărcarea completă"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Glisează spre stânga pentru a începe tutorialul pentru comunitate"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Deschide editorul de widgeturi"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Elimină"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adaugă un widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gata"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Schimbă utilizatorul"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"meniu vertical"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Atinge pentru a programa Economisirea energiei"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Pornește dacă e probabil ca bateria să se descarce"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nu, mulțumesc"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Extrage memoria SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"În uz"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicațiile folosesc <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string> <string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Oglindești pe ecranul extern?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Orice activitate care rulează pe două ecrane va fi oprită"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Afișare în oglindă"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Închide"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Ecran conectat"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 2e8a2572b3ce..51192f8e11ce 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Запись видео с экрана"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Начать"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Остановить"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Запись неисправности"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Начать"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Остановить"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С чем связана проблема, с которой вы столкнулись?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберите тип проблемы"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запись экрана"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Производительность"</item> + <item msgid="1627504621139124393">"Интерфейс"</item> + <item msgid="8309220355268900335">"Батарея"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Чтобы ознакомиться с руководством, проведите по экрану влево"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Открыть редактор виджетов"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Удалить"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавить виджет"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"раскрывающееся меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string> @@ -465,7 +467,7 @@ <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Отклонить все беззвучные уведомления"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"В режиме \"Не беспокоить\" уведомления заблокированы"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Начать"</string> - <string name="empty_shade_text" msgid="8935967157319717412">"Нет уведомлений"</string> + <string name="empty_shade_text" msgid="8935967157319717412">"Нет уведомлений."</string> <string name="no_unseen_notif_text" msgid="395512586119868682">"Новых уведомлений нет"</string> <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Разблокируйте, чтобы увидеть уведомления"</string> <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Устройством управляет один из родителей."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Нажмите, чтобы настроить режим энергосбережения"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Включать, если высока вероятность, что батарея скоро разрядится"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Нет, спасибо"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Передача SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Используется"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"В приложениях используется <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string> <string name="install_app" msgid="5066668100199613936">"Установить приложение"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублировать на внешний дисплей?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Функция одновременного использования двух экранов будет остановлена, если она активна."</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Дублировать"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Закрыть"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Экран подключен"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 2405bbfc6c28..7ade110cd5db 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"තිර පටිගත කිරීම"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ආරම්භ කරන්න"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"නතර කරන්න"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"පටිගත කිරීමේ ගැටලුව"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"අරඹන්න"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"නවත්වන්න"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ඔබේ උපාංග අත්දැකීමේ කුමන කොටසට බලපෑවේ ද?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ගැටලු වර්ගය තෝරන්න"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"තිර පටිගත කිරීම"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"කාර්ය සාධනය"</item> + <item msgid="1627504621139124393">"පරිශීලක අතුරු මුහුණත"</item> + <item msgid="8309220355268900335">"බැටරිය"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"පොදු නිබන්ධනය ආරම්භ කිරීමට වමට ස්වයිප් කරන්න"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"විජට් සංස්කාරකය විවෘත කරන්න"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"ඉවත් කරන්න"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"විජට්ටුව එක් කරන්න"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"නිමයි"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"නිපතන මෙනුව"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"බැටරි සුරැකුම කාලසටහන්ගත කිරීමට තට්ටු කරන්න"</string> <string name="auto_saver_text" msgid="3214960308353838764">"බැටරිය අවසන් වීමට යන විට සක්රීය කරන්න"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"එපා ස්තූතියි"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"භාවිතයේ ඇත"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"යෙදුම් ඔබේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරමින් සිටී."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string> <string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"බාහිර සංදර්ශකයට දර්පණය කරන්න ද?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"දැනට ක්රියාත්මක වන ඕනෑම ද්විත්ව තිර ක්රියාකාරකමක් නවත්වනු ඇත"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"සංදර්ශකය දර්පණය කරන්න"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"අස් කරන්න"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"සංදර්ශකය සම්බන්ධ කර ඇත"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index f53b5bf5c1c4..8d760d51603d 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rekordér obrazovky"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začať"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončiť"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Problém s nahrávaním"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Začnite"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zastavte"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Čo v zariadení bolo ovplyvnené?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte typ problému"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekordér obrazovky"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Výkon"</item> + <item msgid="1627504621139124393">"Používateľské rozhranie"</item> + <item msgid="8309220355268900335">"Batéria"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Potiahnutím doľava spustite komunitný návod"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otvoriť editor miniaplikácií"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrániť"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridať miniaplikáciu"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hotovo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbaľovacia ponuka"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Klepnutím naplánujete aktivovanie Šetriča batérie"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Zapnite, keď je batéria takmer vybitá"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nie, vďaka"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Výpis haldy SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Používa sa"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikácie používajú zoznam <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string> <string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Chcete zrkadliť na externú obrazovku?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Akákoľvek momentálne prebiehajúca aktivita vo funkcii Dual Screen bude zastavená"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Zrkadliť obrazovku"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Zavrieť"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Obrazovka je pripojená"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index ef56c4b248b0..4ae80ef5ba4c 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Snemanje zaslona"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začni"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ustavi"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Snemanje težave"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Začetek"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Ustavitev"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na kateri del izkušnje z napravo je to vplivalo?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Izberite vrsto težave"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snemanje zaslona"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Učinkovitost delovanja"</item> + <item msgid="1627504621139124393">"Uporabniški vmesnik"</item> + <item msgid="8309220355268900335">"Baterija"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enoročni način"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardni"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Povlecite levo, da zaženete vadnico za skupnost"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Odpiranje urejevalnika pripomočkov"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrani"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajanje pripomočka"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Končano"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"spustni meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Dotaknite se za načrtovanje varčevanja z energijo baterije"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Vklop, če je verjetno, da se bo baterija izpraznila"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Izvoz kopice SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"V uporabi"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije uporabljajo <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string> <string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite zrcaliti na zunanji zaslon?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Vse dejavnosti na dveh zaslonih, ki se trenutno izvajajo, bodo ustavljene."</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Zrcali zaslon"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Opusti"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Zaslon je povezan"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index b8824c7ae524..83727038c0af 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Regjistrimi i ekranit"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Nis"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ndalo"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Regjistro problemin"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Nis"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Ndalo"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cila pjesë e përvojës me pajisjen është prekur?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Zgjidh llojin e problemit"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Regjistrim i ekranit"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performanca"</item> + <item msgid="1627504621139124393">"Ndërfaqja e përdoruesit"</item> + <item msgid="8309220355268900335">"Bateria"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Rrëshqit shpejt majtas për të filluar udhëzuesin e përbashkët"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Hap modifikuesin e miniaplikacionit"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Hiq"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Shto miniaplikacionin"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"U krye"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyja me tërheqje poshtë"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Trokit për të planifikuar \"Kursyesin e baterisë\""</string> <string name="auto_saver_text" msgid="3214960308353838764">"Aktivizoje kur bateria mund të mbarojë"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Jo"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Hidh grumbullin SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Në përdorim"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacionet po përdorin <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string> <string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Të pasqyrohet në ekranin e jashtëm?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"Pasqyro ekranin"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Hiq"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 1eb45191f226..1bda1dbe0ae1 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Снимање екрана"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почните"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зауставите"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Евидентирајте проблем"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Покрени"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Заустави"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"На који део доживљаја на уређају је ово утицало?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изаберите тип проблема"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екрана"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Учинак"</item> + <item msgid="1627504621139124393">"Кориснички интерфејс"</item> + <item msgid="8309220355268900335">"Батерија"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Пуни се • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Превуците улево да бисте започели заједнички водич"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Отвори уређивач виџета"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Уклони"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додај виџет"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падајући мени"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Додирните да бисте направили распоред за уштеду батерије"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Укључите ако ће батерија вероватно да се испразни"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Не, хвала"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Издвоји SysUI мем."</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"У употреби"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликације користе <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string> <string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Желите ли да пресликате на спољњи екран?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Биће заустављена свака активност двојног екрана која је у току"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Одбаци"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Екран је повезан"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index c998e6d6d1f0..8cfafcf2fcdd 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skärminspelning"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starta"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppa"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Registrera problem"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Starta"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stoppa"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Vilken enhetsupplevelse påverkades?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Välj problemtyp"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skärminspelning"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Prestanda"</item> + <item msgid="1627504621139124393">"Användargränssnitt"</item> + <item msgid="8309220355268900335">"Batteri"</item> + </string-array> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhandsläge"</string> <string name="quick_settings_contrast_label" msgid="988087460210159123">"Kontrast"</string> <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Svep åt vänster för att börja med gruppguiden"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Öppna widgetredigeraren"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Ta bort"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lägg till widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klar"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullgardinsmeny"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Tryck för att skapa ett schema för batterisparläget"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Aktivera när batteriet håller på att ta slut"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Nej tack"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI-heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Används"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"<xliff:g id="TYPES_LIST">%s</xliff:g> används av appar."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1115,7 +1116,7 @@ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Söker efter nätverk …"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Det gick inte att ansluta till nätverket"</string> <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Du ansluts inte till wifi automatiskt för närvarande"</string> - <string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Se alla"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Koppla bort Ethernet för att växla nätverk"</string> <string name="wifi_scan_notify_message" msgid="3753839537448621794">"I syfte att förbättra upplevelsen med enheten kan appar och tjänster fortfarande söka efter wifi-nätverk när som helst, även om wifi har inaktiverats. Du kan ändra detta i inställningarna för wifi-sökning. "<annotation id="link">"Ändra"</annotation></string> <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Inaktivera flygplansläge"</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string> <string name="install_app" msgid="5066668100199613936">"Installera appen"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vill du spegla till extern skärm?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Pågående Dual Screen-aktivitet stoppas"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Spegla skärm"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Ignorera"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Skärm har anslutits"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index fc742d82de75..286e65abf384 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rekodi ya skrini"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Anza kurekodi"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Acha kurekodi"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Hitilafu ya Kurekodi"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Anza"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Simamisha"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ni sehemu gani ya matumizi ya kifaa iliathiriwa?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chagua aina ya tatizo"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekodi ya skrini"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Utendaji"</item> + <item msgid="1627504621139124393">"Kiolesura cha Mtumiaji"</item> + <item msgid="8309220355268900335">"Betri"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Telezesha kidole kushoto ili uanze mafunzo ya pamoja"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Fungua kihariri cha wijeti"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Ondoa"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ongeza wijeti"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Nimemaliza"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyu ya kuvuta chini"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Gusa ili uratibu wakati wa kuwasha Kiokoa Betri"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Washa wakati betri inakaribia kuisha"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Hapana"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Inatumika"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programu zinatumia <xliff:g id="TYPES_LIST">%s</xliff:g> yako."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string> <string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Ungependa kuonyesha kwenye skrini ya nje?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"Akisi skrini"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Ondoa"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index afba7a928892..aab713f7517a 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ஸ்கிரீன் ரெக்கார்டு"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"தொடங்கு"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"நிறுத்து"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"சிக்கலை ரெக்கார்டு செய்தல்"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"தொடங்குங்கள்"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"நிறுத்துங்கள்"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"சாதன அனுபவத்தின் எந்தப் பகுதி பாதிக்கப்பட்டது?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"சிக்கல் வகையைத் தேர்வுசெய்க"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ஸ்கிரீன் ரெக்கார்டு"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"செயல்திறன்"</item> + <item msgid="1627504621139124393">"பயனர் இடைமுகம்"</item> + <item msgid="8309220355268900335">"பேட்டரி"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • சார்ஜாகிறது • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> இல் முழுவதும் சார்ஜாகும்"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"சமூகப் பயிற்சியைத் தொடங்க இடதுபுறம் ஸ்வைப் செய்யுங்கள்"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"விட்ஜெட் எடிட்டரைத் திறக்கும்"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"அகற்றும்"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"விட்ஜெட்டைச் சேர்"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"முடிந்தது"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"கீழ் இழுக்கும் மெனு"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"பேட்டரி சேமிப்பானை ஆன் செய்வது தொடர்பாகத் திட்டமிட, தட்டவும்"</string> <string name="auto_saver_text" msgid="3214960308353838764">"பேட்டரி தீர்ந்துபோகும் நிலையில் இருக்கும் போது ஆன் செய்யப்படும்"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"வேண்டாம்"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"உபயோகத்தில் உள்ளது"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"உங்கள் <xliff:g id="TYPES_LIST">%s</xliff:g> ஆகியவற்றை ஆப்ஸ் பயன்படுத்துகின்றன."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string> <string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"வெளிப்புறக் காட்சிக்கு மிரர் செய்யவா?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"டிஸ்பிளேயை மிரர் செய்"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"வேண்டாம்"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 6621dae427e1..2536a96050fa 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"స్క్రీన్ రికార్డ్"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ప్రారంభించండి"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ఆపు"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"సమస్యను రికార్డ్ చేయడం"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"ప్రారంభించండి"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"ఆపివేయండి"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"మీ పరికర అనుభవంలో ఏ భాగం ప్రభావితమైంది?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"సమస్య రకాన్ని ఎంచుకోండి"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"స్క్రీన్ రికార్డ్"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"పనితీరు"</item> + <item msgid="1627504621139124393">"యూజర్ ఇంటర్ఫేస్"</item> + <item msgid="8309220355268900335">"బ్యాటరీ"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ఛార్జ్ అవుతోంది • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"కమ్యూనల్ ట్యుటోరియల్ను ప్రారంభించడానికి ఎడమ వైపునకు స్వైప్ చేయండి"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"విడ్జెట్ ఎడిటర్ను తెరవండి"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"తీసివేయండి"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"విడ్జెట్ను జోడించండి"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"పూర్తయింది"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"వినియోగదారుని మార్చు"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"పుల్డౌన్ మెనూ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"బ్యాటరీ సేవర్ని షెడ్యూల్ చేయడానికి నొక్కండి"</string> <string name="auto_saver_text" msgid="3214960308353838764">"బ్యాటరీ ఛార్జింగ్ పూర్తిగా అయిపోతున్న తరుణంలో ఆన్ చేస్తుంది"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"వద్దు, ధన్యవాదాలు"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"డంప్ SysUI హీప్"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"వినియోగంలో ఉంది"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"అప్లికేషన్లు మీ <xliff:g id="TYPES_LIST">%s</xliff:g>ని ఉపయోగిస్తున్నాయి."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్లలో ఆటోమేటిక్గా ఉండేలా ఒక నోట్స్ యాప్ను సెట్ చేసుకోండి"</string> <string name="install_app" msgid="5066668100199613936">"యాప్ను ఇన్స్టాల్ చేయండి"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ఎక్స్టర్నల్ డిస్ప్లేకి మిర్రర్ చేయాలా?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"ప్రస్తుతం రన్ అవుతున్న Dual Screen యాక్టివిటీ ఏదైనా ఉంటే, అది ఆపివేయబడుతుంది"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"మిర్రర్ డిస్ప్లే"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"విస్మరించండి"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"డిస్ప్లే కనెక్ట్ చేయబడింది"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 8c24e4b6acfe..3c96e30f4631 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"บันทึกหน้าจอ"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"เริ่ม"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"หยุด"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"ปัญหาการบันทึก"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"เริ่ม"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"หยุด"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ประสบการณ์การใช้งานอุปกรณ์ส่วนใดที่ได้รับผลกระทบ"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"เลือกประเภทปัญหา"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"บันทึกหน้าจอ"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"ประสิทธิภาพ"</item> + <item msgid="1627504621139124393">"อินเทอร์เฟซผู้ใช้"</item> + <item msgid="8309220355268900335">"แบตเตอรี่"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • กำลังชาร์จ • จะเต็มในอีก <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"ปัดไปทางซ้ายเพื่อเริ่มบทแนะนำส่วนกลาง"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"เปิดเครื่องมือแก้ไขวิดเจ็ต"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"นำออก"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"เพิ่มวิดเจ็ต"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"เสร็จสิ้น"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"สลับผู้ใช้"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"เมนูแบบเลื่อนลง"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"แตะเพื่อตั้งเวลาโหมดประหยัดแบตเตอรี่"</string> <string name="auto_saver_text" msgid="3214960308353838764">"เปิดเมื่อมีแนวโน้มว่าแบตเตอรี่จะหมด"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"ไม่เป็นไร"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"ใช้งานอยู่"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"หลายแอปพลิเคชันใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณอยู่"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string> <string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"มิเรอร์ไปยังจอแสดงผลภายนอกไหม"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"กิจกรรมที่ทำอยู่บน Dual Screen จะหยุดลง"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"มิเรอร์จอแสดงผล"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"ปิด"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"เชื่อมต่อจอแสดงผลแล้ว"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index f0b9d1f878a6..8fc5b6b6668a 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Pag-record ng screen"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Magsimula"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ihinto"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Mag-record ng Isyu"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Magsimula"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Ihinto"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ano\'ng naapektuhang parte ng experience sa device?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Piliin ang uri ng isyu"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pag-record ng screen"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performance"</item> + <item msgid="1627504621139124393">"User Interface"</item> + <item msgid="8309220355268900335">"Baterya"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nagcha-charge • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> na lang para mapuno"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Mag-swipe pakaliwa para simulan ang communal na tutorial"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Buksan ang editor ng widget"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Alisin"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Magdagdag ng widget"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Tapos na"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"I-tap para iiskedyul ang Pantipid ng Baterya"</string> <string name="auto_saver_text" msgid="3214960308353838764">"I-on kapag malamang na maubos ang baterya"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Hindi, salamat na lang"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Ginagamit"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ginagamit ng mga application ang iyong <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string> <string name="install_app" msgid="5066668100199613936">"I-install ang app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"I-mirror sa external na display?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Ihihinto ang anumang aktibidad sa dual screen na kasalukuyang tumatakbo."</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"I-mirror ang display"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"I-dismiss"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Naikonekta ang display"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index f9d90d4ad72e..a4083efc84f8 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekran kaydı"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlat"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Durdur"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Sorunu Kaydedin"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Başlayın"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Durdurun"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz deneyiminiz ne şekilde etkilendi?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sorun türünü seçin"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran kaydedicisi"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Performans"</item> + <item msgid="1627504621139124393">"Kullanıcı Arayüzü"</item> + <item msgid="8309220355268900335">"Pil"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Ortak eğitimi başlatmak için sola kaydırın"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Widget düzenleyiciyi açın"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Kaldır"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget ekle"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Bitti"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Pil Tasarrufunu programlamak için dokunun"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Piliniz bitecek gibiyse bu özelliği açın"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Hayır, teşekkürler"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI Yığın Dökümü"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Kullanımda"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Uygulamalar şunları kullanıyor: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string> <string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Harici ekrana yansıtılsın mı?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Şu anda devam eden tüm Dual Screen etkinlikleri durdurulacak"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Ekranı yansıt"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Kapat"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Ekran bağlandı"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index c5211e899d2d..5e0f2c2ed352 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Запис екрана"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почати"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зупинити"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Запис помилки"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Почати"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Зупинити"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"На який аспект роботи пристрою вплинула проблема?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Виберіть тип проблеми"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис відео з екрана"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Продуктивність"</item> + <item msgid="1627504621139124393">"Інтерфейс користувача"</item> + <item msgid="8309220355268900335">"Акумулятор"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Проведіть пальцем уліво, щоб відкрити спільний навчальний посібник"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Відкрити редактор віджетів"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Видалити"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додати віджет"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"спадне меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Торкніться, щоб налаштувати режим енергозбереження"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Вмикати, коли заряд акумулятора закінчується"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ні, дякую"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Використовується"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Додатки використовують <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string> <string name="install_app" msgid="5066668100199613936">"Установити додаток"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублювати на зовнішньому екрані?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"Дублювати екран"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Закрити"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 01995c8a2a58..c28e064e1f22 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"اسکرین ریکارڈ"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع کریں"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"روکیں"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"مسئلہ ریکارڈ کریں"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"شروع کریں"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"روکیں"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"آپ کے آلے کے تجربے کا کون سا حصہ متاثر ہوا؟"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"مسئلہ کی قسم منتخب کریں"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"اسکرین ریکارڈ"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"کارکردگی"</item> + <item msgid="1627504621139124393">"یوزر انٹرفیس"</item> + <item msgid="8309220355268900335">"بیٹری"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • چارج ہو رہا ہے • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> میں مکمل"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"کمیونل ٹیوٹوریل شروع کرنے کے لیے بائیں سوائپ کریں"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ویجیٹ ایڈیٹر کو کھولیں"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"ہٹائیں"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ویجیٹ شامل کریں"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ہو گیا"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"پل ڈاؤن مینیو"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"بیٹری سیور شیڈول کرنے کے لیے تھپتھپائیں"</string> <string name="auto_saver_text" msgid="3214960308353838764">"جب بیٹری کے ختم ہونے کا امکان ہو تو آن کریں"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"نہیں شکریہ"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"زیر استعمال"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ایپلیکیشنز آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں۔"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string> <string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"بیرونی ڈسپلے پر مرر کریں؟"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"فی الحال چلنے والی Dual Screen کی کوئی بھی سرگرمی روک دی جائے گی"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"ڈسپلے کو مرر کریں"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"برخاست کریں"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ڈسپلے منسلک ہے"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index bf4814618758..e032c76f48b5 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekran yozuvi"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Boshlash"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Toʻxtatish"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Yozib olishda xato"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Boshlash"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Toʻxtatish"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Qurilma ishlashining qaysi qismiga taʼsir qildi?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Muammo turini tanlang"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran yozuvi"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Unumdorlik"</item> + <item msgid="1627504621139124393">"Foydalanuvchi interfeysi"</item> + <item msgid="8309220355268900335">"Batareya"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Quvvat olmoqda • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> qoldi"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Qoʻllanma bilan tanishish uchun chapga suring"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Vidjet muharririni ochish"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Olib tashlash"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidjet kiritish"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Tayyor"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"tortib tushiriladigan menyu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Quvvat tejash rejimini rejalashtirish uchun bosing"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Batareya quvvati kamayishi aniqlanganda yoqilsin"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Kerak emas"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Foydalanilmoqda"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ilovalarda ishlatilmoqda: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standart qaydlar ilovasini Sozlamalar orqali tanlang"</string> <string name="install_app" msgid="5066668100199613936">"Ilovani oʻrnatish"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tashqi displeyda aks ettirilsinmi?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Joriy ishga tushgan ikki ekranli faollik toʻxtatiladi"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Displeyni aks ettirish"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Yopish"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Displey ulandi"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index a70c8ad9912a..b87619e497df 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -269,7 +269,7 @@ <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Tự động xoay màn hình"</string> <string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string> <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Trình bảo vệ màn hình"</string> - <string name="quick_settings_camera_label" msgid="5612076679385269339">"Truy cập máy ảnh"</string> + <string name="quick_settings_camera_label" msgid="5612076679385269339">"Quyền truy cập camera"</string> <string name="quick_settings_mic_label" msgid="8392773746295266375">"Quyền truy cập micrô"</string> <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Được phép"</string> <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bị chặn"</string> @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ghi màn hình"</string> <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> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Ghi lại vấn đề"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Bắt đầu"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Dừng"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bạn gặp loại vấn đề gì khi dùng thiết bị?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chọn loại vấn đề"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ghi màn hình"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Hiệu suất"</item> + <item msgid="1627504621139124393">"Giao diện người dùng"</item> + <item msgid="8309220355268900335">"Pin"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Vuốt sang trái để bắt đầu xem hướng dẫn chung"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Mở trình chỉnh sửa tiện ích"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Xoá"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Thêm tiện ích"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Xong"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"trình đơn kéo xuống"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Nhấn để lên lịch Trình tiết kiệm pin"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Bật khi pin sắp hết"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Không, cảm ơn"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Trích xuất bộ nhớ SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Đang được sử dụng"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Các ứng dụng đang dùng <xliff:g id="TYPES_LIST">%s</xliff:g> của bạn."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,7 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string> <string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Phản chiếu sang màn hình ngoài?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (2917631104216376315) --> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> <skip /> <string name="mirror_display" msgid="2515262008898122928">"Phản chiếu màn hình"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Đóng"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index abc2e311ef84..43dfbe8e8ff1 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -298,7 +298,7 @@ <string name="quick_settings_connecting" msgid="2381969772953268809">"正在连接…"</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"热点"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"正在开启…"</string> - <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"流量节省程序已开启"</string> + <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"省流模式已开启"</string> <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# 部设备}other{# 部设备}}"</string> <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"手电筒"</string> <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"相机正在使用中"</string> @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"屏幕录制"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"开始"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"录制问题"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"开始"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"停止"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"设备体验的哪个方面受到影响?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"选择问题类型"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"屏幕录制"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"性能"</item> + <item msgid="1627504621139124393">"界面"</item> + <item msgid="8309220355268900335">"电池"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在充电 • 将于 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>后充满"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"向左滑动即可启动公共教程"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"打开微件编辑器"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"添加微件"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉菜单"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string> @@ -609,7 +611,7 @@ <string name="notification_channel_summary_low" msgid="4860617986908931158">"不发出提示音,也不振动"</string> <string name="notification_conversation_summary_low" msgid="1734433426085468009">"不发出提示音,也不振动;显示在对话部分的靠下位置"</string> <string name="notification_channel_summary_default" msgid="777294388712200605">"可能会响铃或振动,取决于设备设置"</string> - <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"可能会响铃或振动,取决于设备设置。默认情况下,来自<xliff:g id="APP_NAME">%1$s</xliff:g>的对话会以对话泡的形式显示。"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"可能会响铃或振动,取决于设备设置。默认情况下,来自<xliff:g id="APP_NAME">%1$s</xliff:g>的对话会以消息气泡的形式显示。"</string> <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"让系统决定是否应让设备在收到此通知时发出提示音或振动"</string> <string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>状态</b>:已提升为“默认”"</string> <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>状态</b>:已降低为“静音”"</string> @@ -637,7 +639,7 @@ <string name="notification_more_settings" msgid="4936228656989201793">"更多设置"</string> <string name="notification_app_settings" msgid="8963648463858039377">"自定义"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"显示气泡"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"移除对话泡"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"移除消息气泡"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g><xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"通知设置"</string> <string name="notification_menu_snooze_description" msgid="4740133348901973244">"通知延后选项"</string> @@ -736,8 +738,8 @@ <string name="accessibility_long_click_tile" msgid="210472753156768705">"打开“设置”"</string> <string name="accessibility_status_bar_headphones" msgid="1304082414912647414">"已连接到耳机"</string> <string name="accessibility_status_bar_headset" msgid="2699275863720926104">"已连接到耳机"</string> - <string name="data_saver" msgid="3484013368530820763">"流量节省程序"</string> - <string name="accessibility_data_saver_on" msgid="5394743820189757731">"流量节省程序已开启"</string> + <string name="data_saver" msgid="3484013368530820763">"省流模式"</string> + <string name="accessibility_data_saver_on" msgid="5394743820189757731">"省流模式已开启"</string> <string name="switch_bar_on" msgid="1770868129120096114">"开启"</string> <string name="switch_bar_off" msgid="5669805115416379556">"关闭"</string> <string name="tile_unavailable" msgid="3095879009136616920">"不可用"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"点按即可预设省电模式"</string> <string name="auto_saver_text" msgid="3214960308353838764">"在电池电量可能会耗尽时,系统会开启此模式"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"不用了"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"转储 SysUI 堆"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"正在使用"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多个应用正在使用您的<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string> <string name="install_app" msgid="5066668100199613936">"安装应用"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"镜像到外接显示屏?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"当前正在进行的任何双屏幕活动都将会停止"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"镜像到显示屏"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"关闭"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"显示屏已连接"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index ac40c48ea66a..784f667575b9 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"螢幕錄影"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"錄製問題"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"開始"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"停止"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受影響?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"效能"</item> + <item msgid="1627504621139124393">"使用者介面"</item> + <item msgid="8309220355268900335">"電池"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"向左滑動即可開始共用教學課程"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"開啟小工具編輯器"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"輕按即可預定慳電模式自動開啟時間"</string> <string name="auto_saver_text" msgid="3214960308353838764">"在電池電量可能耗盡前啟用「慳電模式」"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"不用了,謝謝"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"使用中"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string> <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要鏡像投射至外部顯示屏嗎?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"目前進行的雙螢幕活動都會停止"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"關閉"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"已連接顯示屏"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index cc34a4a98b85..15da239353d0 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"螢幕錄影"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"記錄問題"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"開始"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"停止"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受到影響?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"效能"</item> + <item msgid="1627504621139124393">"使用者介面"</item> + <item msgid="8309220355268900335">"電池"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 充電中 • 將於 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充飽"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"向左滑動即可啟動通用教學課程"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"開啟小工具編輯器"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"輕觸即可排定省電模式自動開啟的情況"</string> <string name="auto_saver_text" msgid="3214960308353838764">"在電池電量即將耗盡時開啟"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"不用了,謝謝"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"使用中"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string> <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要以鏡像方式投放至外部螢幕嗎?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"目前進行的雙螢幕活動都會停止"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"關閉"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"螢幕已連結"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 83fc6287fa16..31cdca973cde 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -330,12 +330,17 @@ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Irekhodi lesikrini"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Qala"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Misa"</string> - <!-- no translation found for qs_record_issue_label (8166290137285529059) --> - <skip /> - <!-- no translation found for qs_record_issue_start (2979831312582567056) --> - <skip /> - <!-- no translation found for qs_record_issue_stop (3531747965741982657) --> - <skip /> + <string name="qs_record_issue_label" msgid="8166290137285529059">"Rekhoda Inkinga"</string> + <string name="qs_record_issue_start" msgid="2979831312582567056">"Qala"</string> + <string name="qs_record_issue_stop" msgid="3531747965741982657">"Misa"</string> + <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuthinteke yiphi ingxenye yokusebenzisa idivayisi?"</string> + <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Khetha uhlobo lwenkinga"</string> + <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Irekhodi lesikrini"</string> + <string-array name="qs_record_issue_types"> + <item msgid="2947988124014085798">"Ukusebenza"</item> + <item msgid="1627504621139124393">"Okusetshenziswa Kubonwa"</item> + <item msgid="8309220355268900335">"Ibhethri"</item> + </string-array> <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> @@ -408,12 +413,9 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Iyashaja • Izogcwala ngo-<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swayiphela kwesokunxele ukuze uqale okokufundisa komphakathi"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Vula isihleli sewijethi"</string> - <!-- no translation found for button_to_remove_widget (3948204829181214098) --> - <skip /> - <!-- no translation found for hub_mode_add_widget_button_text (4831464661209971729) --> - <skip /> - <!-- no translation found for hub_mode_editing_exit_button_text (3704686734192264771) --> - <skip /> + <string name="button_to_remove_widget" msgid="3948204829181214098">"Susa"</string> + <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engeza iwijethi"</string> + <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Kwenziwe"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"imenyu yokudonsela phansi"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wonke ama-app nedatha kulesi sikhathi azosuswa."</string> @@ -867,7 +869,6 @@ <string name="auto_saver_title" msgid="6873691178754086596">"Thepha ukuze ushejuli isilondolozi sebhethri"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Vula uma ibhethri sekungenzeka liphele"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Cha ngiyabonga"</string> - <string name="heap_dump_tile_name" msgid="2464189856478823046">"I-Dump SysUI Heap"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Kuyasebenza"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Izinhlelo zokusebenza zisebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho."</string> <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string> @@ -1207,7 +1208,8 @@ <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string> <string name="install_app" msgid="5066668100199613936">"Faka i-app"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Fanisa nesibonisi sangaphandle?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="2917631104216376315">"Noma yimuphi umsebenzi wezikrini ezimbili ezisebenzayo uzomiswa"</string> + <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> + <skip /> <string name="mirror_display" msgid="2515262008898122928">"Isibonisi sokufanisa"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Chitha"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Isibonisi sixhunyiwe"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index e01a2aa674b3..5c362b203e09 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -963,10 +963,16 @@ <bool name="config_edgeToEdgeBottomSheetDialog">true</bool> <!-- + Time in milliseconds the user has to touch the side FPS sensor to successfully authenticate when + the screen is turned off with AOD not enabled. + TODO(b/302332976) Get this value from the HAL if they can provide an API for it. + --> + <integer name="config_restToUnlockDurationScreenOff">500</integer> + <!-- Time in milliseconds the user has to touch the side FPS sensor to successfully authenticate TODO(b/302332976) Get this value from the HAL if they can provide an API for it. --> - <integer name="config_restToUnlockDuration">300</integer> + <integer name="config_restToUnlockDurationDefault">300</integer> <!-- Width in pixels of the Side FPS sensor. diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 80725c2bd4b5..6e035e8c8c36 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -262,8 +262,9 @@ <item type="id" name="device_entry_icon_fg" /> <item type="id" name="device_entry_icon_bg" /> - <!--Id for the device-entry UDFPS icon that lives in the alternate bouncer. --> + <!--Id for the device-entry UDFPS related views that live in the alternate bouncer. --> <item type="id" name="alternate_bouncer_udfps_icon_view" /> + <item type="id" name="alternate_bouncer_udfps_accessibility_overlay" /> <!-- Id for the udfps accessibility overlay --> <item type="id" name="udfps_accessibility_overlay" /> diff --git a/packages/SystemUI/shared/res/values/ids.xml b/packages/SystemUI/shared/res/values/ids.xml new file mode 100644 index 000000000000..1ff2f0eff215 --- /dev/null +++ b/packages/SystemUI/shared/res/values/ids.xml @@ -0,0 +1,24 @@ +<?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> + <!-- ID of the smartspace card view. --> + <item type="id" name="bc_smartspace_view" /> + <!-- ID of the smartspace date view. --> + <item type="id" name="date_smartspace_view" /> + <!-- ID of the smartspace weather view. --> + <item type="id" name="weather_smartspace_view" /> +</resources> diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt index 1ee58deb501c..5e76801aaca3 100644 --- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt +++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt @@ -41,6 +41,7 @@ import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.settings.SecureSettings import java.io.PrintWriter import javax.inject.Inject +import dagger.Lazy /** * Handles active unlock settings changes. @@ -51,6 +52,7 @@ class ActiveUnlockConfig @Inject constructor( private val secureSettings: SecureSettings, private val contentResolver: ContentResolver, private val selectedUserInteractor: SelectedUserInteractor, + private val keyguardUpdateMonitor: Lazy<KeyguardUpdateMonitor>, dumpManager: DumpManager ) : Dumpable { @@ -96,7 +98,6 @@ class ActiveUnlockConfig @Inject constructor( UNDER_DISPLAY_FINGERPRINT(3), } - var keyguardUpdateMonitor: KeyguardUpdateMonitor? = null private var requestActiveUnlockOnWakeup = false private var requestActiveUnlockOnUnlockIntent = false private var requestActiveUnlockOnBioFail = false @@ -316,7 +317,7 @@ class ActiveUnlockConfig @Inject constructor( return false } - keyguardUpdateMonitor?.let { + keyguardUpdateMonitor.get().let { val anyFaceEnrolled = it.isFaceEnabledAndEnrolled val anyFingerprintEnrolled = it.isUnlockWithFingerprintPossible( selectedUserInteractor.getSelectedUserId()) @@ -369,13 +370,13 @@ class ActiveUnlockConfig @Inject constructor( }") pw.println("Current state:") - keyguardUpdateMonitor?.let { + keyguardUpdateMonitor.get().let { pw.println(" shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment=" + "${shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment()}") pw.println(" isFaceEnabledAndEnrolled=${it.isFaceEnabledAndEnrolled}") pw.println(" fpUnlockPossible=${ it.isUnlockWithFingerprintPossible(selectedUserInteractor.getSelectedUserId())}") pw.println(" udfpsEnrolled=${it.isUdfpsEnrolled}") - } ?: pw.println(" keyguardUpdateMonitor is uninitialized") + } } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index bcc20448297d..82410fd39dcd 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -33,6 +33,7 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener import androidx.annotation.VisibleForTesting import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.Flags.migrateClocksToBlueprint import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.customization.R import com.android.systemui.dagger.qualifiers.Background @@ -325,6 +326,10 @@ constructor( } } + if (visible) { + refreshTime() + } + smallTimeListener?.update(shouldTimeListenerRun) largeTimeListener?.update(shouldTimeListenerRun) } @@ -346,6 +351,19 @@ constructor( weatherData = data clock?.run { events.onWeatherDataChanged(data) } } + + override fun onTimeChanged() { + refreshTime() + } + + private fun refreshTime() { + if (!migrateClocksToBlueprint()) { + return + } + + clock?.smallClock?.events?.onTimeTick() + clock?.largeClock?.events?.onTimeTick() + } } private val zenModeCallback = object : ZenModeController.Callback { @@ -558,7 +576,8 @@ constructor( isRunning = true when (clockFace.config.tickRate) { ClockTickRate.PER_MINUTE -> { - /* Handled by KeyguardClockSwitchController */ + // Handled by KeyguardClockSwitchController and + // by KeyguardUpdateMonitorCallback#onTimeChanged. } ClockTickRate.PER_SECOND -> executor.execute(secondsRunnable) ClockTickRate.PER_FRAME -> { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index 714fe64f1a8f..66f965aea76f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -30,13 +30,13 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.Flags; import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; import com.android.systemui.bouncer.ui.BouncerMessageView; import com.android.systemui.bouncer.ui.binder.BouncerMessageViewBinder; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.log.BouncerLogger; import com.android.systemui.res.R; import com.android.systemui.statusbar.policy.DevicePostureController; @@ -108,7 +108,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> private void updateMessageAreaVisibility() { if (mMessageAreaController == null) return; - if (mFeatureFlags.isEnabled(Flags.REVAMPED_BOUNCER_MESSAGES)) { + if (Flags.revampedBouncerMessages()) { mMessageAreaController.disable(); } else { mMessageAreaController.setIsVisible(true); @@ -182,15 +182,13 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> public void bindMessageView( @NonNull BouncerMessageInteractor bouncerMessageInteractor, KeyguardMessageAreaController.Factory messageAreaControllerFactory, - BouncerLogger bouncerLogger, - FeatureFlags featureFlags) { + BouncerLogger bouncerLogger) { BouncerMessageView bouncerMessageView = (BouncerMessageView) mView.getBouncerMessageView(); if (bouncerMessageView != null) { BouncerMessageViewBinder.bind(bouncerMessageView, bouncerMessageInteractor, messageAreaControllerFactory, - bouncerLogger, - featureFlags); + bouncerLogger); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index cce2018f733f..5e35e7764dd8 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -31,7 +31,6 @@ import static com.android.keyguard.KeyguardSecurityModel.SecurityMode.SimPin; import static com.android.keyguard.KeyguardSecurityModel.SecurityMode.SimPuk; import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE; -import static com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES; import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; @@ -1164,7 +1163,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mLockPatternUtils.reportFailedPasswordAttempt(userId); if (timeoutMs > 0) { mLockPatternUtils.reportPasswordLockout(timeoutMs, userId); - if (!mFeatureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) { + if (!com.android.systemui.Flags.revampedBouncerMessages()) { mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils, mSecurityModel.getSecurityMode(userId)); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 9c61a8a3cd8b..4d84d0b3b666 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -111,6 +111,7 @@ import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.settingslib.Utils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; +import com.android.systemui.CoreStartable; import com.android.systemui.Dumpable; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; @@ -175,7 +176,7 @@ import javax.inject.Provider; * to be updated. */ @SysUISingleton -public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpable { +public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpable, CoreStartable { private static final String TAG = "KeyguardUpdateMonitor"; private static final int BIOMETRIC_LOCKOUT_RESET_DELAY_MS = 600; @@ -216,7 +217,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private static final int MSG_BIOMETRIC_ENROLLMENT_STATE_CHANGED = 348; /** Biometric authentication state: Not listening. */ - private static final int BIOMETRIC_STATE_STOPPED = 0; + @VisibleForTesting + protected static final int BIOMETRIC_STATE_STOPPED = 0; /** Biometric authentication state: Listening. */ private static final int BIOMETRIC_STATE_RUNNING = 1; @@ -347,6 +349,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final LatencyTracker mLatencyTracker; private final StatusBarStateController mStatusBarStateController; private final Executor mBackgroundExecutor; + private final Executor mMainExecutor; private final SensorPrivacyManager mSensorPrivacyManager; private final ActiveUnlockConfig mActiveUnlockConfig; private final IDreamManager mDreamManager; @@ -354,7 +357,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Nullable private final FingerprintManager mFpm; @Nullable + private final BiometricManager mBiometricManager; + @Nullable private KeyguardFaceAuthInteractor mFaceAuthInteractor; + private final DevicePostureController mDevicePostureController; private final TaskStackChangeListeners mTaskStackChangeListeners; private final IActivityTaskManager mActivityTaskManager; private final SelectedUserInteractor mSelectedUserInteractor; @@ -370,7 +376,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private boolean mIsDreaming; private boolean mLogoutEnabled; private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - private FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider; + private final FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider; /** * Short delay before restarting fingerprint authentication after a successful try. This should @@ -1798,6 +1804,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab public void onFingerprintDetected(int sensorId, int userId, boolean isStrongBiometric) { handleBiometricDetected(userId, FINGERPRINT, isStrongBiometric); + setFingerprintRunningState(BIOMETRIC_STATE_STOPPED); } }; @@ -2105,6 +2112,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); mStrongAuthTracker = new StrongAuthTracker(context); mBackgroundExecutor = backgroundExecutor; + mMainExecutor = mainExecutor; mBroadcastDispatcher = broadcastDispatcher; mInteractionJankMonitor = interactionJankMonitor; mLatencyTracker = latencyTracker; @@ -2126,7 +2134,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mDevicePolicyManager = devicePolicyManager; mPackageManager = packageManager; mFpm = fingerprintManager; - mActiveUnlockConfig.setKeyguardUpdateMonitor(this); + mBiometricManager = biometricManager; mConfigFaceAuthSupportedPosture = mContext.getResources().getInteger( R.integer.config_face_auth_supported_posture); mFaceWakeUpTriggersConfig = faceWakeUpTriggersConfig; @@ -2134,10 +2142,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mContext.getResources().getStringArray( R.array.config_fingerprint_listen_on_occluding_activity_packages)) .collect(Collectors.toSet()); + mDevicePostureController = devicePostureController; mTaskStackChangeListeners = taskStackChangeListeners; mActivityTaskManager = activityTaskManagerService; mSelectedUserInteractor = selectedUserInteractor; + mFingerprintInteractiveToAuthProvider = interactiveToAuthProvider.orElse(null); + mIsSystemUser = mUserManager.isSystemUser(); + mHandler = new Handler(mainLooper) { @Override public void handleMessage(Message msg) { @@ -2252,6 +2264,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } }; + mTimeFormatChangeObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + mHandler.sendMessage(mHandler.obtainMessage( + MSG_TIME_FORMAT_UPDATE, + Settings.System.getString( + mContext.getContentResolver(), + Settings.System.TIME_12_24))); + } + }; + } + + @Override + public void start() { // Since device can't be un-provisioned, we only need to register a content observer // to update mDeviceProvisioned when we are... if (!mDeviceProvisioned) { @@ -2297,7 +2323,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mHandler, UserHandle.ALL); mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); - mUserTracker.addCallback(mUserChangedCallback, mainExecutor); + mUserTracker.addCallback(mUserChangedCallback, mMainExecutor); mTrustManager.registerTrustListener(this); @@ -2318,8 +2344,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback); } - if (biometricManager != null) { - biometricManager.registerEnabledOnKeyguardCallback(mBiometricEnabledCallback); + if (mBiometricManager != null) { + mBiometricManager.registerEnabledOnKeyguardCallback(mBiometricEnabledCallback); } // in case authenticators aren't registered yet at this point: @@ -2327,7 +2353,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onAllAuthenticatorsRegistered( @BiometricAuthenticator.Modality int modality) { - mainExecutor.execute( + mMainExecutor.execute( () -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE)); } @@ -2335,7 +2361,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) { mHandler.obtainMessage(MSG_BIOMETRIC_ENROLLMENT_STATE_CHANGED, modality, 0) .sendToTarget(); - mainExecutor.execute( + mMainExecutor.execute( () -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE)); } @@ -2353,12 +2379,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } }); if (mConfigFaceAuthSupportedPosture != DEVICE_POSTURE_UNKNOWN) { - devicePostureController.addCallback(mPostureCallback); + mDevicePostureController.addCallback(mPostureCallback); } updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); mTaskStackChangeListeners.registerTaskStackListener(mTaskStackListener); - mIsSystemUser = mUserManager.isSystemUser(); int user = mSelectedUserInteractor.getSelectedUserId(true); mUserIsUnlocked.put(user, mUserManager.isUserUnlocked(user)); mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled(); @@ -2377,22 +2402,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener); initializeSimState(); - mTimeFormatChangeObserver = new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - mHandler.sendMessage(mHandler.obtainMessage( - MSG_TIME_FORMAT_UPDATE, - Settings.System.getString( - mContext.getContentResolver(), - Settings.System.TIME_12_24))); - } - }; - mContext.getContentResolver().registerContentObserver( Settings.System.getUriFor(Settings.System.TIME_12_24), false, mTimeFormatChangeObserver, UserHandle.USER_ALL); - - mFingerprintInteractiveToAuthProvider = interactiveToAuthProvider.orElse(null); } private void initializeSimState() { diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 175fcdb6e11a..d5dc85cd8715 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -26,7 +26,6 @@ import static com.android.systemui.Flags.keyguardBottomAreaRefactor; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1; import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED; -import static com.android.systemui.Flags.newAodTransition; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; import android.annotation.SuppressLint; @@ -395,16 +394,6 @@ public class LockIconViewController implements Dumpable { mView.updateIcon(ICON_LOCK, true); mView.setContentDescription(mLockedLabel); mView.setVisibility(View.VISIBLE); - } else if (mIsDozing && newAodTransition()) { - mView.animate() - .alpha(0f) - .setDuration(FADE_OUT_DURATION_MS) - .withEndAction(() -> { - mView.clearIcon(); - mView.setVisibility(View.INVISIBLE); - mView.setContentDescription(null); - }) - .start(); } else { mView.clearIcon(); mView.setVisibility(View.INVISIBLE); diff --git a/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt b/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt index 603471b1de41..7a560e846318 100644 --- a/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt +++ b/packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt @@ -19,6 +19,7 @@ package com.android.keyguard.mediator import android.annotation.BinderThread import android.os.Handler import android.os.Trace +import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.unfold.SysUIUnfoldComponent @@ -59,8 +60,11 @@ class ScreenOnCoordinator @Inject constructor( foldAodAnimationController?.onScreenTurningOn(pendingTasks.registerTask("fold-to-aod")) pendingTasks.onTasksComplete { - mainHandler.post { + if (Flags.enableBackgroundKeyguardOndrawnCallback()) { + // called by whatever thread completes the last task registered. onDrawn.run() + } else { + mainHandler.post { onDrawn.run() } } } Trace.endSection() diff --git a/packages/SystemUI/src/com/android/systemui/CoreStartable.java b/packages/SystemUI/src/com/android/systemui/CoreStartable.java index 7295936ddc7c..4c9782cdf36c 100644 --- a/packages/SystemUI/src/com/android/systemui/CoreStartable.java +++ b/packages/SystemUI/src/com/android/systemui/CoreStartable.java @@ -33,6 +33,9 @@ import java.io.PrintWriter; * abstract fun bind(impl: FoobarStartable): CoreStartable * </pre> * + * If your CoreStartable depends on different CoreStartables starting before it, use a + * {@link com.android.systemui.startable.Dependencies} annotation to list out those dependencies. + * * @see SystemUIApplication#startServicesIfNeeded() */ public interface CoreStartable extends Dumpable { diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 01f6971de373..8aae20651a10 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -16,6 +16,7 @@ package com.android.systemui; +import android.annotation.SuppressLint; import android.app.ActivityThread; import android.app.Application; import android.app.Notification; @@ -26,27 +27,33 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.os.Bundle; -import android.os.Looper; import android.os.Process; -import android.os.SystemProperties; import android.os.Trace; -import android.os.UserHandle; import android.util.Log; import android.util.TimingsTraceLog; import android.view.SurfaceControl; import android.view.ThreadedRenderer; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + import com.android.internal.protolog.common.ProtoLog; import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dump.DumpManager; import com.android.systemui.res.R; +import com.android.systemui.startable.Dependencies; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.NotificationChannels; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayDeque; +import java.util.Arrays; import java.util.Comparator; +import java.util.HashSet; import java.util.Map; +import java.util.StringJoiner; import java.util.TreeMap; import javax.inject.Provider; @@ -78,10 +85,17 @@ public class SystemUIApplication extends Application implements ProtoLog.REQUIRE_PROTOLOGTOOL = false; } + @VisibleForTesting + @Override + public void attachBaseContext(Context base) { + super.attachBaseContext(base); + } + protected GlobalRootComponent getRootComponent() { return mInitializer.getRootComponent(); } + @SuppressLint("RegisterReceiverViaContext") @Override public void onCreate() { super.onCreate(); @@ -96,9 +110,11 @@ public class SystemUIApplication extends Application implements mBootCompleteCache = mSysUIComponent.provideBootCacheImpl(); log.traceEnd(); + GlobalRootComponent rootComponent = mInitializer.getRootComponent(); + // Enable Looper trace points. // This allows us to see Handler callbacks on traces. - Looper.getMainLooper().setTraceTag(Trace.TRACE_TAG_APP); + rootComponent.getMainLooper().setTraceTag(Trace.TRACE_TAG_APP); // Set the application theme that is inherited by all services. Note that setting the // application theme in the manifest does only work for activities. Keep this in sync with @@ -106,15 +122,17 @@ public class SystemUIApplication extends Application implements setTheme(R.style.Theme_SystemUI); View.setTraceLayoutSteps( - SystemProperties.getBoolean("persist.debug.trace_layouts", false)); + rootComponent.getSystemPropertiesHelper() + .getBoolean("persist.debug.trace_layouts", false)); View.setTracedRequestLayoutClassClass( - SystemProperties.get("persist.debug.trace_request_layout_class", null)); + rootComponent.getSystemPropertiesHelper() + .get("persist.debug.trace_request_layout_class", null)); if (Flags.enableLayoutTracing()) { View.setTraceLayoutSteps(true); } - if (Process.myUserHandle().equals(UserHandle.SYSTEM)) { + if (rootComponent.getProcessWrapper().isSystemUser()) { IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED); bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); @@ -175,8 +193,8 @@ public class SystemUIApplication extends Application implements } /** - * Makes sure that all the SystemUI services are running. If they are already running, this is a - * no-op. This is needed to conditinally start all the services, as we only need to have it in + * Makes sure that all the CoreStartables are running. If they are already running, this is a + * no-op. This is needed to conditionally start all the services, as we only need to have it in * the main process. * <p>This method must only be called from the main thread.</p> */ @@ -221,7 +239,8 @@ public class SystemUIApplication extends Application implements if (!mBootCompleteCache.isBootComplete()) { // check to see if maybe it was already completed long before we began // see ActivityManagerService.finishBooting() - if ("1".equals(SystemProperties.get("sys.boot_completed"))) { + if ("1".equals(getRootComponent().getSystemPropertiesHelper() + .get("sys.boot_completed"))) { mBootCompleteCache.setBootComplete(); if (DEBUG) { Log.v(TAG, "BOOT_COMPLETED was already sent"); @@ -237,17 +256,78 @@ public class SystemUIApplication extends Application implements Trace.TRACE_TAG_APP); log.traceBegin(metricsPrefix); - int i = 0; - for (Map.Entry<Class<?>, Provider<CoreStartable>> entry : startables.entrySet()) { - String clsName = entry.getKey().getName(); - int j = i; // Copied to make lambda happy. - timeInitialization( - clsName, - () -> mServices[j] = startStartable(clsName, entry.getValue()), - log, - metricsPrefix); - i++; + HashSet<Class<?>> startedStartables = new HashSet<>(); + + // Perform a form of topological sort: + // 1) Iterate through a queue of all non-started startables + // If the startable has all of its dependencies met + // - start it + // Else + // - enqueue it for the next iteration + // 2) If anything was started and the "next" queue is not empty, loop back to 1 + // 3) If we're done looping and there are any non-started startables left, throw an error. + // + // This "sort" is not very optimized. We assume that most CoreStartables don't have many + // dependencies - zero in fact. We assume two or three iterations of this loop will be + // enough. If that ever changes, it may be worth revisiting. + + log.traceBegin("Topologically start Core Startables"); + boolean startedAny = false; + ArrayDeque<Map.Entry<Class<?>, Provider<CoreStartable>>> queue; + ArrayDeque<Map.Entry<Class<?>, Provider<CoreStartable>>> nextQueue = + new ArrayDeque<>(startables.entrySet()); + int numIterations = 0; + + int serviceIndex = 0; + + do { + queue = nextQueue; + nextQueue = new ArrayDeque<>(startables.size()); + + while (!queue.isEmpty()) { + Map.Entry<Class<?>, Provider<CoreStartable>> entry = queue.removeFirst(); + + Class<?> cls = entry.getKey(); + Dependencies dep = cls.getAnnotation(Dependencies.class); + Class<? extends CoreStartable>[] deps = (dep == null ? null : dep.value()); + if (deps == null || startedStartables.containsAll(Arrays.asList(deps))) { + String clsName = cls.getName(); + int i = serviceIndex; // Copied to make lambda happy. + timeInitialization( + clsName, + () -> mServices[i] = startStartable(clsName, entry.getValue()), + log, + metricsPrefix); + startedStartables.add(cls); + startedAny = true; + serviceIndex++; + } else { + nextQueue.add(entry); + } + } + numIterations++; + } while (startedAny && !nextQueue.isEmpty()); // if none were started, stop. + + if (!nextQueue.isEmpty()) { // If some startables were left over, throw an error. + while (!nextQueue.isEmpty()) { + Map.Entry<Class<?>, Provider<CoreStartable>> entry = nextQueue.removeFirst(); + Class<?> cls = entry.getKey(); + Dependencies dep = cls.getAnnotation(Dependencies.class); + Class<? extends CoreStartable>[] deps = (dep == null ? null : dep.value()); + StringJoiner stringJoiner = new StringJoiner(", "); + for (int i = 0; deps != null && i < deps.length; i++) { + if (!startedStartables.contains(deps[i])) { + stringJoiner.add(deps[i].getName()); + } + } + Log.e(TAG, "Failed to start " + cls.getName() + + ". Missing dependencies: [" + stringJoiner + "]"); + } + + throw new RuntimeException("Failed to start all CoreStartables. Check logcat!"); } + Log.i(TAG, "Topological CoreStartables completed in " + numIterations + " iterations"); + log.traceEnd(); if (vendorComponent != null) { timeInitialization( @@ -258,8 +338,8 @@ public class SystemUIApplication extends Application implements metricsPrefix); } - for (i = 0; i < mServices.length; i++) { - final CoreStartable service = mServices[i]; + for (serviceIndex = 0; serviceIndex < mServices.length; serviceIndex++) { + final CoreStartable service = mServices[serviceIndex]; if (mBootCompleteCache.isBootComplete()) { notifyBootCompleted(service); } @@ -308,10 +388,14 @@ public class SystemUIApplication extends Application implements Trace.TRACE_TAG_APP, clsName + ".newInstance()"); } try { - startable = (CoreStartable) Class.forName(clsName).newInstance(); + startable = (CoreStartable) Class.forName(clsName) + .getDeclaredConstructor() + .newInstance(); } catch (ClassNotFoundException - | IllegalAccessException - | InstantiationException ex) { + | IllegalAccessException + | InstantiationException + | NoSuchMethodException + | InvocationTargetException ex) { throw new RuntimeException(ex); } finally { Trace.endSection(); @@ -344,7 +428,7 @@ public class SystemUIApplication extends Application implements } @Override - public void onConfigurationChanged(Configuration newConfig) { + public void onConfigurationChanged(@NonNull Configuration newConfig) { if (mServicesStarted) { ConfigurationController configController = mSysUIComponent.getConfigurationController(); if (Trace.isEnabled()) { @@ -363,7 +447,7 @@ public class SystemUIApplication extends Application implements @Override public void setContextAvailableCallback( - SystemUIAppComponentFactoryBase.ContextAvailableCallback callback) { + @NonNull SystemUIAppComponentFactoryBase.ContextAvailableCallback callback) { mContextAvailableCallback = callback; } diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt index f2b55f456f00..49f34f18b06e 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt @@ -18,6 +18,7 @@ package com.android.systemui.authentication.data.repository +import android.annotation.UserIdInt import android.app.admin.DevicePolicyManager import android.content.IntentFilter import android.os.UserHandle @@ -25,6 +26,11 @@ import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockscreenCredential import com.android.keyguard.KeyguardSecurityModel import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.None +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Password +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pattern +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pin +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Sim import com.android.systemui.authentication.shared.model.AuthenticationResultModel import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton @@ -124,6 +130,12 @@ interface AuthenticationRepository { val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> /** + * Checks the given [LockscreenCredential] to see if it's correct, returning an + * [AuthenticationResultModel] representing what happened. + */ + suspend fun checkCredential(credential: LockscreenCredential): AuthenticationResultModel + + /** * Returns the currently-configured authentication method. This determines how the * authentication challenge needs to be completed in order to unlock an otherwise locked device. * @@ -147,10 +159,26 @@ interface AuthenticationRepository { suspend fun reportLockoutStarted(durationMs: Int) /** - * Checks the given [LockscreenCredential] to see if it's correct, returning an - * [AuthenticationResultModel] representing what happened. + * Returns the current maximum number of login attempts that are allowed before the device or + * profile is wiped. + * + * If there is no wipe policy, returns `0`. + * + * @see [DevicePolicyManager.getMaximumFailedPasswordsForWipe] */ - suspend fun checkCredential(credential: LockscreenCredential): AuthenticationResultModel + suspend fun getMaxFailedUnlockAttemptsForWipe(): Int + + /** + * Returns the user that will be wiped first when too many failed attempts are made to unlock + * the device by the selected user. That user is either the same as the current user ID or + * belongs to the same profile group. + * + * When there is no such policy, returns [UserHandle.USER_NULL]. E.g. managed profile user may + * be wiped as a result of failed primary profile password attempts when using unified + * challenge. Primary user may be wiped as a result of failed password attempts on the managed + * profile of an organization-owned device. + */ + @UserIdInt suspend fun getProfileWithMinFailedUnlockAttemptsForWipe(): Int } @SysUISingleton @@ -164,6 +192,7 @@ constructor( private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>, private val userRepository: UserRepository, private val lockPatternUtils: LockPatternUtils, + private val devicePolicyManager: DevicePolicyManager, broadcastDispatcher: BroadcastDispatcher, mobileConnectionsRepository: MobileConnectionsRepository, ) : AuthenticationRepository { @@ -200,11 +229,7 @@ constructor( .onStart { emit(Unit) } .map { selectedUserId } } - .map { selectedUserId -> - withContext(backgroundDispatcher) { - blockingAuthenticationMethodInternal(selectedUserId) - } - } + .map(::getAuthenticationMethod) .distinctUntilChanged() override val minPatternLength: Int = LockPatternUtils.MIN_LOCK_PATTERN_SIZE @@ -242,12 +267,22 @@ constructor( } } - override suspend fun getAuthenticationMethod(): AuthenticationMethodModel { + override suspend fun checkCredential( + credential: LockscreenCredential + ): AuthenticationResultModel { return withContext(backgroundDispatcher) { - blockingAuthenticationMethodInternal(selectedUserId) + try { + val matched = lockPatternUtils.checkCredential(credential, selectedUserId) {} + AuthenticationResultModel(isSuccessful = matched, lockoutDurationMs = 0) + } catch (ex: LockPatternUtils.RequestThrottledException) { + AuthenticationResultModel(isSuccessful = false, lockoutDurationMs = ex.timeoutMs) + } } } + override suspend fun getAuthenticationMethod(): AuthenticationMethodModel = + getAuthenticationMethod(selectedUserId) + override suspend fun getPinLength(): Int { return withContext(backgroundDispatcher) { lockPatternUtils.getPinLength(selectedUserId) } } @@ -272,27 +307,26 @@ constructor( _hasLockoutOccurred.value = true } - override suspend fun checkCredential( - credential: LockscreenCredential - ): AuthenticationResultModel { + private suspend fun getFailedAuthenticationAttemptCount(): Int { return withContext(backgroundDispatcher) { - try { - val matched = lockPatternUtils.checkCredential(credential, selectedUserId) {} - AuthenticationResultModel(isSuccessful = matched, lockoutDurationMs = 0) - } catch (ex: LockPatternUtils.RequestThrottledException) { - AuthenticationResultModel(isSuccessful = false, lockoutDurationMs = ex.timeoutMs) - } + lockPatternUtils.getCurrentFailedPasswordAttempts(selectedUserId) } } - private suspend fun getFailedAuthenticationAttemptCount(): Int { + override suspend fun getMaxFailedUnlockAttemptsForWipe(): Int { return withContext(backgroundDispatcher) { - lockPatternUtils.getCurrentFailedPasswordAttempts(selectedUserId) + lockPatternUtils.getMaximumFailedPasswordsForWipe(selectedUserId) + } + } + + override suspend fun getProfileWithMinFailedUnlockAttemptsForWipe(): Int { + return withContext(backgroundDispatcher) { + devicePolicyManager.getProfileWithMinimumFailedPasswordsForWipe(selectedUserId) } } private val selectedUserId: Int - get() = userRepository.getSelectedUserInfo().id + @UserIdInt get() = userRepository.getSelectedUserInfo().id /** * Returns a [StateFlow] that's automatically kept fresh. The passed-in [getFreshValue] is @@ -336,24 +370,18 @@ constructor( return flow.asStateFlow() } - /** - * Returns the authentication method for the given user ID. - * - * WARNING: this is actually a blocking IPC/"binder" call that's expensive to do on the main - * thread. We keep it not marked as `suspend` because we want to be able to run this without a - * `runBlocking` which has a ton of performance/blocking problems. - */ - private fun blockingAuthenticationMethodInternal( - userId: Int, - ): AuthenticationMethodModel { - return when (getSecurityMode.apply(userId)) { - KeyguardSecurityModel.SecurityMode.PIN -> AuthenticationMethodModel.Pin - KeyguardSecurityModel.SecurityMode.SimPin, - KeyguardSecurityModel.SecurityMode.SimPuk -> AuthenticationMethodModel.Sim - KeyguardSecurityModel.SecurityMode.Password -> AuthenticationMethodModel.Password - KeyguardSecurityModel.SecurityMode.Pattern -> AuthenticationMethodModel.Pattern - KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None - KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!") + /** Returns the authentication method for the given user ID. */ + private suspend fun getAuthenticationMethod(@UserIdInt userId: Int): AuthenticationMethodModel { + return withContext(backgroundDispatcher) { + when (getSecurityMode.apply(userId)) { + KeyguardSecurityModel.SecurityMode.PIN -> Pin + KeyguardSecurityModel.SecurityMode.SimPin, + KeyguardSecurityModel.SecurityMode.SimPuk -> Sim + KeyguardSecurityModel.SecurityMode.Password -> Password + KeyguardSecurityModel.SecurityMode.Pattern -> Pattern + KeyguardSecurityModel.SecurityMode.None -> None + KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!") + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt index c85ffe6ca56f..fdccad137a24 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt @@ -16,15 +16,24 @@ package com.android.systemui.authentication.domain.interactor +import android.os.UserHandle +import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockPatternView import com.android.internal.widget.LockscreenCredential import com.android.systemui.authentication.data.repository.AuthenticationRepository import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Password +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pattern +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pin import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate +import com.android.systemui.authentication.shared.model.AuthenticationWipeModel +import com.android.systemui.authentication.shared.model.AuthenticationWipeModel.WipeTarget import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.time.SystemClock import javax.inject.Inject +import kotlin.math.max import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -49,6 +58,7 @@ class AuthenticationInteractor constructor( @Application private val applicationScope: CoroutineScope, private val repository: AuthenticationRepository, + private val selectedUserInteractor: SelectedUserInteractor, ) { /** * The currently-configured authentication method. This determines how the authentication @@ -140,6 +150,35 @@ constructor( get() = repository.lockoutEndTimestamp /** + * Models an imminent wipe risk to the user, profile, or device upon further unsuccessful + * authentication attempts. + * + * Returns `null` when there is no risk of wipe yet, or when there's no wipe policy set by the + * DevicePolicyManager. + */ + val upcomingWipe: Flow<AuthenticationWipeModel?> = + repository.failedAuthenticationAttempts.map { failedAttempts -> + val failedAttemptsBeforeWipe = repository.getMaxFailedUnlockAttemptsForWipe() + if (failedAttemptsBeforeWipe == 0) { + return@map null // There is no restriction. + } + + // The user has a DevicePolicyManager that requests a user/profile to be wiped after N + // attempts. Once the grace period is reached, show a dialog every time as a clear + // warning until the deletion fires. + val remainingAttemptsBeforeWipe = max(0, failedAttemptsBeforeWipe - failedAttempts) + if (remainingAttemptsBeforeWipe >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { + return@map null // There is no current risk of wiping the device. + } + + AuthenticationWipeModel( + wipeTarget = getWipeTarget(), + failedAttempts = failedAttempts, + remainingAttempts = remainingAttemptsBeforeWipe, + ) + } + + /** * Returns the currently-configured authentication method. This determines how the * authentication challenge needs to be completed in order to unlock an otherwise locked device. * @@ -154,7 +193,8 @@ constructor( suspend fun getAuthenticationMethod() = repository.getAuthenticationMethod() /** - * Attempts to authenticate the user and unlock the device. + * Attempts to authenticate the user and unlock the device. May trigger lockout or wipe the + * user/profile/device data upon failure. * * If [tryAutoConfirm] is `true`, authentication is attempted if and only if the auth method * supports auto-confirming, and the input's length is at least the required length. Otherwise, @@ -175,21 +215,7 @@ constructor( } val authMethod = getAuthenticationMethod() - val skipCheck = - when { - // Lockout is active, the UI layer should not have called this; skip the attempt. - repository.lockoutEndTimestamp != null -> true - // The input is too short; skip the attempt. - input.isTooShort(authMethod) -> true - // Auto-confirm attempt when the feature is not enabled; skip the attempt. - tryAutoConfirm && !isAutoConfirmEnabled.value -> true - // Auto-confirm should skip the attempt if the pin entered is too short. - tryAutoConfirm && - authMethod == AuthenticationMethodModel.Pin && - input.size < repository.getPinLength() -> true - else -> false - } - if (skipCheck) { + if (shouldSkipAuthenticationAttempt(authMethod, tryAutoConfirm, input.size)) { return AuthenticationResult.SKIPPED } @@ -198,43 +224,85 @@ constructor( val authenticationResult = repository.checkCredential(credential) credential.zeroize() - if (authenticationResult.isSuccessful || !tryAutoConfirm) { - repository.reportAuthenticationAttempt(authenticationResult.isSuccessful) + if (authenticationResult.isSuccessful) { + repository.reportAuthenticationAttempt(isSuccessful = true) + _onAuthenticationResult.emit(true) + return AuthenticationResult.SUCCEEDED } - // Check if lockout should start and, if so, kick off the countdown: - if (!authenticationResult.isSuccessful && authenticationResult.lockoutDurationMs > 0) { - repository.reportLockoutStarted(authenticationResult.lockoutDurationMs) + // Authentication failed. + + if (tryAutoConfirm) { + // Auto-confirm is active, the failed attempt should have no side-effects. + return AuthenticationResult.FAILED } - if (authenticationResult.isSuccessful || !tryAutoConfirm) { - _onAuthenticationResult.emit(authenticationResult.isSuccessful) + repository.reportAuthenticationAttempt(isSuccessful = false) + + if (authenticationResult.lockoutDurationMs > 0) { + // Lockout has been triggered. + repository.reportLockoutStarted(authenticationResult.lockoutDurationMs) } - return if (authenticationResult.isSuccessful) { - AuthenticationResult.SUCCEEDED - } else { - AuthenticationResult.FAILED + _onAuthenticationResult.emit(false) + return AuthenticationResult.FAILED + } + + private suspend fun shouldSkipAuthenticationAttempt( + authenticationMethod: AuthenticationMethodModel, + isAutoConfirmAttempt: Boolean, + inputLength: Int, + ): Boolean { + return when { + // Lockout is active, the UI layer should not have called this; skip the attempt. + repository.lockoutEndTimestamp != null -> true + // Auto-confirm attempt when the feature is not enabled; skip the attempt. + isAutoConfirmAttempt && !isAutoConfirmEnabled.value -> true + // The pin is too short; skip only if this is an auto-confirm attempt. + authenticationMethod == Pin && authenticationMethod.isInputTooShort(inputLength) -> + isAutoConfirmAttempt + // The input is too short. + authenticationMethod.isInputTooShort(inputLength) -> true + else -> false } } - private fun List<Any>.isTooShort(authMethod: AuthenticationMethodModel): Boolean { - return when (authMethod) { - AuthenticationMethodModel.Pattern -> size < repository.minPatternLength - AuthenticationMethodModel.Password -> size < repository.minPasswordLength + private suspend fun AuthenticationMethodModel.isInputTooShort(inputLength: Int): Boolean { + return when (this) { + Pattern -> inputLength < repository.minPatternLength + Password -> inputLength < repository.minPasswordLength + Pin -> inputLength < repository.getPinLength() else -> false } } + /** + * @return Whether the current user, managed profile or whole device is next at risk of wipe. + */ + private suspend fun getWipeTarget(): WipeTarget { + // Check which profile has the strictest policy for failed authentication attempts. + val userToBeWiped = repository.getProfileWithMinFailedUnlockAttemptsForWipe() + return when (userToBeWiped) { + selectedUserInteractor.getSelectedUserId() -> + if (userToBeWiped == UserHandle.USER_SYSTEM) { + WipeTarget.WholeDevice + } else { + WipeTarget.User + } + + // Shouldn't happen at this stage; this is to maintain legacy behavior. + UserHandle.USER_NULL -> WipeTarget.WholeDevice + else -> WipeTarget.ManagedProfile + } + } + private fun AuthenticationMethodModel.createCredential( input: List<Any> ): LockscreenCredential? { return when (this) { - is AuthenticationMethodModel.Pin -> - LockscreenCredential.createPin(input.joinToString("")) - is AuthenticationMethodModel.Password -> - LockscreenCredential.createPassword(input.joinToString("")) - is AuthenticationMethodModel.Pattern -> + is Pin -> LockscreenCredential.createPin(input.joinToString("")) + is Password -> LockscreenCredential.createPassword(input.joinToString("")) + is Pattern -> LockscreenCredential.createPattern( input .map { it as AuthenticationPatternCoordinate } diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt index 3552a1957f1a..4e45fcc25fb8 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt @@ -30,13 +30,13 @@ sealed class AuthenticationMethodModel( * Device doesn't use a secure authentication method. Either there is no lockscreen or the lock * screen can be swiped away when displayed. */ - object None : AuthenticationMethodModel(isSecure = false) + data object None : AuthenticationMethodModel(isSecure = false) - object Pin : AuthenticationMethodModel(isSecure = true) + data object Pin : AuthenticationMethodModel(isSecure = true) - object Password : AuthenticationMethodModel(isSecure = true) + data object Password : AuthenticationMethodModel(isSecure = true) - object Pattern : AuthenticationMethodModel(isSecure = true) + data object Pattern : AuthenticationMethodModel(isSecure = true) - object Sim : AuthenticationMethodModel(isSecure = true) + data object Sim : AuthenticationMethodModel(isSecure = true) } diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationWipeModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationWipeModel.kt new file mode 100644 index 000000000000..7a2b83f2de84 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationWipeModel.kt @@ -0,0 +1,65 @@ +/* + * 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.authentication.shared.model + +import androidx.annotation.StringRes +import com.android.systemui.res.R + +/** + * Some users have a DevicePolicyManager that requests a user/profile to be wiped after N + * unsuccessful authentication attempts. This models the pre-wipe state, so that a warning can be + * shown. + */ +data class AuthenticationWipeModel( + /** Indicates what part of the user data will be removed. */ + val wipeTarget: WipeTarget, + + /** Unsuccessful authentication attempts since the last successful device entry. */ + val failedAttempts: Int, + + /** + * Remaining failed authentication attempts before wipe is triggered. 0 indicates a wipe is + * imminent, no more authentication attempts are allowed. + */ + val remainingAttempts: Int, +) { + sealed class WipeTarget( + @StringRes val messageIdForAlmostWipe: Int, + @StringRes val messageIdForWipe: Int, + ) { + /** The work profile will be removed, which will delete all profile data. */ + data object ManagedProfile : + WipeTarget( + messageIdForAlmostWipe = R.string.kg_failed_attempts_almost_at_erase_profile, + messageIdForWipe = R.string.kg_failed_attempts_now_erasing_profile, + ) + + /** The user will be removed, which will delete all user data. */ + data object User : + WipeTarget( + messageIdForAlmostWipe = R.string.kg_failed_attempts_almost_at_erase_user, + messageIdForWipe = R.string.kg_failed_attempts_now_erasing_user, + ) + + /** The device will be reset and all data will be deleted. */ + data object WholeDevice : + WipeTarget( + messageIdForAlmostWipe = R.string.kg_failed_attempts_almost_at_wipe, + messageIdForWipe = R.string.kg_failed_attempts_now_wiping, + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 8a1a2da6cf3f..a4f90ebfb83c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -106,6 +106,7 @@ import javax.inject.Inject; import javax.inject.Provider; import kotlinx.coroutines.CoroutineScope; +import kotlinx.coroutines.Job; /** * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the @@ -136,6 +137,7 @@ public class AuthController implements private final Provider<UdfpsController> mUdfpsControllerFactory; private final Provider<SideFpsController> mSidefpsControllerFactory; private final CoroutineScope mApplicationCoroutineScope; + private Job mBiometricContextListenerJob = null; // TODO: these should be migrated out once ready @NonNull private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor; @@ -914,7 +916,11 @@ public class AuthController implements @Override public void setBiometricContextListener(IBiometricContextListener listener) { - mLogContextInteractor.get().addBiometricContextListener(listener); + if (mBiometricContextListenerJob != null) { + mBiometricContextListenerJob.cancel(null); + } + mBiometricContextListenerJob = + mLogContextInteractor.get().addBiometricContextListener(listener); } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt index f4231ac01fee..c320350e69cd 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt @@ -26,6 +26,8 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.isDefaultOrientation import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.log.SideFpsLogger import com.android.systemui.res.R import java.util.Optional @@ -47,6 +49,7 @@ constructor( windowManager: WindowManager, displayStateInteractor: DisplayStateInteractor, fingerprintInteractiveToAuthProvider: Optional<FingerprintInteractiveToAuthProvider>, + keyguardTransitionInteractor: KeyguardTransitionInteractor, private val logger: SideFpsLogger, ) { @@ -62,8 +65,21 @@ constructor( val isAvailable: Flow<Boolean> = fingerprintPropertyRepository.sensorType.map { it == FingerprintSensorType.POWER_BUTTON } - val authenticationDuration: Long = - context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L + val authenticationDuration: Flow<Long> = + keyguardTransitionInteractor + .isFinishedInStateWhere { it == KeyguardState.OFF || it == KeyguardState.DOZING } + .map { + if (it) + context.resources + ?.getInteger(R.integer.config_restToUnlockDurationScreenOff) + ?.toLong() + else + context.resources + ?.getInteger(R.integer.config_restToUnlockDurationDefault) + ?.toLong() + } + .map { it ?: 0L } + .onEach { logger.authDurationChanged(it) } val isProlongedTouchRequiredForAuthentication: Flow<Boolean> = if (fingerprintInteractiveToAuthProvider.isEmpty) { diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt index 1095abe24b47..81d822fa7b03 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt @@ -20,6 +20,10 @@ import android.content.Context import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Password +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pattern +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pin +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Sim import com.android.systemui.bouncer.data.repository.BouncerRepository import com.android.systemui.classifier.FalsingClassifier import com.android.systemui.classifier.domain.interactor.FalsingInteractor @@ -158,7 +162,7 @@ constructor( return AuthenticationResult.SKIPPED } - if (authenticationInteractor.getAuthenticationMethod() == AuthenticationMethodModel.Sim) { + if (authenticationInteractor.getAuthenticationMethod() == Sim) { // SIM is authenticated in SimBouncerInteractor. return AuthenticationResult.SKIPPED } @@ -178,21 +182,21 @@ constructor( authResult == AuthenticationResult.FAILED || (authResult == AuthenticationResult.SKIPPED && !tryAutoConfirm) ) { - showErrorMessage() + showWrongInputMessage() } return authResult } /** - * Shows the error message. + * Shows the a message notifying the user that their credentials input is wrong. * * Callers should use this instead of [authenticate] when they know ahead of time that an auth * attempt will fail but aren't interested in the other side effects like triggering lockout. * For example, if the user entered a pattern that's too short, the system can show the error * message without having the attempt trigger lockout. */ - private suspend fun showErrorMessage() { - repository.setMessage(errorMessage(authenticationInteractor.getAuthenticationMethod())) + private suspend fun showWrongInputMessage() { + repository.setMessage(wrongInputMessage(authenticationInteractor.getAuthenticationMethod())) } /** Notifies that the input method editor (software keyboard) has been hidden by the user. */ @@ -202,24 +206,19 @@ constructor( private fun promptMessage(authMethod: AuthenticationMethodModel): String { return when (authMethod) { - is AuthenticationMethodModel.Sim -> simBouncerInteractor.getDefaultMessage() - is AuthenticationMethodModel.Pin -> - applicationContext.getString(R.string.keyguard_enter_your_pin) - is AuthenticationMethodModel.Password -> - applicationContext.getString(R.string.keyguard_enter_your_password) - is AuthenticationMethodModel.Pattern -> - applicationContext.getString(R.string.keyguard_enter_your_pattern) + is Sim -> simBouncerInteractor.getDefaultMessage() + is Pin -> applicationContext.getString(R.string.keyguard_enter_your_pin) + is Password -> applicationContext.getString(R.string.keyguard_enter_your_password) + is Pattern -> applicationContext.getString(R.string.keyguard_enter_your_pattern) else -> "" } } - private fun errorMessage(authMethod: AuthenticationMethodModel): String { + private fun wrongInputMessage(authMethod: AuthenticationMethodModel): String { return when (authMethod) { - is AuthenticationMethodModel.Pin -> applicationContext.getString(R.string.kg_wrong_pin) - is AuthenticationMethodModel.Password -> - applicationContext.getString(R.string.kg_wrong_password) - is AuthenticationMethodModel.Pattern -> - applicationContext.getString(R.string.kg_wrong_pattern) + is Pin -> applicationContext.getString(R.string.kg_wrong_pin) + is Password -> applicationContext.getString(R.string.kg_wrong_password) + is Pattern -> applicationContext.getString(R.string.kg_wrong_pattern) else -> "" } } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt index f612f9afed77..b587ed846a38 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt @@ -22,6 +22,7 @@ import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardSecurityModel.SecurityMode import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback +import com.android.systemui.Flags import com.android.systemui.biometrics.data.repository.FacePropertyRepository import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.bouncer.data.repository.BouncerMessageRepository @@ -29,8 +30,6 @@ import com.android.systemui.bouncer.shared.model.BouncerMessageModel import com.android.systemui.bouncer.shared.model.Message 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.REVAMPED_BOUNCER_MESSAGES import com.android.systemui.flags.SystemPropertiesHelper import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository @@ -100,7 +99,6 @@ constructor( private val repository: BouncerMessageRepository, private val userRepository: UserRepository, private val countDownTimerUtil: CountDownTimerUtil, - private val featureFlags: FeatureFlags, private val updateMonitor: KeyguardUpdateMonitor, trustRepository: TrustRepository, biometricSettingsRepository: BiometricSettingsRepository, @@ -229,7 +227,7 @@ constructor( } fun onPrimaryAuthLockedOut(secondsBeforeLockoutReset: Long) { - if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return + if (!Flags.revampedBouncerMessages()) return val callback = object : CountDownTimerCallback { @@ -250,7 +248,7 @@ constructor( } fun onPrimaryAuthIncorrectAttempt() { - if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return + if (!Flags.revampedBouncerMessages()) return repository.setMessage( incorrectSecurityInput(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value) @@ -258,21 +256,21 @@ constructor( } fun setFingerprintAcquisitionMessage(value: String?) { - if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return + if (!Flags.revampedBouncerMessages()) return repository.setMessage( defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value) ) } fun setFaceAcquisitionMessage(value: String?) { - if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return + if (!Flags.revampedBouncerMessages()) return repository.setMessage( defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value) ) } fun setCustomMessage(value: String?) { - if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return + if (!Flags.revampedBouncerMessages()) return repository.setMessage( defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value) @@ -283,7 +281,7 @@ constructor( get() = defaultMessage(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value) fun onPrimaryBouncerUserInput() { - if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return + if (!Flags.revampedBouncerMessages()) return repository.setMessage(defaultMessage) } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerMessageViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerMessageViewBinder.kt index 5a59012a74b8..b8e6ad6956fe 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerMessageViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerMessageViewBinder.kt @@ -23,11 +23,10 @@ import androidx.lifecycle.repeatOnLifecycle import com.android.keyguard.BouncerKeyguardMessageArea import com.android.keyguard.KeyguardMessageArea import com.android.keyguard.KeyguardMessageAreaController +import com.android.systemui.Flags import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor import com.android.systemui.bouncer.shared.model.Message import com.android.systemui.bouncer.ui.BouncerMessageView -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.log.BouncerLogger import kotlinx.coroutines.launch @@ -39,10 +38,9 @@ object BouncerMessageViewBinder { interactor: BouncerMessageInteractor, factory: KeyguardMessageAreaController.Factory, bouncerLogger: BouncerLogger, - featureFlags: FeatureFlags ) { view.repeatWhenAttached { - if (!featureFlags.isEnabled(Flags.REVAMPED_BOUNCER_MESSAGES)) { + if (!Flags.revampedBouncerMessages()) { view.primaryMessageView?.disable() view.secondaryMessageView?.disable() return@repeatWhenAttached diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt index 5dcd6615509d..cc387e98aa23 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt @@ -32,7 +32,6 @@ import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE import com.android.systemui.bouncer.ui.BouncerViewDelegate import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel -import com.android.systemui.flags.FeatureFlags import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.log.BouncerLogger @@ -53,7 +52,6 @@ object KeyguardBouncerViewBinder { messageAreaControllerFactory: KeyguardMessageAreaController.Factory, bouncerMessageInteractor: BouncerMessageInteractor, bouncerLogger: BouncerLogger, - featureFlags: FeatureFlags, selectedUserInteractor: SelectedUserInteractor, ) { // Builds the KeyguardSecurityContainerController from bouncer view group. @@ -141,8 +139,7 @@ object KeyguardBouncerViewBinder { it.bindMessageView( bouncerMessageInteractor, messageAreaControllerFactory, - bouncerLogger, - featureFlags + bouncerLogger ) } } else { diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt index be6cf85a5a0e..4d686a1ba0d4 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt @@ -16,12 +16,15 @@ package com.android.systemui.bouncer.ui.viewmodel +import android.app.admin.DevicePolicyManager +import android.app.admin.DevicePolicyResources import android.content.Context import android.graphics.Bitmap import androidx.core.graphics.drawable.toBitmap import com.android.internal.R import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.authentication.shared.model.AuthenticationWipeModel import com.android.systemui.bouncer.domain.interactor.BouncerActionButtonInteractor import com.android.systemui.bouncer.domain.interactor.BouncerInteractor import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor @@ -51,7 +54,6 @@ import kotlinx.coroutines.flow.Flow 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.map import kotlinx.coroutines.flow.stateIn @@ -64,14 +66,15 @@ class BouncerViewModel( @Application private val applicationScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, private val bouncerInteractor: BouncerInteractor, + private val simBouncerInteractor: SimBouncerInteractor, private val authenticationInteractor: AuthenticationInteractor, flags: SceneContainerFlags, selectedUser: Flow<UserViewModel>, users: Flow<List<UserViewModel>>, userSwitcherMenu: Flow<List<UserActionViewModel>>, - actionButtonInteractor: BouncerActionButtonInteractor, - private val simBouncerInteractor: SimBouncerInteractor, + actionButton: Flow<BouncerActionButtonModel?>, private val clock: SystemClock, + private val devicePolicyManager: DevicePolicyManager, ) { val selectedUserImage: StateFlow<Bitmap?> = selectedUser @@ -113,7 +116,6 @@ class BouncerViewModel( // Handle to the scope of the child ViewModel (stored in [authMethod]). private var childViewModelScope: CoroutineScope? = null - private val _dialogMessage = MutableStateFlow<String?>(null) /** View-model for the current UI, based on the current authentication method. */ val authMethodViewModel: StateFlow<AuthMethodBouncerViewModel?> = @@ -129,12 +131,32 @@ class BouncerViewModel( * A message for a dialog to show when the user has attempted the wrong credential too many * times and now must wait a while before attempting again. * - * If `null`, no dialog should be shown. + * If `null`, the lockout dialog should not be shown. + */ + private val lockoutDialogMessage = MutableStateFlow<String?>(null) + + /** + * A message for a dialog to show when the user has attempted the wrong credential too many + * times and their user/profile/device data is at risk of being wiped due to a Device Manager + * policy. * - * Once the dialog is shown, the UI should call [onDialogDismissed] when the user dismisses this - * dialog. + * If `null`, the wipe dialog should not be shown. */ - val dialogMessage: StateFlow<String?> = _dialogMessage.asStateFlow() + private val wipeDialogMessage = MutableStateFlow<String?>(null) + + /** + * Models the dialog to be shown to the user, or `null` if no dialog should be shown. + * + * Once the dialog is shown, the UI should call [DialogViewModel.onDismiss] when the user + * dismisses this dialog. + */ + val dialogViewModel: StateFlow<DialogViewModel?> = + combine(wipeDialogMessage, lockoutDialogMessage) { _, _ -> createDialogViewModel() } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = createDialogViewModel(), + ) /** * A message shown when the user has attempted the wrong credential too many times and now must @@ -159,7 +181,7 @@ class BouncerViewModel( * be shown. */ val actionButton: StateFlow<BouncerActionButtonModel?> = - actionButtonInteractor.actionButton.stateIn( + actionButton.stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = null @@ -208,6 +230,7 @@ class BouncerViewModel( init { if (flags.isEnabled()) { + // Keeps the lockout dialog up-to-date. applicationScope.launch { bouncerInteractor.onLockoutStarted.collect { showLockoutDialog() @@ -219,18 +242,20 @@ class BouncerViewModel( // Update the lockout countdown whenever the selected user is switched. selectedUser.collect { startLockoutCountdown() } } - } - } - /** Notifies that the dialog has been dismissed by the user. */ - fun onDialogDismissed() { - _dialogMessage.value = null + // Keeps the upcoming wipe dialog up-to-date. + applicationScope.launch { + authenticationInteractor.upcomingWipe.collect { wipeModel -> + wipeDialogMessage.value = wipeModel?.message + } + } + } } private fun showLockoutDialog() { applicationScope.launch { val failedAttempts = authenticationInteractor.failedAuthenticationAttempts.value - _dialogMessage.value = + lockoutDialogMessage.value = authMethodViewModel.value?.lockoutMessageId?.let { messageId -> applicationContext.getString( messageId, @@ -341,6 +366,71 @@ class BouncerViewModel( ) } + /** + * @return A message warning the user that the user/profile/device will be wiped upon a further + * [AuthenticationWipeModel.remainingAttempts] unsuccessful authentication attempts. + */ + private fun AuthenticationWipeModel.getAlmostAtWipeMessage(): String { + val message = + applicationContext.getString( + wipeTarget.messageIdForAlmostWipe, + failedAttempts, + remainingAttempts, + ) + return if (wipeTarget == AuthenticationWipeModel.WipeTarget.ManagedProfile) { + devicePolicyManager.resources.getString( + DevicePolicyResources.Strings.SystemUi + .KEYGUARD_DIALOG_FAILED_ATTEMPTS_ALMOST_ERASING_PROFILE, + { message }, + failedAttempts, + remainingAttempts, + ) + ?: message + } else { + message + } + } + + /** + * @return A message informing the user that their user/profile/device will be wiped promptly. + */ + private fun AuthenticationWipeModel.getWipeMessage(): String { + val message = applicationContext.getString(wipeTarget.messageIdForWipe, failedAttempts) + return if (wipeTarget == AuthenticationWipeModel.WipeTarget.ManagedProfile) { + devicePolicyManager.resources.getString( + DevicePolicyResources.Strings.SystemUi + .KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE, + { message }, + failedAttempts, + ) + ?: message + } else { + message + } + } + + private val AuthenticationWipeModel.message: String + get() = if (remainingAttempts > 0) getAlmostAtWipeMessage() else getWipeMessage() + + private fun createDialogViewModel(): DialogViewModel? { + val wipeText = wipeDialogMessage.value + val lockoutText = lockoutDialogMessage.value + return when { + // The wipe dialog takes priority over the lockout dialog. + wipeText != null -> + DialogViewModel( + text = wipeText, + onDismiss = { wipeDialogMessage.value = null }, + ) + lockoutText != null -> + DialogViewModel( + text = lockoutText, + onDismiss = { lockoutDialogMessage.value = null }, + ) + else -> null // No dialog to show. + } + } + data class MessageViewModel( val text: String, @@ -353,6 +443,13 @@ class BouncerViewModel( val isUpdateAnimated: Boolean, ) + data class DialogViewModel( + val text: String, + + /** Callback to run after the dialog has been dismissed by the user. */ + val onDismiss: () -> Unit, + ) + data class UserSwitcherDropdownItemViewModel( val icon: Icon, val text: Text, @@ -370,26 +467,28 @@ object BouncerViewModelModule { @Application applicationScope: CoroutineScope, @Main mainDispatcher: CoroutineDispatcher, bouncerInteractor: BouncerInteractor, + simBouncerInteractor: SimBouncerInteractor, authenticationInteractor: AuthenticationInteractor, flags: SceneContainerFlags, userSwitcherViewModel: UserSwitcherViewModel, actionButtonInteractor: BouncerActionButtonInteractor, - simBouncerInteractor: SimBouncerInteractor, clock: SystemClock, + devicePolicyManager: DevicePolicyManager, ): BouncerViewModel { return BouncerViewModel( applicationContext = applicationContext, applicationScope = applicationScope, mainDispatcher = mainDispatcher, bouncerInteractor = bouncerInteractor, + simBouncerInteractor = simBouncerInteractor, authenticationInteractor = authenticationInteractor, flags = flags, selectedUser = userSwitcherViewModel.selectedUser, users = userSwitcherViewModel.users, userSwitcherMenu = userSwitcherViewModel.menu, - actionButtonInteractor = actionButtonInteractor, - simBouncerInteractor = simBouncerInteractor, + actionButton = actionButtonInteractor.actionButton, clock = clock, + devicePolicyManager = devicePolicyManager, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 0f4e583eda45..18fb895f4aaf 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -24,6 +24,9 @@ import com.android.systemui.communal.data.repository.CommunalRepository import com.android.systemui.communal.data.repository.CommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalContentSize +import com.android.systemui.communal.shared.model.CommunalContentSize.FULL +import com.android.systemui.communal.shared.model.CommunalContentSize.HALF +import com.android.systemui.communal.shared.model.CommunalContentSize.THIRD import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState import com.android.systemui.communal.widgets.EditWidgetsActivityStarter @@ -133,12 +136,11 @@ constructor( target.featureType == SmartspaceTarget.FEATURE_TIMER && target.remoteViews != null } - .map Target@{ target -> + .mapIndexed Target@{ index, target -> return@Target CommunalContentModel.Smartspace( smartspaceTargetId = target.smartspaceTargetId, remoteViews = target.remoteViews!!, - // Smartspace always as HALF for now. - size = CommunalContentSize.HALF, + size = dynamicContentSize(targets.size, index), ) } } @@ -147,23 +149,50 @@ constructor( /** A list of tutorial content to be displayed in the communal hub in tutorial mode. */ val tutorialContent: List<CommunalContentModel.Tutorial> = listOf( - CommunalContentModel.Tutorial(id = 0, CommunalContentSize.FULL), - CommunalContentModel.Tutorial(id = 1, CommunalContentSize.THIRD), - CommunalContentModel.Tutorial(id = 2, CommunalContentSize.THIRD), - CommunalContentModel.Tutorial(id = 3, CommunalContentSize.THIRD), - CommunalContentModel.Tutorial(id = 4, CommunalContentSize.HALF), - CommunalContentModel.Tutorial(id = 5, CommunalContentSize.HALF), - CommunalContentModel.Tutorial(id = 6, CommunalContentSize.HALF), - CommunalContentModel.Tutorial(id = 7, CommunalContentSize.HALF), + CommunalContentModel.Tutorial(id = 0, FULL), + CommunalContentModel.Tutorial(id = 1, THIRD), + CommunalContentModel.Tutorial(id = 2, THIRD), + CommunalContentModel.Tutorial(id = 3, THIRD), + CommunalContentModel.Tutorial(id = 4, HALF), + CommunalContentModel.Tutorial(id = 5, HALF), + CommunalContentModel.Tutorial(id = 6, HALF), + CommunalContentModel.Tutorial(id = 7, HALF), ) val umoContent: Flow<List<CommunalContentModel.Umo>> = mediaRepository.mediaPlaying.flatMapLatest { mediaPlaying -> if (mediaPlaying) { // TODO(b/310254801): support HALF and FULL layouts - flowOf(listOf(CommunalContentModel.Umo(CommunalContentSize.THIRD))) + flowOf(listOf(CommunalContentModel.Umo(THIRD))) } else { flowOf(emptyList()) } } + + companion object { + /** + * Calculates the content size dynamically based on the total number of contents of that + * type. + * + * Contents with the same type are expected to fill each column evenly. Currently there are + * three possible sizes. When the total number is 1, size for that content is [FULL], when + * the total number is 2, size for each is [HALF], and 3, size for each is [THIRD]. + * + * When dynamic contents fill in multiple columns, the first column follows the algorithm + * above, and the remaining contents are packed in [THIRD]s. For example, when the total + * number if 4, the first one is [FULL], filling the column, and the remaining 3 are + * [THIRD]. + * + * @param size The total number of contents of this type. + * @param index The index of the current content of this type. + */ + private fun dynamicContentSize(size: Int, index: Int): CommunalContentSize { + val remainder = size % CommunalContentSize.entries.size + return CommunalContentSize.toSize( + span = + FULL.span / + if (index > remainder - 1) CommunalContentSize.entries.size else remainder + ) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt index c903709aa2ee..572794daaca6 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt @@ -30,5 +30,13 @@ enum class CommunalContentSize(val span: Int) { HALF(3), /** Content takes a third of the height of the column. */ - THIRD(2), + THIRD(2); + + companion object { + /** Converts from span to communal content size. */ + fun toSize(span: Int): CommunalContentSize { + return entries.find { it.span == span } + ?: throw Exception("Invalid span for communal content size") + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/PanelConfirmationDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/controls/management/PanelConfirmationDialogFactory.kt index 5df26b3176ff..a6b432019486 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/PanelConfirmationDialogFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/PanelConfirmationDialogFactory.kt @@ -28,27 +28,26 @@ import javax.inject.Inject /** * Factory to create dialogs for consenting to show app panels for specific apps. * - * [internalDialogFactory] is for facilitating testing. + * [dialogFactory] is for facilitating testing. */ -class PanelConfirmationDialogFactory( - private val internalDialogFactory: (Context) -> SystemUIDialog +class PanelConfirmationDialogFactory @Inject constructor( + private val dialogFactory: SystemUIDialog.Factory ) { - @Inject constructor() : this({ SystemUIDialog(it) }) /** * Creates a dialog to show to the user. [response] will be true if an only if the user responds * affirmatively. */ fun createConfirmationDialog( - context: Context, - appName: CharSequence, - response: Consumer<Boolean> + context: Context, + appName: CharSequence, + response: Consumer<Boolean> ): Dialog { val listener = DialogInterface.OnClickListener { _, which -> response.accept(which == DialogInterface.BUTTON_POSITIVE) } - return internalDialogFactory(context).apply { + return dialogFactory.create(context).apply { setTitle(this.context.getString(R.string.controls_panel_authorization_title, appName)) setMessage(this.context.getString(R.string.controls_panel_authorization, appName)) setCanceledOnTouchOutside(true) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialogsFactory.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialogsFactory.kt index 2ad6014fd7cd..e42a4a6af0de 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialogsFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialogsFactory.kt @@ -25,20 +25,21 @@ import com.android.systemui.statusbar.phone.SystemUIDialog import java.util.function.Consumer import javax.inject.Inject -class ControlsDialogsFactory(private val internalDialogFactory: (Context) -> SystemUIDialog) { +class ControlsDialogsFactory @Inject constructor( + private val dialogFactory: SystemUIDialog.Factory +) { - @Inject constructor() : this({ SystemUIDialog(it) }) fun createRemoveAppDialog( - context: Context, - appName: CharSequence, - response: Consumer<Boolean> + context: Context, + appName: CharSequence, + response: Consumer<Boolean> ): Dialog { val listener = DialogInterface.OnClickListener { _, which -> response.accept(which == DialogInterface.BUTTON_POSITIVE) } - return internalDialogFactory(context).apply { + return dialogFactory.create(context).apply { setTitle(context.getString(R.string.controls_panel_remove_app_authorization, appName)) setCanceledOnTouchOutside(true) setOnCancelListener { response.accept(false) } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java index 9e8c0ec7423e..e78ce3bbb0d1 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java @@ -17,8 +17,12 @@ package com.android.systemui.dagger; import android.content.Context; +import android.os.Looper; import com.android.systemui.dagger.qualifiers.InstrumentationTest; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.flags.SystemPropertiesHelper; +import com.android.systemui.process.ProcessWrapper; import com.android.systemui.util.InitializationChecker; import dagger.BindsInstance; @@ -58,4 +62,20 @@ public interface GlobalRootComponent { * Returns an {@link InitializationChecker}. */ InitializationChecker getInitializationChecker(); + + /** + * Returns the main looper for this process. + */ + @Main + Looper getMainLooper(); + + /** + * Returns a {@link SystemPropertiesHelper}. + */ + SystemPropertiesHelper getSystemPropertiesHelper(); + + /** + * Returns a {@link ProcessWrapper} + */ + ProcessWrapper getProcessWrapper(); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index a25c78871115..92300efdc930 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -112,6 +112,7 @@ 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; import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.phone.ConfigurationControllerModule; import com.android.systemui.statusbar.phone.LetterboxModule; import com.android.systemui.statusbar.phone.NotificationIconAreaControllerModule; import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule; @@ -178,6 +179,7 @@ import javax.inject.Named; ClockRegistryModule.class, CommunalModule.class, CommonDataLayerModule.class, + ConfigurationControllerModule.class, ConnectivityModule.class, ControlsModule.class, CoroutinesModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt index efa1c0a07490..684627ba27bf 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt @@ -19,6 +19,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterIsInstance @@ -31,4 +32,11 @@ constructor( ) { val fingerprintFailure: Flow<FailFingerprintAuthenticationStatus> = repository.authenticationStatus.filterIsInstance<FailFingerprintAuthenticationStatus>() + + /** Whether fingerprint authentication is currently running or not */ + val isRunning: Flow<Boolean> = repository.isRunning + + /** Provide the current status of fingerprint authentication. */ + val authenticationStatus: Flow<FingerprintAuthenticationStatus> = + repository.authenticationStatus } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/AlternateBouncerUdfpsAccessibilityOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/AlternateBouncerUdfpsAccessibilityOverlayViewModel.kt new file mode 100644 index 000000000000..eeac52783bcf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/AlternateBouncerUdfpsAccessibilityOverlayViewModel.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.deviceentry.ui.viewmodel + +import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor +import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf + +/** Models the UI state for the alternate bouncer UDFPS accessibility overlay */ +@ExperimentalCoroutinesApi +class AlternateBouncerUdfpsAccessibilityOverlayViewModel +@Inject +constructor( + udfpsOverlayInteractor: UdfpsOverlayInteractor, + accessibilityInteractor: AccessibilityInteractor, +) : + UdfpsAccessibilityOverlayViewModel( + udfpsOverlayInteractor, + accessibilityInteractor, + ) { + /** Overlay is always visible if touch exploration is enabled on the alternate bouncer. */ + override fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> = flowOf(true) +} diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/DeviceEntryUdfpsAccessibilityOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/DeviceEntryUdfpsAccessibilityOverlayViewModel.kt new file mode 100644 index 000000000000..af51576817e5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/DeviceEntryUdfpsAccessibilityOverlayViewModel.kt @@ -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.systemui.deviceentry.ui.viewmodel + +import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor +import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor +import com.android.systemui.keyguard.ui.view.DeviceEntryIconView +import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel +import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine + +/** Models the UI state for the non-alternate bouncer UDFPS accessibility overlay */ +@ExperimentalCoroutinesApi +class DeviceEntryUdfpsAccessibilityOverlayViewModel +@Inject +constructor( + udfpsOverlayInteractor: UdfpsOverlayInteractor, + accessibilityInteractor: AccessibilityInteractor, + private val deviceEntryIconViewModel: DeviceEntryIconViewModel, + private val deviceEntryFgIconViewModel: DeviceEntryForegroundViewModel, +) : + UdfpsAccessibilityOverlayViewModel( + udfpsOverlayInteractor, + accessibilityInteractor, + ) { + /** Overlay is only visible if the UDFPS icon is visible on the keyguard. */ + override fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> = + combine( + deviceEntryFgIconViewModel.viewModel, + deviceEntryIconViewModel.deviceEntryViewAlpha, + ) { iconViewModel, alpha -> + iconViewModel.type == DeviceEntryIconView.IconType.FINGERPRINT && + !iconViewModel.useAodVariant && + alpha == 1f + } +} diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt index 80684b442c5d..f5a88708ee2a 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt @@ -23,48 +23,33 @@ import com.android.systemui.accessibility.domain.interactor.AccessibilityInterac import com.android.systemui.biometrics.UdfpsUtils import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams -import com.android.systemui.keyguard.ui.view.DeviceEntryIconView -import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel -import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel -import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf /** Models the UI state for the UDFPS accessibility overlay */ @ExperimentalCoroutinesApi -class UdfpsAccessibilityOverlayViewModel -@Inject -constructor( +abstract class UdfpsAccessibilityOverlayViewModel( udfpsOverlayInteractor: UdfpsOverlayInteractor, accessibilityInteractor: AccessibilityInteractor, - deviceEntryIconViewModel: DeviceEntryIconViewModel, - deviceEntryFgIconViewModel: DeviceEntryForegroundViewModel, ) { private val udfpsUtils = UdfpsUtils() private val udfpsOverlayParams: StateFlow<UdfpsOverlayParams> = udfpsOverlayInteractor.udfpsOverlayParams - /** Overlay is only visible if touch exploration is enabled and UDFPS can be used. */ val visible: Flow<Boolean> = accessibilityInteractor.isTouchExplorationEnabled.flatMapLatest { touchExplorationEnabled -> if (touchExplorationEnabled) { - combine( - deviceEntryFgIconViewModel.viewModel, - deviceEntryIconViewModel.deviceEntryViewAlpha, - ) { iconViewModel, alpha -> - iconViewModel.type == DeviceEntryIconView.IconType.FINGERPRINT && - !iconViewModel.useAodVariant && - alpha == 1f - } + isVisibleWhenTouchExplorationEnabled() } else { flowOf(false) } } + abstract fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> + /** Give directional feedback to help the user authenticate with UDFPS. */ fun onHoverEvent(v: View, event: MotionEvent): Boolean { val overlayParams = udfpsOverlayParams.value diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index 4c4aa5ce1911..8776ec5496c8 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -118,6 +118,11 @@ public interface DozeHost { * Called when the dozing state may have been updated. */ default void onDozingChanged(boolean isDozing) {} + + /** + * Called when fingerprint acquisition has started and screen state might need updating. + */ + default void onSideFingerprintAcquisitionStarted() {} } interface PulseCallback { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 5b90ef2bb806..424bd0a3e23b 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -514,6 +514,7 @@ public class DozeLog implements Dumpable { case REASON_SENSOR_TAP: return "tap"; case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps"; case REASON_SENSOR_QUICK_PICKUP: return "quickPickup"; + case PULSE_REASON_FINGERPRINT_ACTIVATED: return "fingerprint-triggered"; default: throw new IllegalArgumentException("invalid reason: " + pulseReason); } } @@ -542,7 +543,9 @@ public class DozeLog implements Dumpable { PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP_PRESENCE, PULSE_REASON_SENSOR_WAKE_REACH, REASON_SENSOR_TAP, - REASON_SENSOR_UDFPS_LONG_PRESS, REASON_SENSOR_QUICK_PICKUP}) + REASON_SENSOR_UDFPS_LONG_PRESS, REASON_SENSOR_QUICK_PICKUP, + PULSE_REASON_FINGERPRINT_ACTIVATED + }) public @interface Reason {} public static final int PULSE_REASON_NONE = -1; public static final int PULSE_REASON_INTENT = 0; @@ -557,6 +560,7 @@ public class DozeLog implements Dumpable { public static final int REASON_SENSOR_TAP = 9; public static final int REASON_SENSOR_UDFPS_LONG_PRESS = 10; public static final int REASON_SENSOR_QUICK_PICKUP = 11; + public static final int PULSE_REASON_FINGERPRINT_ACTIVATED = 12; - public static final int TOTAL_REASONS = 12; + public static final int TOTAL_REASONS = 13; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 795c3d4528c5..93111874c69b 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -265,6 +265,10 @@ public class DozeTriggers implements DozeMachine.Part { mDozeLog.traceNotificationPulse(); } + private void onSideFingerprintAcquisitionStarted() { + requestPulse(DozeLog.PULSE_REASON_FINGERPRINT_ACTIVATED, false, null); + } + private static void runIfNotNull(Runnable runnable) { if (runnable != null) { runnable.run(); @@ -690,5 +694,10 @@ public class DozeTriggers implements DozeMachine.Part { public void onNotificationAlerted(Runnable onPulseSuppressedListener) { onNotification(onPulseSuppressedListener); } + + @Override + public void onSideFingerprintAcquisitionStarted() { + DozeTriggers.this.onSideFingerprintAcquisitionStarted(); + } }; } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 1b350055e8de..bb0c2733e511 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -208,10 +208,6 @@ object Flags { val WALLPAPER_PICKER_GRID_APPLY_BUTTON = unreleasedFlag("wallpaper_picker_grid_apply_button") - /** Provide new auth messages on the bouncer. */ - // TODO(b/277961132): Tracking bug. - @JvmField val REVAMPED_BOUNCER_MESSAGES = unreleasedFlag("revamped_bouncer_messages") - /** Keyguard Migration */ // TODO(b/297037052): Tracking bug. diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt index 6c160975587b..6fa20de1fb7f 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt @@ -17,19 +17,22 @@ package com.android.systemui.flags import android.os.SystemProperties -import com.android.systemui.dagger.SysUISingleton - import javax.inject.Inject +import javax.inject.Singleton /** * Proxy to make {@link SystemProperties} easily testable. */ -@SysUISingleton +@Singleton open class SystemPropertiesHelper @Inject constructor() { fun get(name: String): String { return SystemProperties.get(name) } + fun get(name: String, def: String?): String { + return SystemProperties.get(name, def) + } + fun getBoolean(name: String, default: Boolean): Boolean { return SystemProperties.getBoolean(name, default) } diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt index 6cb68bade9a9..89bfd96d2408 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt @@ -16,6 +16,7 @@ package com.android.systemui.haptics.slider +import android.view.MotionEvent import androidx.annotation.FloatRange /** Configuration parameters of a [SliderHapticFeedbackProvider] */ @@ -38,6 +39,8 @@ data class SliderHapticFeedbackConfig( val numberOfLowTicks: Int = 5, /** Maximum velocity allowed for vibration scaling. This is not expected to change. */ val maxVelocityToScale: Float = 2000f, /* In pixels/sec */ + /** Axis to use when computing velocity. Must be the same as the slider's axis of movement */ + val velocityAxis: Int = MotionEvent.AXIS_X, /** Vibration scale at the upper bookend of the slider */ @FloatRange(from = 0.0, to = 1.0) val upperBookendScale: Float = 1f, /** Vibration scale at the lower bookend of the slider */ diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt index 9e6245ae7f21..6f28ab7f414c 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt @@ -162,27 +162,33 @@ class SliderHapticFeedbackProvider( override fun onLowerBookend() { if (!hasVibratedAtLowerBookend) { - velocityTracker.computeCurrentVelocity(UNITS_SECOND, config.maxVelocityToScale) - vibrateOnEdgeCollision(abs(velocityTracker.xVelocity)) + vibrateOnEdgeCollision(abs(getTrackedVelocity())) hasVibratedAtLowerBookend = true } } override fun onUpperBookend() { if (!hasVibratedAtUpperBookend) { - velocityTracker.computeCurrentVelocity(UNITS_SECOND, config.maxVelocityToScale) - vibrateOnEdgeCollision(abs(velocityTracker.xVelocity)) + vibrateOnEdgeCollision(abs(getTrackedVelocity())) hasVibratedAtUpperBookend = true } } override fun onProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float) { - velocityTracker.computeCurrentVelocity(UNITS_SECOND, config.maxVelocityToScale) - vibrateDragTexture(abs(velocityTracker.xVelocity), progress) + vibrateDragTexture(abs(getTrackedVelocity()), progress) hasVibratedAtUpperBookend = false hasVibratedAtLowerBookend = false } + private fun getTrackedVelocity(): Float { + velocityTracker.computeCurrentVelocity(UNITS_SECOND, config.maxVelocityToScale) + return if (velocityTracker.isAxisSupported(config.velocityAxis)) { + velocityTracker.getAxisVelocity(config.velocityAxis) + } else { + 0f + } + } + override fun onProgressJump(@FloatRange(from = 0.0, to = 1.0) progress: Float) {} override fun onSelectAndArrow(@FloatRange(from = 0.0, to = 1.0) progress: Float) {} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index af5d48d9ae07..afef8751b065 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -39,12 +39,14 @@ import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea import com.android.systemui.keyguard.ui.view.KeyguardRootView import com.android.systemui.keyguard.ui.view.layout.KeyguardBlueprintCommandListener +import com.android.systemui.keyguard.ui.viewmodel.AodAlphaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.NotificationShadeWindowView import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.KeyguardIndicationController @@ -83,6 +85,7 @@ constructor( private val deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor, private val vibratorHelper: VibratorHelper, private val falsingManager: FalsingManager, + private val aodAlphaViewModel: AodAlphaViewModel, ) : CoreStartable { private var rootViewHandle: DisposableHandle? = null @@ -109,7 +112,9 @@ constructor( bindKeyguardRootView() initializeViews() - KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) + if (!SceneContainerFlag.isEnabled) { + KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) + } keyguardBlueprintCommandListener.start() } @@ -126,7 +131,7 @@ constructor( KeyguardIndicationAreaBinder.bind( notificationShadeWindowView.requireViewById(R.id.keyguard_indication_area), keyguardIndicationAreaViewModel, - keyguardRootViewModel, + aodAlphaViewModel, indicationController, ) } @@ -142,13 +147,16 @@ constructor( } private fun bindKeyguardRootView() { + if (SceneContainerFlag.isEnabled) { + return + } + rootViewHandle?.dispose() rootViewHandle = KeyguardRootViewBinder.bind( keyguardRootView, keyguardRootViewModel, configuration, - featureFlags, occludingAppDeviceEntryMessageViewModel, chipbarCoordinator, screenOffAnimationController, 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 3925dd1620b4..13e38358477a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -34,6 +34,7 @@ import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.keyguard.mediator.ScreenOnCoordinator; +import com.android.systemui.CoreStartable; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollector; @@ -79,9 +80,12 @@ import com.android.systemui.util.time.SystemClock; import com.android.systemui.wallpapers.data.repository.WallpaperRepository; import com.android.wm.shell.keyguard.KeyguardTransitions; +import dagger.Binds; import dagger.Lazy; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; import java.util.concurrent.Executor; @@ -105,7 +109,7 @@ import kotlinx.coroutines.CoroutineDispatcher; StartKeyguardTransitionModule.class, ResourceTrimmerModule.class, }) -public class KeyguardModule { +public interface KeyguardModule { /** * Provides our instance of KeyguardViewMediator which is considered optional. */ @@ -207,13 +211,19 @@ public class KeyguardModule { /** */ @Provides - public ViewMediatorCallback providesViewMediatorCallback(KeyguardViewMediator viewMediator) { + static ViewMediatorCallback providesViewMediatorCallback(KeyguardViewMediator viewMediator) { return viewMediator.getViewMediatorCallback(); } /** */ @Provides - public KeyguardQuickAffordancesMetricsLogger providesKeyguardQuickAffordancesMetricsLogger() { + static KeyguardQuickAffordancesMetricsLogger providesKeyguardQuickAffordancesMetricsLogger() { return new KeyguardQuickAffordancesMetricsLoggerImpl(); } + + /** Binds {@link KeyguardUpdateMonitor} as a {@link CoreStartable}. */ + @Binds + @IntoMap + @ClassKey(KeyguardUpdateMonitor.class) + CoreStartable bindsKeyguardUpdateMonitor(KeyguardUpdateMonitor keyguardUpdateMonitor); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt new file mode 100644 index 000000000000..70c2e6d56ca3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt @@ -0,0 +1,52 @@ +/* + * 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.animation.ValueAnimator +import com.android.app.animation.Interpolators +import com.android.systemui.Flags +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds + +@SysUISingleton +class FromGlanceableHubTransitionInteractor +@Inject +constructor( + override val transitionRepository: KeyguardTransitionRepository, + override val transitionInteractor: KeyguardTransitionInteractor, +) : TransitionInteractor(fromState = KeyguardState.GLANCEABLE_HUB) { + override fun start() { + if (!Flags.communalHub()) { + return + } + } + + override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { + return ValueAnimator().apply { + interpolator = Interpolators.LINEAR + duration = DEFAULT_DURATION.inWholeMilliseconds + } + } + + companion object { + const val TAG = "FromGlanceableHubTransitionInteractor" + val DEFAULT_DURATION = 500.milliseconds + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt index ba7b9870103a..91f8420393e1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt @@ -42,6 +42,7 @@ constructor( is FromGoneTransitionInteractor -> Log.d(TAG, "Started $it") is FromLockscreenTransitionInteractor -> Log.d(TAG, "Started $it") is FromDreamingTransitionInteractor -> Log.d(TAG, "Started $it") + is FromGlanceableHubTransitionInteractor -> Log.d(TAG, "Started $it") is FromOccludedTransitionInteractor -> Log.d(TAG, "Started $it") is FromDozingTransitionInteractor -> Log.d(TAG, "Started $it") is FromAlternateBouncerTransitionInteractor -> Log.d(TAG, "Started $it") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt index 2d43897c2565..fbf693625f63 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt @@ -96,6 +96,7 @@ constructor( KeyguardState.AOD -> false KeyguardState.DREAMING -> true KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> true + KeyguardState.GLANCEABLE_HUB -> true KeyguardState.ALTERNATE_BOUNCER -> true KeyguardState.PRIMARY_BOUNCER -> true KeyguardState.LOCKSCREEN -> true diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt index 56f552961432..d95c38e2697c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt @@ -67,4 +67,10 @@ abstract class StartKeyguardTransitionModule { abstract fun fromAlternateBouncer( impl: FromAlternateBouncerTransitionInteractor ): TransitionInteractor + + @Binds + @IntoSet + abstract fun fromGlanceableHub( + impl: FromGlanceableHubTransitionInteractor + ): TransitionInteractor } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt index f5bcab96a5a4..92612b824974 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt @@ -62,6 +62,12 @@ enum class KeyguardState { * unlocked if SWIPE security method is used, or if face lockscreen bypass is false. */ LOCKSCREEN, + /** + * Device is locked or on dream and user has swiped from the right edge to enter the glanceable + * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen + * or dream, as well as swipe down for the notifications and up for the bouncer. + */ + GLANCEABLE_HUB, /* * Keyguard is no longer visible. In most cases the user has just authenticated and keyguard * is being removed, but there are other cases where the user is swiping away keyguard, such as @@ -95,6 +101,7 @@ enum class KeyguardState { DOZING -> false DREAMING -> false DREAMING_LOCKSCREEN_HOSTED -> false + GLANCEABLE_HUB -> true AOD -> false ALTERNATE_BOUNCER -> true PRIMARY_BOUNCER -> true diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt index 12775854c737..cf1d2477c9af 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt @@ -32,6 +32,7 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map @@ -89,7 +90,6 @@ constructor( val start = (startTime / transitionDuration).toFloat() val chunks = (transitionDuration / duration).toFloat() logger.logCreate(name, start) - var isComplete = true fun stepToValue(step: TransitionStep): Float? { val value = (step.value - start) * chunks @@ -98,17 +98,13 @@ constructor( // middle, it is possible this animation is being skipped but we need to inform // the ViewModels of the last update STARTED -> { - isComplete = false onStart?.invoke() max(0f, min(1f, value)) } // Always send a final value of 1. Because of rounding, [value] may never be // exactly 1. RUNNING -> - if (isComplete) { - null - } else if (value >= 1f) { - isComplete = true + if (value >= 1f) { 1f } else if (value >= 0f) { value @@ -132,6 +128,7 @@ constructor( value } .filterNotNull() + .distinctUntilChanged() } /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt index 78906acd9cea..b2a35495c693 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt @@ -17,21 +17,24 @@ package com.android.systemui.keyguard.ui.binder import android.view.View +import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.classifier.Classifier import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor -import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler +import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder +import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay +import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel import com.android.systemui.keyguard.ui.view.DeviceEntryIconView +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel -import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.scrim.ScrimView -import com.android.systemui.statusbar.gesture.TapGestureDetector +import dagger.Lazy import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch @@ -47,21 +50,24 @@ object AlternateBouncerViewBinder { @JvmStatic fun bind( view: ConstraintLayout, - viewModel: AlternateBouncerViewModel, - falsingManager: FalsingManager, - swipeUpAnywhereGestureHandler: SwipeUpAnywhereGestureHandler, - tapGestureDetector: TapGestureDetector, - alternateBouncerUdfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, + alternateBouncerDependencies: AlternateBouncerDependencies, ) { if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) { return } - optionallyAddUdfpsView( + optionallyAddUdfpsViews( view = view, - alternateBouncerUdfpsIconViewModel = alternateBouncerUdfpsIconViewModel, + udfpsIconViewModel = alternateBouncerDependencies.udfpsIconViewModel, + udfpsA11yOverlayViewModel = + alternateBouncerDependencies.udfpsAccessibilityOverlayViewModel, ) val scrim = view.requireViewById(R.id.alternate_bouncer_scrim) as ScrimView + val viewModel = alternateBouncerDependencies.viewModel + val swipeUpAnywhereGestureHandler = + alternateBouncerDependencies.swipeUpAnywhereGestureHandler + val falsingManager = alternateBouncerDependencies.falsingManager + val tapGestureDetector = alternateBouncerDependencies.tapGestureDetector view.repeatWhenAttached { alternateBouncerViewContainer -> repeatOnLifecycle(Lifecycle.State.STARTED) { scrim.viewAlpha = 0f @@ -102,44 +108,79 @@ object AlternateBouncerViewBinder { } } - private fun optionallyAddUdfpsView( + private fun optionallyAddUdfpsViews( view: ConstraintLayout, - alternateBouncerUdfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, + udfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, + udfpsA11yOverlayViewModel: Lazy<AlternateBouncerUdfpsAccessibilityOverlayViewModel>, ) { view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { launch { - alternateBouncerUdfpsIconViewModel.iconLocation.collect { iconLocation -> - val viewId = R.id.alternate_bouncer_udfps_icon_view - var udfpsView = view.getViewById(viewId) + udfpsIconViewModel.iconLocation.collect { iconLocation -> + // add UDFPS a11y overlay + val udfpsA11yOverlayViewId = + R.id.alternate_bouncer_udfps_accessibility_overlay + var udfpsA11yOverlay = view.getViewById(udfpsA11yOverlayViewId) + if (udfpsA11yOverlay == null) { + udfpsA11yOverlay = + UdfpsAccessibilityOverlay(view.context).apply { + id = udfpsA11yOverlayViewId + } + view.addView(udfpsA11yOverlay) + UdfpsAccessibilityOverlayBinder.bind( + udfpsA11yOverlay, + udfpsA11yOverlayViewModel.get(), + ) + } + + // add UDFPS icon view + val udfpsViewId = R.id.alternate_bouncer_udfps_icon_view + var udfpsView = view.getViewById(udfpsViewId) if (udfpsView == null) { udfpsView = - DeviceEntryIconView(view.context, null).apply { id = viewId } + DeviceEntryIconView(view.context, null).apply { + id = udfpsViewId + contentDescription = + context.resources.getString( + R.string.accessibility_fingerprint_label + ) + } view.addView(udfpsView) AlternateBouncerUdfpsViewBinder.bind( udfpsView, - alternateBouncerUdfpsIconViewModel, + udfpsIconViewModel, ) } val constraintSet = ConstraintSet().apply { clone(view) } constraintSet.apply { - constrainWidth(viewId, iconLocation.width) - constrainHeight(viewId, iconLocation.height) + // udfpsView: + constrainWidth(udfpsViewId, iconLocation.width) + constrainHeight(udfpsViewId, iconLocation.height) connect( - viewId, + udfpsViewId, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, iconLocation.top, ) connect( - viewId, + udfpsViewId, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, iconLocation.left ) + + // udfpsA11yOverlayView: + constrainWidth( + udfpsA11yOverlayViewId, + ViewGroup.LayoutParams.MATCH_PARENT + ) + constrainHeight( + udfpsA11yOverlayViewId, + ViewGroup.LayoutParams.MATCH_PARENT + ) } constraintSet.applyTo(view) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt index 4c33d905b785..7c1368af652c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt @@ -23,8 +23,8 @@ import android.widget.TextView import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.Flags.keyguardBottomAreaRefactor +import com.android.systemui.keyguard.ui.viewmodel.AodAlphaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R import com.android.systemui.statusbar.KeyguardIndicationController @@ -51,7 +51,7 @@ object KeyguardIndicationAreaBinder { fun bind( view: ViewGroup, viewModel: KeyguardIndicationAreaViewModel, - keyguardRootViewModel: KeyguardRootViewModel, + aodAlphaViewModel: AodAlphaViewModel, indicationController: KeyguardIndicationController, ): DisposableHandle { indicationController.setIndicationArea(view) @@ -69,7 +69,7 @@ object KeyguardIndicationAreaBinder { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { if (keyguardBottomAreaRefactor()) { - keyguardRootViewModel.alpha.collect { alpha -> + aodAlphaViewModel.alpha.collect { alpha -> view.apply { this.importantForAccessibility = if (alpha == 0f) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index fad0370a85d7..2aebd99e3664 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt @@ -42,9 +42,9 @@ import com.android.systemui.common.shared.model.Text import com.android.systemui.common.shared.model.TintedIcon import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor -import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel import com.android.systemui.lifecycle.repeatWhenAttached @@ -68,7 +68,10 @@ import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch /** Bind occludingAppDeviceEntryMessageViewModel to run whenever the keyguard view is attached. */ @@ -81,7 +84,6 @@ object KeyguardRootViewBinder { view: ViewGroup, viewModel: KeyguardRootViewModel, configuration: ConfigurationState, - featureFlags: FeatureFlagsClassic, occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, chipbarCoordinator: ChipbarCoordinator, screenOffAnimationController: ScreenOffAnimationController, @@ -108,6 +110,8 @@ object KeyguardRootViewBinder { } } + val burnInParams = MutableStateFlow(BurnInParameters()) + val disposableHandle = view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { @@ -164,35 +168,41 @@ object KeyguardRootViewBinder { // large clock isn't added to burnInLayer due to its scale transition // so we also need to add translation to it here // same as translationX - viewModel.translationY.collect { y -> - childViews[burnInLayerId]?.translationY = y - childViews[largeClockId]?.translationY = y - } + burnInParams + .flatMapLatest { params -> viewModel.translationY(params) } + .collect { y -> + childViews[burnInLayerId]?.translationY = y + childViews[largeClockId]?.translationY = y + } } launch { - viewModel.translationX.collect { x -> - childViews[burnInLayerId]?.translationX = x - childViews[largeClockId]?.translationX = x - } + burnInParams + .flatMapLatest { params -> viewModel.translationX(params) } + .collect { x -> + childViews[burnInLayerId]?.translationX = x + childViews[largeClockId]?.translationX = x + } } launch { - viewModel.scale.collect { (scale, scaleClockOnly) -> - if (scaleClockOnly) { - // For clocks except weather clock, we have scale transition - // besides translate - childViews[largeClockId]?.let { - it.scaleX = scale - it.scaleY = scale + burnInParams + .flatMapLatest { params -> viewModel.scale(params) } + .collect { scaleViewModel -> + if (scaleViewModel.scaleClockOnly) { + // For clocks except weather clock, we have scale transition + // besides translate + childViews[largeClockId]?.let { + it.scaleX = scaleViewModel.scale + it.scaleY = scaleViewModel.scale + } + } else { + // For weather clock, large clock should have only scale + // transition with other parts in burnInLayer + childViews[burnInLayerId]?.scaleX = scaleViewModel.scale + childViews[burnInLayerId]?.scaleY = scaleViewModel.scale } - } else { - // For weather clock, large clock should have only scale - // transition with other parts in burnInLayer - childViews[burnInLayerId]?.scaleX = scale - childViews[burnInLayerId]?.scaleY = scale } - } } if (NotificationIconContainerRefactor.isEnabled) { @@ -274,10 +284,12 @@ object KeyguardRootViewBinder { } if (!migrateClocksToBlueprint()) { - viewModel.clockControllerProvider = clockControllerProvider + burnInParams.update { current -> + current.copy(clockControllerProvider = clockControllerProvider) + } } - onLayoutChangeListener = OnLayoutChange(viewModel) + onLayoutChangeListener = OnLayoutChange(viewModel, burnInParams) view.addOnLayoutChangeListener(onLayoutChangeListener) // Views will be added or removed after the call to bind(). This is needed to avoid many @@ -296,7 +308,9 @@ object KeyguardRootViewBinder { view.setOnApplyWindowInsetsListener { v: View, insets: WindowInsets -> val insetTypes = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout() - viewModel.topInset = insets.getInsetsIgnoringVisibility(insetTypes).top + burnInParams.update { current -> + current.copy(topInset = insets.getInsetsIgnoringVisibility(insetTypes).top) + } insets } @@ -333,8 +347,10 @@ object KeyguardRootViewBinder { ) } - private class OnLayoutChange(private val viewModel: KeyguardRootViewModel) : - OnLayoutChangeListener { + private class OnLayoutChange( + private val viewModel: KeyguardRootViewModel, + private val burnInParams: MutableStateFlow<BurnInParameters>, + ) : OnLayoutChangeListener { override fun onLayoutChange( view: View, left: Int, @@ -355,7 +371,7 @@ object KeyguardRootViewBinder { } view.findViewById<View>(R.id.keyguard_status_view)?.let { statusView -> - viewModel.statusViewTop = statusView.top + burnInParams.update { current -> current.copy(statusViewTop = statusView.top) } } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt index e36819b54524..92270ad31664 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt @@ -28,6 +28,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R +import com.android.systemui.shared.R as sharedR import kotlinx.coroutines.launch object KeyguardSmartspaceViewBinder { @@ -69,9 +70,10 @@ object KeyguardSmartspaceViewBinder { smartspaceViewModel.isSmartspaceEnabled && smartspaceViewModel.isDateWeatherDecoupled ) { - val dateView = constraintLayout.requireViewById<View>(smartspaceViewModel.dateId) + val dateView = + constraintLayout.requireViewById<View>(sharedR.id.date_smartspace_view) val weatherView = - constraintLayout.requireViewById<View>(smartspaceViewModel.weatherId) + constraintLayout.requireViewById<View>(sharedR.id.weather_smartspace_view) addView(weatherView) addView(dateView) } @@ -88,8 +90,10 @@ object KeyguardSmartspaceViewBinder { smartspaceViewModel.isSmartspaceEnabled && smartspaceViewModel.isDateWeatherDecoupled ) { - val dateView = smartspaceViewModel.dateView - val weatherView = smartspaceViewModel.weatherView + val dateView = + constraintLayout.requireViewById<View>(sharedR.id.date_smartspace_view) + val weatherView = + constraintLayout.requireViewById<View>(sharedR.id.weather_smartspace_view) removeView(weatherView) removeView(dateView) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt index 03e45fdbe75f..eb3afb7c9eec 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -367,7 +367,6 @@ constructor( keyguardRootView, keyguardRootViewModel, configuration, - featureFlags, occludingAppDeviceEntryMessageViewModel, chipbarCoordinator, screenOffAnimationController, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt index d89e1e41d1bc..1ccc6ccf2cec 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt @@ -28,6 +28,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R +import com.android.systemui.shared.R as sharedR import javax.inject.Inject /** Adds a layer to group elements for translation for burn-in preventation */ @@ -87,7 +88,7 @@ constructor( burnInLayer.apply { if (smartspaceViewModel.isSmartspaceEnabled) { val smartspaceView = - constraintLayout.requireViewById<View>(smartspaceViewModel.smartspaceViewId) + constraintLayout.requireViewById<View>(sharedR.id.bc_smartspace_view) addView(smartspaceView) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt index b429ab4fac0a..f560b5f068c9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt @@ -32,6 +32,7 @@ import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R +import com.android.systemui.shared.R as sharedR import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder import com.android.systemui.statusbar.notification.icon.ui.viewbinder.StatusBarIconViewBindingFailureTracker @@ -117,7 +118,7 @@ constructor( } constraintSet.apply { if (migrateClocksToBlueprint()) { - connect(nicId, TOP, smartspaceViewModel.smartspaceViewId, BOTTOM, bottomMargin) + connect(nicId, TOP, sharedR.id.bc_smartspace_view, BOTTOM, bottomMargin) setGoneMargin(nicId, BOTTOM, bottomMargin) } else { connect(nicId, TOP, R.id.keyguard_status_view, topAlignment, bottomMargin) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt index 656c75c7bfec..b5f32c8a5608 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt @@ -32,7 +32,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceLayout import com.android.systemui.res.R @@ -55,7 +54,6 @@ open class ClockSection constructor( private val clockInteractor: KeyguardClockInteractor, protected val keyguardClockViewModel: KeyguardClockViewModel, - private val smartspaceViewModel: KeyguardSmartspaceViewModel, private val context: Context, private val splitShadeStateController: SplitShadeStateController, ) : KeyguardSection() { @@ -119,8 +117,8 @@ constructor( com.android.systemui.customization.R.dimen.small_clock_padding_top ) + context.resources.getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) - largeClockTopMargin += smartspaceViewModel.getDimen(DATE_WEATHER_VIEW_HEIGHT) - largeClockTopMargin += smartspaceViewModel.getDimen(ENHANCED_SMARTSPACE_HEIGHT) + largeClockTopMargin += getDimen(DATE_WEATHER_VIEW_HEIGHT) + largeClockTopMargin += getDimen(ENHANCED_SMARTSPACE_HEIGHT) if (!keyguardClockViewModel.useLargeClock) { largeClockTopMargin -= context.resources.getDimensionPixelSize( @@ -163,6 +161,12 @@ constructor( } } + private fun getDimen(name: String): Int { + val res = context.packageManager.getResourcesForApplication(context.packageName) + val id = res.getIdentifier(name, "dimen", context.packageName) + return res.getDimensionPixelSize(id) + } + companion object { private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height" private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height" diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt index 66c137f7d75e..ea05c1d878b8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt @@ -25,8 +25,8 @@ import com.android.systemui.Flags.keyguardBottomAreaRefactor import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea +import com.android.systemui.keyguard.ui.viewmodel.AodAlphaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.res.R import com.android.systemui.statusbar.KeyguardIndicationController import javax.inject.Inject @@ -37,7 +37,7 @@ class DefaultIndicationAreaSection constructor( private val context: Context, private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel, - private val keyguardRootViewModel: KeyguardRootViewModel, + private val aodAlphaViewModel: AodAlphaViewModel, private val indicationController: KeyguardIndicationController, ) : KeyguardSection() { private val indicationAreaViewId = R.id.keyguard_indication_area @@ -56,7 +56,7 @@ constructor( KeyguardIndicationAreaBinder.bind( constraintLayout.requireViewById(R.id.keyguard_indication_area), keyguardIndicationAreaViewModel, - keyguardRootViewModel, + aodAlphaViewModel, indicationController, ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt index e7b6e44450bd..b0eee0a68b1f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt @@ -31,6 +31,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlags import com.android.systemui.shade.NotificationPanelView +import com.android.systemui.shared.R as sharedR import com.android.systemui.statusbar.notification.stack.AmbientState import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator @@ -80,7 +81,7 @@ constructor( connect( R.id.nssl_placeholder, TOP, - smartspaceViewModel.smartspaceViewId, + sharedR.id.bc_smartspace_view, BOTTOM, bottomMargin ) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt index e1a33dea2257..3265d796ecc7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt @@ -23,7 +23,7 @@ import androidx.constraintlayout.widget.ConstraintSet import com.android.systemui.Flags import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay -import com.android.systemui.deviceentry.ui.viewmodel.UdfpsAccessibilityOverlayViewModel +import com.android.systemui.deviceentry.ui.viewmodel.DeviceEntryUdfpsAccessibilityOverlayViewModel import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.res.R import javax.inject.Inject @@ -35,7 +35,7 @@ class DefaultUdfpsAccessibilityOverlaySection @Inject constructor( private val context: Context, - private val viewModel: UdfpsAccessibilityOverlayViewModel, + private val viewModel: DeviceEntryUdfpsAccessibilityOverlayViewModel, ) : KeyguardSection() { private val viewId = R.id.udfps_accessibility_overlay private var cachedConstraintLayout: ConstraintLayout? = null diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt index 8cd51cd3b1e3..eacd466bc473 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.view.layout.sections import android.content.Context +import android.view.View import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet.BOTTOM @@ -44,13 +45,9 @@ constructor( val smartspaceController: LockscreenSmartspaceController, val keyguardUnlockAnimationController: KeyguardUnlockAnimationController, ) : KeyguardSection() { - var smartspaceView by keyguardSmartspaceViewModel::smartspaceView - var weatherView by keyguardSmartspaceViewModel::weatherView - var dateView by keyguardSmartspaceViewModel::dateView - - val smartspaceViewId = keyguardSmartspaceViewModel.smartspaceViewId - val weatherViewId = keyguardSmartspaceViewModel.weatherId - val dateViewId = keyguardSmartspaceViewModel.dateId + private var smartspaceView: View? = null + private var weatherView: View? = null + private var dateView: View? = null override fun addViews(constraintLayout: ConstraintLayout) { if (!migrateClocksToBlueprint()) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeClockSection.kt index 1302bfa6fc31..19ba1aa4763a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeClockSection.kt @@ -20,7 +20,6 @@ import android.content.Context import androidx.constraintlayout.widget.ConstraintSet import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R import com.android.systemui.statusbar.policy.SplitShadeStateController import javax.inject.Inject @@ -30,17 +29,9 @@ class SplitShadeClockSection constructor( clockInteractor: KeyguardClockInteractor, keyguardClockViewModel: KeyguardClockViewModel, - smartspaceViewModel: KeyguardSmartspaceViewModel, context: Context, splitShadeStateController: SplitShadeStateController, -) : - ClockSection( - clockInteractor, - keyguardClockViewModel, - smartspaceViewModel, - context, - splitShadeStateController - ) { +) : ClockSection(clockInteractor, keyguardClockViewModel, context, splitShadeStateController) { override fun applyDefaultConstraints(constraints: ConstraintSet) { super.applyDefaultConstraints(constraints) val largeClockEndGuideline = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt index 5afdbaa47d95..f20ab06bcda9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt @@ -35,6 +35,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.media.controls.ui.KeyguardMediaController import com.android.systemui.res.R import com.android.systemui.shade.NotificationPanelView +import com.android.systemui.shared.R as sharedR import javax.inject.Inject /** Aligns media on left side for split shade, below smartspace, date, and weather. */ @@ -90,9 +91,9 @@ constructor( Barrier.BOTTOM, 0, *intArrayOf( - keyguardSmartspaceViewModel.smartspaceViewId, - keyguardSmartspaceViewModel.dateId, - keyguardSmartspaceViewModel.weatherId, + sharedR.id.bc_smartspace_view, + sharedR.id.date_smartspace_view, + sharedR.id.weather_smartspace_view, ) ) connect(mediaContainerId, TOP, smartSpaceBarrier, BOTTOM) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerDependencies.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerDependencies.kt new file mode 100644 index 000000000000..6846886875c9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerDependencies.kt @@ -0,0 +1,39 @@ +/* + * 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.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel +import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.statusbar.gesture.TapGestureDetector +import dagger.Lazy +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi + +/** Provides dependencies for the AlternateBouncerViewBinder. */ +@ExperimentalCoroutinesApi +class AlternateBouncerDependencies +@Inject +constructor( + val viewModel: AlternateBouncerViewModel, + val falsingManager: FalsingManager, + val swipeUpAnywhereGestureHandler: SwipeUpAnywhereGestureHandler, + val tapGestureDetector: TapGestureDetector, + val udfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, + val udfpsAccessibilityOverlayViewModel: + Lazy<AlternateBouncerUdfpsAccessibilityOverlayViewModel>, +) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt new file mode 100644 index 000000000000..d4ea728bbffb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onStart + +/** Models UI state for the alpha of the AOD (always-on display). */ +@SysUISingleton +class AodAlphaViewModel +@Inject +constructor( + keyguardInteractor: KeyguardInteractor, + keyguardTransitionInteractor: KeyguardTransitionInteractor, + occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, +) { + + /** The alpha level for the entire lockscreen while in AOD. */ + val alpha: Flow<Float> = + combine( + keyguardTransitionInteractor.transitionValue(KeyguardState.GONE).onStart { + emit(0f) + }, + merge( + keyguardInteractor.keyguardAlpha, + occludedToLockscreenTransitionViewModel.lockscreenAlpha, + ) + ) { transitionToGone, alpha -> + if (transitionToGone == 1f) { + // Ensures content is not visible when in GONE state + 0f + } else { + alpha + } + } + .distinctUntilChanged() +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt new file mode 100644 index 000000000000..780e323a96bc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt @@ -0,0 +1,192 @@ +/* + * 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.keyguard.ui.viewmodel + +import android.util.MathUtils +import com.android.app.animation.Interpolators +import com.android.keyguard.KeyguardClockSwitch +import com.android.systemui.Flags +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.BurnInInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.BurnInModel +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.res.R +import javax.inject.Inject +import javax.inject.Provider +import kotlin.math.max +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onStart + +/** + * Models UI state for elements that need to apply anti-burn-in tactics when showing in AOD + * (always-on display). + */ +@SysUISingleton +class AodBurnInViewModel +@Inject +constructor( + private val burnInInteractor: BurnInInteractor, + private val configurationInteractor: ConfigurationInteractor, + private val keyguardInteractor: KeyguardInteractor, + private val keyguardTransitionInteractor: KeyguardTransitionInteractor, + private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel, + private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, + private val keyguardClockViewModel: KeyguardClockViewModel, +) { + /** Alpha for elements that appear and move during the animation -> AOD */ + val alpha: Flow<Float> = goneToAodTransitionViewModel.enterFromTopAnimationAlpha + + /** Horizontal translation for elements that need to apply anti-burn-in tactics. */ + fun translationX( + params: BurnInParameters, + ): Flow<Float> { + return burnIn(params).map { it.translationX.toFloat() } + } + + /** Vertical translation for elements that need to apply anti-burn-in tactics. */ + fun translationY( + params: BurnInParameters, + ): Flow<Float> { + return configurationInteractor + .dimensionPixelSize(R.dimen.keyguard_enter_from_top_translation_y) + .flatMapLatest { enterFromTopAmount -> + combine( + keyguardInteractor.keyguardTranslationY.onStart { emit(0f) }, + burnIn(params).map { it.translationY.toFloat() }.onStart { emit(0f) }, + goneToAodTransitionViewModel + .enterFromTopTranslationY(enterFromTopAmount) + .onStart { emit(0f) }, + occludedToLockscreenTransitionViewModel.lockscreenTranslationY.onStart { + emit(0f) + }, + ) { + keyguardTransitionY, + burnInTranslationY, + goneToAodTransitionTranslationY, + occludedToLockscreenTransitionTranslationY -> + + // All values need to be combined for a smooth translation + keyguardTransitionY + + burnInTranslationY + + goneToAodTransitionTranslationY + + occludedToLockscreenTransitionTranslationY + } + } + .distinctUntilChanged() + } + + /** Scale for elements that need to apply anti-burn-in tactics. */ + fun scale( + params: BurnInParameters, + ): Flow<BurnInScaleViewModel> { + return burnIn(params).map { + BurnInScaleViewModel( + scale = it.scale, + scaleClockOnly = it.scaleClockOnly, + ) + } + } + + private fun burnIn( + params: BurnInParameters, + ): Flow<BurnInModel> { + return combine( + merge( + keyguardTransitionInteractor.goneToAodTransition.map { it.value }, + keyguardTransitionInteractor.dozeAmountTransition.map { it.value }, + ) + .map { dozeAmount -> Interpolators.FAST_OUT_SLOW_IN.getInterpolation(dozeAmount) }, + burnInInteractor.keyguardBurnIn, + ) { interpolated, burnIn -> + val useScaleOnly = + (clockController(params.clockControllerProvider) + ?.get() + ?.config + ?.useAlternateSmartspaceAODTransition + ?: false) && keyguardClockViewModel.clockSize.value == KeyguardClockSwitch.LARGE + + if (useScaleOnly) { + BurnInModel( + translationX = 0, + translationY = 0, + scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated), + ) + } else { + // Ensure the desired translation doesn't encroach on the top inset + val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt() + val translationY = + if (Flags.migrateClocksToBlueprint()) { + burnInY + } else { + max(params.topInset, params.statusViewTop + burnInY) - params.statusViewTop + } + + BurnInModel( + translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(), + translationY = translationY, + scale = + MathUtils.lerp( + /* start= */ burnIn.scale, + /* stop= */ 1f, + /* amount= */ 1f - interpolated, + ), + scaleClockOnly = true, + ) + } + } + } + + private fun clockController( + provider: Provider<ClockController>?, + ): Provider<ClockController>? { + return if (Flags.migrateClocksToBlueprint()) { + Provider { keyguardClockViewModel.clock } + } else { + provider + } + } +} + +/** UI-sourced parameters to pass into the various methods of [AodBurnInViewModel]. */ +data class BurnInParameters( + val clockControllerProvider: Provider<ClockController>? = null, + /** System insets that keyguard needs to stay out of */ + val topInset: Int = 0, + /** Status view top, without translation added in */ + val statusViewTop: Int = 0, +) + +/** + * Models UI state of the scaling to apply to elements that need to be scaled for anti-burn-in + * purposes. + */ +data class BurnInScaleViewModel( + val scale: Float = 1f, + /** Whether the scale only applies to clock UI elements. */ + val scaleClockOnly: Boolean = false, +) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt index 528a2eebc9cd..5bb27824753d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import android.content.Context import androidx.constraintlayout.helper.widget.Layer import com.android.keyguard.KeyguardClockSwitch.LARGE import com.android.keyguard.KeyguardClockSwitch.SMALL @@ -25,6 +26,9 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.shared.model.SettingsClockSize import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.res.R +import com.android.systemui.statusbar.policy.SplitShadeStateController +import com.android.systemui.util.Utils import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted @@ -36,9 +40,10 @@ import kotlinx.coroutines.flow.stateIn class KeyguardClockViewModel @Inject constructor( - val keyguardInteractor: KeyguardInteractor, - val keyguardClockInteractor: KeyguardClockInteractor, + keyguardInteractor: KeyguardInteractor, + private val keyguardClockInteractor: KeyguardClockInteractor, @Application private val applicationScope: CoroutineScope, + private val splitShadeStateController: SplitShadeStateController, ) { var burnInLayer: Layer? = null val useLargeClock: Boolean @@ -85,4 +90,43 @@ constructor( started = SharingStarted.WhileSubscribed(), initialValue = false ) + + // Needs to use a non application context to get display cutout. + fun getSmallClockTopMargin(context: Context) = + if (splitShadeStateController.shouldUseSplitNotificationShade(context.resources)) { + context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) + } else { + context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) + + Utils.getStatusBarHeaderHeightKeyguard(context) + } + + fun getLargeClockTopMargin(context: Context): Int { + var largeClockTopMargin = + context.resources.getDimensionPixelSize(R.dimen.status_bar_height) + + context.resources.getDimensionPixelSize( + com.android.systemui.customization.R.dimen.small_clock_padding_top + ) + + context.resources.getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) + largeClockTopMargin += getDimen(context, DATE_WEATHER_VIEW_HEIGHT) + largeClockTopMargin += getDimen(context, ENHANCED_SMARTSPACE_HEIGHT) + if (!useLargeClock) { + largeClockTopMargin -= + context.resources.getDimensionPixelSize( + com.android.systemui.customization.R.dimen.small_clock_height + ) + } + + return largeClockTopMargin + } + + private fun getDimen(context: Context, name: String): Int { + val res = context.packageManager.getResourcesForApplication(context.packageName) + val id = res.getIdentifier(name, "dimen", context.packageName) + return res.getDimensionPixelSize(id) + } + + companion object { + private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height" + private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height" + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 26dace00ad76..5059e6be9080 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -18,27 +18,17 @@ package com.android.systemui.keyguard.ui.viewmodel import android.graphics.Point -import android.util.MathUtils import android.view.View.VISIBLE -import com.android.app.animation.Interpolators -import com.android.keyguard.KeyguardClockSwitch.LARGE -import com.android.systemui.Flags.migrateClocksToBlueprint import com.android.systemui.Flags.newAodTransition import com.android.systemui.common.shared.model.NotificationContainerBounds -import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor -import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.keyguard.domain.interactor.BurnInInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.shared.model.BurnInModel import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN -import com.android.systemui.plugins.clocks.ClockController -import com.android.systemui.res.R import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.ScreenOffAnimationController @@ -49,51 +39,29 @@ import com.android.systemui.util.ui.AnimatedValue import com.android.systemui.util.ui.toAnimatedValueFlow import com.android.systemui.util.ui.zip import javax.inject.Inject -import javax.inject.Provider import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.merge -import kotlinx.coroutines.flow.onStart @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class KeyguardRootViewModel @Inject constructor( - configurationInteractor: ConfigurationInteractor, private val deviceEntryInteractor: DeviceEntryInteractor, private val dozeParameters: DozeParameters, private val keyguardInteractor: KeyguardInteractor, - private val keyguardTransitionInteractor: KeyguardTransitionInteractor, + keyguardTransitionInteractor: KeyguardTransitionInteractor, private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, - private val burnInInteractor: BurnInInteractor, - private val keyguardClockViewModel: KeyguardClockViewModel, - private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel, - private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel, - private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, + aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel, screenOffAnimationController: ScreenOffAnimationController, - // TODO(b/310989341): remove after changing migrate_clocks_to_blueprint to aconfig - private val featureFlags: FeatureFlagsClassic, + private val aodBurnInViewModel: AodBurnInViewModel, + aodAlphaViewModel: AodAlphaViewModel, ) { - var clockControllerProvider: Provider<ClockController>? = null - get() { - if (migrateClocksToBlueprint()) { - return Provider { keyguardClockViewModel.clock } - } else { - return field - } - } - - /** System insets that keyguard needs to stay out of */ - var topInset: Int = 0 - /** Status view top, without translation added in */ - var statusViewTop: Int = 0 val burnInLayerVisibility: Flow<Int> = keyguardTransitionInteractor.startedKeyguardState @@ -110,96 +78,25 @@ constructor( keyguardInteractor.notificationContainerBounds /** An observable for the alpha level for the entire keyguard root view. */ - val alpha: Flow<Float> = - combine( - keyguardTransitionInteractor.transitionValue(GONE).onStart { emit(0f) }, - merge( - keyguardInteractor.keyguardAlpha, - occludedToLockscreenTransitionViewModel.lockscreenAlpha, - ) - ) { transitionToGone, alpha -> - if (transitionToGone == 1f) { - // Ensures content is not visible when in GONE state - 0f - } else { - alpha - } - } - .distinctUntilChanged() - - private fun burnIn(): Flow<BurnInModel> { - val dozingAmount: Flow<Float> = - merge( - keyguardTransitionInteractor.goneToAodTransition.map { it.value }, - keyguardTransitionInteractor.dozeAmountTransition.map { it.value }, - ) - - return combine(dozingAmount, burnInInteractor.keyguardBurnIn) { dozeAmount, burnIn -> - val interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(dozeAmount) - val useScaleOnly = - (clockControllerProvider?.get()?.config?.useAlternateSmartspaceAODTransition - ?: false) && keyguardClockViewModel.clockSize.value == LARGE - if (useScaleOnly) { - BurnInModel( - translationX = 0, - translationY = 0, - scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolation), - ) - } else { - // Ensure the desired translation doesn't encroach on the top inset - val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolation).toInt() - val translationY = - if (migrateClocksToBlueprint()) { - burnInY - } else { - -(statusViewTop - Math.max(topInset, statusViewTop + burnInY)) - } - BurnInModel( - translationX = MathUtils.lerp(0, burnIn.translationX, interpolation).toInt(), - translationY = translationY, - scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolation), - scaleClockOnly = true, - ) - } - } - } + val alpha: Flow<Float> = aodAlphaViewModel.alpha /** Specific alpha value for elements visible during [KeyguardState.LOCKSCREEN] */ val lockscreenStateAlpha: Flow<Float> = aodToLockscreenTransitionViewModel.lockscreenAlpha /** For elements that appear and move during the animation -> AOD */ - val burnInLayerAlpha: Flow<Float> = goneToAodTransitionViewModel.enterFromTopAnimationAlpha + val burnInLayerAlpha: Flow<Float> = aodBurnInViewModel.alpha - val translationY: Flow<Float> = - configurationInteractor - .dimensionPixelSize(R.dimen.keyguard_enter_from_top_translation_y) - .flatMapLatest { enterFromTopAmount -> - combine( - keyguardInteractor.keyguardTranslationY.onStart { emit(0f) }, - burnIn().map { it.translationY.toFloat() }.onStart { emit(0f) }, - goneToAodTransitionViewModel - .enterFromTopTranslationY(enterFromTopAmount) - .onStart { emit(0f) }, - occludedToLockscreenTransitionViewModel.lockscreenTranslationY.onStart { - emit(0f) - }, - ) { - keyguardTransitionY, - burnInTranslationY, - goneToAodTransitionTranslationY, - occludedToLockscreenTransitionTranslationY -> - // All values need to be combined for a smooth translation - keyguardTransitionY + - burnInTranslationY + - goneToAodTransitionTranslationY + - occludedToLockscreenTransitionTranslationY - } - } - .distinctUntilChanged() + fun translationY(params: BurnInParameters): Flow<Float> { + return aodBurnInViewModel.translationY(params) + } - val translationX: Flow<Float> = burnIn().map { it.translationX.toFloat() } + fun translationX(params: BurnInParameters): Flow<Float> { + return aodBurnInViewModel.translationX(params) + } - val scale: Flow<Pair<Float, Boolean>> = burnIn().map { Pair(it.scale, it.scaleClockOnly) } + fun scale(params: BurnInParameters): Flow<BurnInScaleViewModel> { + return aodBurnInViewModel.scale(params) + } /** Is the notification icon container visible? */ val isNotifIconContainerVisible: Flow<AnimatedValue<Boolean>> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt index 26e7ee8f561b..a1dd720a82f1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt @@ -16,47 +16,66 @@ package com.android.systemui.keyguard.ui.viewmodel -import android.content.Context -import android.util.Log -import android.view.View import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn @SysUISingleton class KeyguardSmartspaceViewModel @Inject -constructor(val context: Context, val smartspaceController: LockscreenSmartspaceController) { +constructor( + @Application applicationScope: CoroutineScope, + smartspaceController: LockscreenSmartspaceController, + keyguardClockViewModel: KeyguardClockViewModel, +) { + /** Whether the smartspace section is available in the build. */ val isSmartspaceEnabled: Boolean = smartspaceController.isEnabled() + /** Whether the weather area is available in the build. */ + // TODO(b/317891876): this should be a Flow as the value can change over time. val isWeatherEnabled: Boolean = smartspaceController.isWeatherEnabled() + /** Whether the data and weather areas are decoupled in the build. */ val isDateWeatherDecoupled: Boolean = smartspaceController.isDateWeatherDecoupled() - val smartspaceViewId: Int - get() = getId("bc_smartspace_view") - val dateId: Int - get() = getId("date_smartspace_view") + /** Whether the date area should be visible. */ + val isDateVisible: StateFlow<Boolean> = + keyguardClockViewModel.hasCustomWeatherDataDisplay + .map { !it } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = !keyguardClockViewModel.hasCustomWeatherDataDisplay.value, + ) - val weatherId: Int - get() = getId("weather_smartspace_view") - - var smartspaceView: View? = null - var weatherView: View? = null - var dateView: View? = null - - private fun getId(name: String): Int { - return context.resources.getIdentifier(name, "id", context.packageName).also { - if (it == 0) { - Log.d(TAG, "Cannot resolve id $name") + /** Whether the weather area should be visible. */ + val isWeatherVisible: StateFlow<Boolean> = + keyguardClockViewModel.hasCustomWeatherDataDisplay + .map { clockIncludesCustomWeatherDisplay -> + isWeatherVisible( + clockIncludesCustomWeatherDisplay = clockIncludesCustomWeatherDisplay, + isWeatherEnabled = isWeatherEnabled, + ) } - } - } - fun getDimen(name: String): Int { - val res = context.packageManager.getResourcesForApplication(context.packageName) - val id = res.getIdentifier(name, "dimen", context.packageName) - return res.getDimensionPixelSize(id) - } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = + isWeatherVisible( + clockIncludesCustomWeatherDisplay = + keyguardClockViewModel.hasCustomWeatherDataDisplay.value, + isWeatherEnabled = isWeatherEnabled, + ) + ) - companion object { - private val TAG = KeyguardSmartspaceViewModel::class.java.simpleName + private fun isWeatherVisible( + clockIncludesCustomWeatherDisplay: Boolean, + isWeatherEnabled: Boolean, + ): Boolean { + return !clockIncludesCustomWeatherDisplay && isWeatherEnabled } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt index 539db7fb1ae3..2b28a71b4a3d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt @@ -38,7 +38,6 @@ constructor( deviceEntryInteractor: DeviceEntryInteractor, communalInteractor: CommunalInteractor, val longPress: KeyguardLongPressViewModel, - val keyguardRoot: KeyguardRootViewModel, val notifications: NotificationsPlaceholderViewModel, ) { /** The key of the scene we should switch to when swiping up. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt index 1dbf1f14b569..693e3b7506fc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt @@ -28,13 +28,16 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.isDefaultOrientation import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.res.R +import com.android.systemui.statusbar.phone.DozeServiceHost import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow @@ -43,6 +46,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onCompletion @@ -54,9 +58,13 @@ class SideFpsProgressBarViewModel @Inject constructor( private val context: Context, - private val fpAuthRepository: DeviceEntryFingerprintAuthRepository, + private val fpAuthRepository: DeviceEntryFingerprintAuthInteractor, private val sfpsSensorInteractor: SideFpsSensorInteractor, + // todo (b/317432075) Injecting DozeServiceHost directly instead of using it through + // DozeInteractor as DozeServiceHost already depends on DozeInteractor. + private val dozeServiceHost: DozeServiceHost, displayStateInteractor: DisplayStateInteractor, + @Main private val mainDispatcher: CoroutineDispatcher, @Application private val applicationScope: CoroutineScope, ) { private val _progress = MutableStateFlow(0.0f) @@ -168,18 +176,21 @@ constructor( return@collectLatest } animatorJob = - fpAuthRepository.authenticationStatus - .onEach { authStatus -> + combine( + sfpsSensorInteractor.authenticationDuration, + fpAuthRepository.authenticationStatus, + ::Pair + ) + .onEach { (authDuration, authStatus) -> when (authStatus) { is AcquiredFingerprintAuthenticationStatus -> { if (authStatus.fingerprintCaptureStarted) { _visible.value = true + dozeServiceHost.fireSideFpsAcquisitionStarted() _animator?.cancel() _animator = ValueAnimator.ofFloat(0.0f, 1.0f) - .setDuration( - sfpsSensorInteractor.authenticationDuration - ) + .setDuration(authDuration) .apply { addUpdateListener { _progress.value = it.animatedValue as Float @@ -209,6 +220,7 @@ constructor( else -> Unit } } + .flowOn(mainDispatcher) .onCompletion { _animator?.cancel() } .launchIn(applicationScope) } diff --git a/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt index 919072a63220..171656a48e58 100644 --- a/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt @@ -108,4 +108,13 @@ class SideFpsLogger @Inject constructor(@BouncerLog private val buffer: LogBuffe } ) } + + fun authDurationChanged(duration: Long) { + buffer.log( + TAG, + LogLevel.DEBUG, + { long1 = duration }, + { "SideFpsSensor auth duration changed: $long1" } + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index a6c623391bb0..7e06f5a21113 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -87,6 +87,7 @@ import java.util.Locale; import java.util.Objects; import javax.inject.Inject; +import javax.inject.Provider; /** */ @@ -149,6 +150,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { public static final String EXTRA_CONFIRM_ONLY = "extra_confirm_only"; private final Context mContext; + private final SystemUIDialog.Factory mSystemUIDialogFactory; private final NotificationManager mNoMan; private final PowerManager mPowerMan; private final KeyguardManager mKeyguard; @@ -186,11 +188,17 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { /** */ @Inject - public PowerNotificationWarnings(Context context, ActivityStarter activityStarter, - BroadcastSender broadcastSender, Lazy<BatteryController> batteryControllerLazy, - DialogLaunchAnimator dialogLaunchAnimator, UiEventLogger uiEventLogger, - GlobalSettings globalSettings, UserTracker userTracker) { + public PowerNotificationWarnings( + Context context, + ActivityStarter activityStarter, + BroadcastSender broadcastSender, + Lazy<BatteryController> batteryControllerLazy, + DialogLaunchAnimator dialogLaunchAnimator, + UiEventLogger uiEventLogger, + UserTracker userTracker, + SystemUIDialog.Factory systemUIDialogFactory) { mContext = context; + mSystemUIDialogFactory = systemUIDialogFactory; mNoMan = mContext.getSystemService(NotificationManager.class); mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mKeyguard = mContext.getSystemService(KeyguardManager.class); @@ -444,7 +452,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private void showHighTemperatureDialog() { if (mHighTempDialog != null) return; - final SystemUIDialog d = new SystemUIDialog(mContext); + final SystemUIDialog d = mSystemUIDialogFactory.create(); d.setIconAttribute(android.R.attr.alertDialogIcon); d.setTitle(R.string.high_temp_title); d.setMessage(R.string.high_temp_dialog_message); @@ -479,7 +487,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private void showThermalShutdownDialog() { if (mThermalShutdownDialog != null) return; - final SystemUIDialog d = new SystemUIDialog(mContext); + final SystemUIDialog d = mSystemUIDialogFactory.create(); d.setIconAttribute(android.R.attr.alertDialogIcon); d.setTitle(R.string.thermal_shutdown_title); d.setMessage(R.string.thermal_shutdown_dialog_message); @@ -643,7 +651,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private void showStartSaverConfirmation(Bundle extras) { if (mSaverConfirmation != null || mUseExtraSaverConfirmation) return; - final SystemUIDialog d = new SystemUIDialog(mContext); + final SystemUIDialog d = mSystemUIDialogFactory.create(); final boolean confirmOnly = extras.getBoolean(BatterySaverUtils.EXTRA_CONFIRM_TEXT_ONLY); final int batterySaverTriggerMode = extras.getInt(BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER, diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt index 6f35cfbfb4a5..b5def41fb3c7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt @@ -148,7 +148,8 @@ class FgsManagerControllerImpl @Inject constructor( private val deviceConfigProxy: DeviceConfigProxy, private val dialogLaunchAnimator: DialogLaunchAnimator, private val broadcastDispatcher: BroadcastDispatcher, - private val dumpManager: DumpManager + private val dumpManager: DumpManager, + private val systemUIDialogFactory: SystemUIDialog.Factory, ) : Dumpable, FgsManagerController { companion object { @@ -375,7 +376,7 @@ class FgsManagerControllerImpl @Inject constructor( override fun showDialog(expandable: Expandable?) { synchronized(lock) { if (dialog == null) { - val dialog = SystemUIDialog(context) + val dialog = systemUIDialogFactory.create() dialog.setTitle(R.string.fgs_manager_dialog_title) dialog.setMessage(R.string.fgs_manager_dialog_message) 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 ccf7afbe7016..c9b002209fa8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -55,6 +55,7 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements private final DataSaverController mDataSaverController; private final DialogLaunchAnimator mDialogLaunchAnimator; + private final SystemUIDialog.Factory mSystemUIDialogFactory; @Inject public DataSaverTile( @@ -68,12 +69,14 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements ActivityStarter activityStarter, QSLogger qsLogger, DataSaverController dataSaverController, - DialogLaunchAnimator dialogLaunchAnimator + DialogLaunchAnimator dialogLaunchAnimator, + SystemUIDialog.Factory systemUIDialogFactory ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mDataSaverController = dataSaverController; mDialogLaunchAnimator = dialogLaunchAnimator; + mSystemUIDialogFactory = systemUIDialogFactory; mDataSaverController.observe(getLifecycle(), this); } @@ -98,7 +101,7 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements // Show a dialog to confirm first. Dialogs shown by the DialogLaunchAnimator must be created // and shown on the main thread, so we post it to the UI handler. mUiHandler.post(() -> { - SystemUIDialog dialog = new SystemUIDialog(mContext); + SystemUIDialog dialog = mSystemUIDialogFactory.create(); dialog.setTitle(com.android.internal.R.string.data_saver_enable_title); dialog.setMessage(com.android.internal.R.string.data_saver_description); dialog.setPositiveButton(com.android.internal.R.string.data_saver_enable_button, 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 f37f58db05f8..e89cc5af9a20 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -194,7 +194,8 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> ActivityStarter.OnDismissAction dismissAction = () -> { if (shouldAnimateFromView) { mDialogLaunchAnimator.showFromView(dialog, view, new DialogCuj( - InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)); + InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG), + /* animateBackgroundBoundsChange= */ true); } else { dialog.show(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt index acd7510a6c2a..41cd221186fe 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt @@ -23,7 +23,6 @@ import android.content.DialogInterface.BUTTON_NEUTRAL import android.content.Intent import android.provider.Settings import android.view.LayoutInflater -import androidx.annotation.VisibleForTesting import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.UiEventLogger import com.android.systemui.res.R @@ -44,31 +43,15 @@ import javax.inject.Provider * Controller for [UserDialog]. */ @SysUISingleton -class UserSwitchDialogController @VisibleForTesting constructor( - private val userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>, - private val activityStarter: ActivityStarter, - private val falsingManager: FalsingManager, - private val dialogLaunchAnimator: DialogLaunchAnimator, - private val uiEventLogger: UiEventLogger, - private val dialogFactory: (Context) -> SystemUIDialog +class UserSwitchDialogController @Inject constructor( + private val userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>, + private val activityStarter: ActivityStarter, + private val falsingManager: FalsingManager, + private val dialogLaunchAnimator: DialogLaunchAnimator, + private val uiEventLogger: UiEventLogger, + private val dialogFactory: SystemUIDialog.Factory ) { - @Inject - constructor( - userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>, - activityStarter: ActivityStarter, - falsingManager: FalsingManager, - dialogLaunchAnimator: DialogLaunchAnimator, - uiEventLogger: UiEventLogger - ) : this( - userDetailViewAdapterProvider, - activityStarter, - falsingManager, - dialogLaunchAnimator, - uiEventLogger, - { SystemUIDialog(it) } - ) - companion object { private const val INTERACTION_JANK_TAG = "switch_user" private val USER_SETTINGS_INTENT = Intent(Settings.ACTION_USER_SETTINGS) @@ -81,7 +64,7 @@ class UserSwitchDialogController @VisibleForTesting constructor( * [userDetailViewAdapterProvider] and show it as launched from [expandable]. */ fun showDialog(context: Context, expandable: Expandable) { - with(dialogFactory(context)) { + with(dialogFactory.create()) { setShowForAllUsers(true) setCanceledOnTouchOutside(true) diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java index f07162377358..9076182def70 100644 --- a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java @@ -21,8 +21,10 @@ import android.annotation.SuppressLint; import android.annotation.TestApi; import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.hardware.devicestate.DeviceStateManager; import android.hardware.devicestate.DeviceStateManagerGlobal; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; @@ -72,20 +74,27 @@ public class RearDisplayDialogController implements private DeviceStateManager.DeviceStateCallback mDeviceStateManagerCallback = new DeviceStateManagerCallback(); - private final Context mContext; private final CommandQueue mCommandQueue; private final Executor mExecutor; + private final Resources mResources; + private final LayoutInflater mLayoutInflater; + private final SystemUIDialog.Factory mSystemUIDialogFactory; - @VisibleForTesting - SystemUIDialog mRearDisplayEducationDialog; + private SystemUIDialog mRearDisplayEducationDialog; @Nullable LinearLayout mDialogViewContainer; @Inject - public RearDisplayDialogController(Context context, CommandQueue commandQueue, - @Main Executor executor) { - mContext = context; + public RearDisplayDialogController( + CommandQueue commandQueue, + @Main Executor executor, + @Main Resources resources, + LayoutInflater layoutInflater, + SystemUIDialog.Factory systemUIDialogFactory) { mCommandQueue = commandQueue; mExecutor = executor; + mResources = resources; + mLayoutInflater = layoutInflater; + mSystemUIDialogFactory = systemUIDialogFactory; } @Override @@ -104,8 +113,7 @@ public class RearDisplayDialogController implements if (mRearDisplayEducationDialog != null && mRearDisplayEducationDialog.isShowing() && mDialogViewContainer != null) { // Refresh the dialog view when configuration is changed. - Context dialogContext = mRearDisplayEducationDialog.getContext(); - View dialogView = createDialogView(dialogContext); + View dialogView = createDialogView(mRearDisplayEducationDialog.getContext()); mDialogViewContainer.removeAllViews(); mDialogViewContainer.addView(dialogView); } @@ -114,9 +122,7 @@ public class RearDisplayDialogController implements private void createAndShowDialog() { mServiceNotified = false; Context dialogContext = mRearDisplayEducationDialog.getContext(); - View dialogView = createDialogView(dialogContext); - mDialogViewContainer = new LinearLayout(dialogContext); mDialogViewContainer.setLayoutParams( new LinearLayout.LayoutParams( @@ -133,11 +139,11 @@ public class RearDisplayDialogController implements private View createDialogView(Context context) { View dialogView; + LayoutInflater inflater = mLayoutInflater.cloneInContext(context); if (mStartedFolded) { - dialogView = View.inflate(context, - R.layout.activity_rear_display_education, null); + dialogView = inflater.inflate(R.layout.activity_rear_display_education, null); } else { - dialogView = View.inflate(context, + dialogView = inflater.inflate( R.layout.activity_rear_display_education_opened, null); } LottieAnimationView animationView = dialogView.findViewById( @@ -172,9 +178,9 @@ public class RearDisplayDialogController implements * Ensures we're not using old values from when the dialog may have been shown previously. */ private void initializeValues(int startingBaseState) { - mRearDisplayEducationDialog = new SystemUIDialog(mContext); + mRearDisplayEducationDialog = mSystemUIDialogFactory.create(); if (mFoldedStates == null) { - mFoldedStates = mContext.getResources().getIntArray( + mFoldedStates = mResources.getIntArray( com.android.internal.R.array.config_foldedDeviceStates); } mStartedFolded = isFoldedState(startingBaseState); diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index ab69acbc6e9d..3be60b74af21 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -157,7 +157,10 @@ constructor( // If the hub is fully visible, send all touch events to it. val communalVisible = hubShowing && !hubOccluded if (communalVisible) { - return communalContainerView.dispatchTouchEvent(ev) + communalContainerView.dispatchTouchEvent(ev) + // Return true regardless of dispatch result as some touches at the start of a gesture + // may return false from dispatchTouchEvent. + return true } if (edgeSwipeRegionWidth == 0) { @@ -172,13 +175,19 @@ constructor( x >= communalContainerView.width - edgeSwipeRegionWidth if (inOpeningSwipeRegion && !hubOccluded) { isTrackingOpenGesture = true - return communalContainerView.dispatchTouchEvent(ev) + communalContainerView.dispatchTouchEvent(ev) + // Return true regardless of dispatch result as some touches at the start of a + // gesture may return false from dispatchTouchEvent. + return true } } else if (isTrackingOpenGesture) { if (isUp || isCancel) { isTrackingOpenGesture = false } - return communalContainerView.dispatchTouchEvent(ev) + communalContainerView.dispatchTouchEvent(ev) + // Return true regardless of dispatch result as some touches at the start of a gesture + // may return false from dispatchTouchEvent. + return true } return false diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 286037ef1961..fb6bc38c9a0b 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -2478,6 +2478,13 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump return 0; } if (!mKeyguardBypassController.getBypassEnabled()) { + if (migrateClocksToBlueprint()) { + View nsslPlaceholder = mView.getRootView().findViewById(R.id.nssl_placeholder); + if (!mSplitShadeEnabled && nsslPlaceholder != null) { + return nsslPlaceholder.getTop(); + } + } + return mClockPositionResult.stackScrollerPadding; } int collapsedPosition = mHeadsUpInset; diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 3cf468f302b2..cde2a62f9ae9 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -54,13 +54,10 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl; import com.android.systemui.keyguard.shared.model.TransitionState; import com.android.systemui.keyguard.shared.model.TransitionStep; -import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler; import com.android.systemui.keyguard.ui.binder.AlternateBouncerViewBinder; -import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel; -import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel; +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies; import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel; import com.android.systemui.log.BouncerLogger; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.res.R; import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener; import com.android.systemui.statusbar.DragDownHelper; @@ -69,7 +66,6 @@ import com.android.systemui.statusbar.NotificationInsetsController; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.gesture.TapGestureDetector; import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; @@ -204,11 +200,7 @@ public class NotificationShadeWindowViewController implements Dumpable { AlternateBouncerInteractor alternateBouncerInteractor, SelectedUserInteractor selectedUserInteractor, Lazy<JavaAdapter> javaAdapter, - Lazy<AlternateBouncerViewModel> alternateBouncerViewModel, - Lazy<FalsingManager> falsingManager, - Lazy<SwipeUpAnywhereGestureHandler> swipeUpAnywhereGestureHandler, - Lazy<TapGestureDetector> tapGestureDetector, - Lazy<AlternateBouncerUdfpsIconViewModel> alternateBouncerUdfpsIconViewModel) { + Lazy<AlternateBouncerDependencies> alternateBouncerDependencies) { mLockscreenShadeTransitionController = transitionController; mFalsingCollector = falsingCollector; mStatusBarStateController = statusBarStateController; @@ -250,24 +242,21 @@ public class NotificationShadeWindowViewController implements Dumpable { messageAreaControllerFactory, bouncerMessageInteractor, bouncerLogger, - featureFlagsClassic, selectedUserInteractor); if (DeviceEntryUdfpsRefactor.isEnabled()) { AlternateBouncerViewBinder.bind( mView.findViewById(R.id.alternate_bouncer), - alternateBouncerViewModel.get(), - falsingManager.get(), - swipeUpAnywhereGestureHandler.get(), - tapGestureDetector.get(), - alternateBouncerUdfpsIconViewModel.get() + alternateBouncerDependencies.get() ); javaAdapter.get().alwaysCollectFlow( - alternateBouncerViewModel.get().getForcePluginOpen(), - forcePluginOpen -> + alternateBouncerDependencies.get().getViewModel() + .getForcePluginOpen(), + forcePluginOpen -> mNotificationShadeWindowController.setForcePluginOpen( forcePluginOpen, - alternateBouncerViewModel.get() + alternateBouncerDependencies.get() + .getViewModel() ) ); } diff --git a/packages/SystemUI/src/com/android/systemui/startable/Dependencies.kt b/packages/SystemUI/src/com/android/systemui/startable/Dependencies.kt new file mode 100644 index 000000000000..5e57f1d1a11f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/startable/Dependencies.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.startable + +import com.android.systemui.CoreStartable +import kotlin.reflect.KClass + +/** + * Allows a [CoreStartable] to declare that it must be started after its dependencies. + * + * This creates a partial, topological ordering. See [com.android.systemui.SystemUIApplication] for + * how this ordering is enforced at runtime. + */ +@MustBeDocumented +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class Dependencies(vararg val value: KClass<out CoreStartable> = []) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 633510d9c438..9b8dd0b75a24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -15,6 +15,8 @@ */ package com.android.systemui.statusbar; +import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; +import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; @@ -22,6 +24,7 @@ import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_NULL; import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS; +import static android.app.Flags.keyguardPrivateNotifications; import static android.os.Flags.allowPrivateProfile; import static com.android.systemui.DejankUtils.whitelistIpcs; @@ -47,7 +50,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Log; -import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -149,6 +151,25 @@ public class NotificationLockscreenUserManagerImpl implements new ListenerSet<>(); private final Collection<Uri> mLockScreenUris = new ArrayList<>(); + protected final BroadcastReceiver mKeyguardReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + if (ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED.equals(action)) { + if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) { + mKeyguardAllowingNotifications = + intent.getBooleanExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false); + if (mCurrentUserId == getSendingUserId()) { + boolean changed = updateLockscreenNotificationSetting(); + if (changed) { + notifyNotificationStateChanged(); + } + } + } + } + } + }; protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() { @Override @@ -254,7 +275,12 @@ public class NotificationLockscreenUserManagerImpl implements updateLockscreenNotificationSetting(); updatePublicMode(); - mPresenter.onUserSwitched(mCurrentUserId); + if (mPresenter != null) { + mPresenter.onUserSwitched(mCurrentUserId); + } else { + Log.w(TAG, "user switch before setup with presenter", + new Exception()); + } for (UserChangedListener listener : mListeners) { listener.onUserChanged(mCurrentUserId); @@ -321,11 +347,21 @@ public class NotificationLockscreenUserManagerImpl implements mLockScreenUris.add(SHOW_PRIVATE_LOCKSCREEN); dumpManager.registerDumpable(this); + + if (keyguardPrivateNotifications()) { + init(); + } } public void setUpWithPresenter(NotificationPresenter presenter) { mPresenter = presenter; + if (!keyguardPrivateNotifications()) { + init(); + } + } + + private void init() { mLockscreenSettingsObserver = new ContentObserver( mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD) ? mBackgroundHandler @@ -408,6 +444,11 @@ public class NotificationLockscreenUserManagerImpl implements new IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD) ? mBackgroundExecutor : null, UserHandle.ALL); + if (keyguardPrivateNotifications()) { + mBroadcastDispatcher.registerReceiver(mKeyguardReceiver, + new IntentFilter(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED), + mBackgroundExecutor, UserHandle.ALL); + } IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_ADDED); @@ -449,6 +490,10 @@ public class NotificationLockscreenUserManagerImpl implements mLockscreenSettingsObserver.onChange( false, mLockScreenUris, 0, UserHandle.of(userId)); updateDpcSettings(userId); + + if (keyguardPrivateNotifications()) { + updateGlobalKeyguardSettings(); + } } public boolean shouldShowLockscreenNotifications() { @@ -477,8 +522,12 @@ public class NotificationLockscreenUserManagerImpl implements boolean allowedByDpm; if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) { - show = mUsersUsersAllowingNotifications.get(mCurrentUserId) - && mKeyguardAllowingNotifications; + if (keyguardPrivateNotifications()) { + show = mUsersUsersAllowingNotifications.get(mCurrentUserId); + } else { + show = mUsersUsersAllowingNotifications.get(mCurrentUserId) + && mKeyguardAllowingNotifications; + } // If DPC never notified us about a user, that means they have no policy for the user, // and they allow the behavior allowedByDpm = mUsersDpcAllowingNotifications.get(mCurrentUserId, true); @@ -521,8 +570,13 @@ public class NotificationLockscreenUserManagerImpl implements 1, userId) != 0; mUsersUsersAllowingNotifications.put(userId, newAllowLockscreen); - boolean keyguardChanged = updateGlobalKeyguardSettings(); - return (newAllowLockscreen != originalAllowLockscreen) || keyguardChanged; + + if (keyguardPrivateNotifications()) { + return (newAllowLockscreen != originalAllowLockscreen); + } else { + boolean keyguardChanged = updateGlobalKeyguardSettings(); + return (newAllowLockscreen != originalAllowLockscreen) || keyguardChanged; + } } @WorkerThread @@ -560,8 +614,14 @@ public class NotificationLockscreenUserManagerImpl implements Log.i(TAG, "Asking for redact notifs dpm override too early", new Throwable()); return false; } - return mUsersUsersAllowingPrivateNotifications.get(userHandle) - && mUsersDpcAllowingPrivateNotifications.get(userHandle); + if (keyguardPrivateNotifications()) { + return mUsersUsersAllowingPrivateNotifications.get(userHandle) + && mUsersDpcAllowingPrivateNotifications.get(userHandle) + && mKeyguardAllowingNotifications; + } else { + return mUsersUsersAllowingPrivateNotifications.get(userHandle) + && mUsersDpcAllowingPrivateNotifications.get(userHandle); + } } else { if (userHandle == USER_ALL) { return true; @@ -648,9 +708,14 @@ public class NotificationLockscreenUserManagerImpl implements Log.wtf(TAG, "Asking for show notifs dpm override too early", new Throwable()); updateDpcSettings(userHandle); } - return mUsersUsersAllowingNotifications.get(userHandle) - && mUsersDpcAllowingNotifications.get(userHandle) - && mKeyguardAllowingNotifications; + if (keyguardPrivateNotifications()) { + return mUsersUsersAllowingNotifications.get(userHandle) + && mUsersDpcAllowingNotifications.get(userHandle); + } else { + return mUsersUsersAllowingNotifications.get(userHandle) + && mUsersDpcAllowingNotifications.get(userHandle) + && mKeyguardAllowingNotifications; + } } else { if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) { return true; @@ -689,7 +754,12 @@ public class NotificationLockscreenUserManagerImpl implements ent.getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE; boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey()); - return userForcesRedaction || notificationRequestsRedaction && isNotifRedacted; + if (keyguardPrivateNotifications()) { + return !mKeyguardAllowingNotifications + || userForcesRedaction || notificationRequestsRedaction && isNotifRedacted; + } else { + return userForcesRedaction || notificationRequestsRedaction && isNotifRedacted; + } } private boolean packageHasVisibilityOverride(String key) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 984fcad469a8..7a2e82f24f46 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -323,9 +323,14 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi * Update the icon dimens and drawable with current resources */ public void updateIconDimens() { - reloadDimens(); - updateDrawable(); - maybeUpdateIconScaleDimens(); + Trace.beginSection("StatusBarIconView#updateIconDimens"); + try { + reloadDimens(); + updateDrawable(); + maybeUpdateIconScaleDimens(); + } finally { + Trace.endSection(); + } } private void reloadDimens() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt index 921556854440..b913355ea59b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.icon.domain.interactor +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository @@ -26,11 +27,13 @@ import com.android.systemui.statusbar.notification.shared.ActiveNotificationMode import com.android.wm.shell.bubbles.Bubbles import java.util.Optional import javax.inject.Inject +import kotlin.coroutines.CoroutineContext import kotlin.jvm.optionals.getOrNull import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn /** Domain logic related to notification icons. */ class NotificationIconsInteractor @@ -103,35 +106,41 @@ constructor( class AlwaysOnDisplayNotificationIconsInteractor @Inject constructor( + @Background bgContext: CoroutineContext, deviceEntryInteractor: DeviceEntryInteractor, iconsInteractor: NotificationIconsInteractor, ) { val aodNotifs: Flow<Set<ActiveNotificationModel>> = - deviceEntryInteractor.isBypassEnabled.flatMapLatest { isBypassEnabled -> - iconsInteractor.filteredNotifSet( - showAmbient = false, - showDismissed = false, - showRepliedMessages = false, - showPulsing = !isBypassEnabled, - ) - } + deviceEntryInteractor.isBypassEnabled + .flatMapLatest { isBypassEnabled -> + iconsInteractor.filteredNotifSet( + showAmbient = false, + showDismissed = false, + showRepliedMessages = false, + showPulsing = !isBypassEnabled, + ) + } + .flowOn(bgContext) } /** Domain logic related to notification icons shown in the status bar. */ class StatusBarNotificationIconsInteractor @Inject constructor( + @Background bgContext: CoroutineContext, iconsInteractor: NotificationIconsInteractor, settingsRepository: NotificationListenerSettingsRepository, ) { val statusBarNotifs: Flow<Set<ActiveNotificationModel>> = - settingsRepository.showSilentStatusIcons.flatMapLatest { showSilentIcons -> - iconsInteractor.filteredNotifSet( - forceShowHeadsUp = true, - showAmbient = false, - showLowPriority = showSilentIcons, - showDismissed = false, - showRepliedMessages = false, - ) - } + settingsRepository.showSilentStatusIcons + .flatMapLatest { showSilentIcons -> + iconsInteractor.filteredNotifSet( + forceShowHeadsUp = true, + showAmbient = false, + showLowPriority = showSilentIcons, + showDismissed = false, + showRepliedMessages = false, + ) + } + .flowOn(bgContext) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerAlwaysOnDisplayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerAlwaysOnDisplayViewBinder.kt index d7c29f19fe57..38489f928146 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerAlwaysOnDisplayViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerAlwaysOnDisplayViewBinder.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder import androidx.lifecycle.lifecycleScope +import com.android.app.tracing.traceSection import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel @@ -44,25 +45,27 @@ constructor( private val viewStore: AlwaysOnDisplayNotificationIconViewStore, ) { fun bindWhileAttached(view: NotificationIconContainer): DisposableHandle { - return view.repeatWhenAttached { - lifecycleScope.launch { - launch { - NotificationIconContainerViewBinder.bind( - view = view, - viewModel = viewModel, - configuration = configuration, - systemBarUtilsState = systemBarUtilsState, - failureTracker = failureTracker, - viewStore = viewStore, - ) - } - launch { - KeyguardRootViewBinder.bindAodNotifIconVisibility( - view = view, - isVisible = keyguardRootViewModel.isNotifIconContainerVisible, - configuration = configuration, - screenOffAnimationController = screenOffAnimationController, - ) + return traceSection("NICAlwaysOnDisplay#bindWhileAttached") { + view.repeatWhenAttached { + lifecycleScope.launch { + launch { + NotificationIconContainerViewBinder.bind( + view = view, + viewModel = viewModel, + configuration = configuration, + systemBarUtilsState = systemBarUtilsState, + failureTracker = failureTracker, + viewStore = viewStore, + ) + } + launch { + KeyguardRootViewBinder.bindAodNotifIconVisibility( + view = view, + isVisible = keyguardRootViewModel.isNotifIconContainerVisible, + configuration = configuration, + screenOffAnimationController = screenOffAnimationController, + ) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt index 8e089b1f11fd..3599f1f51966 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder import androidx.lifecycle.lifecycleScope +import com.android.app.tracing.traceSection import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.statusbar.notification.collection.NotifCollection @@ -39,16 +40,18 @@ constructor( private val viewStore: StatusBarNotificationIconViewStore, ) { fun bindWhileAttached(view: NotificationIconContainer): DisposableHandle { - return view.repeatWhenAttached { - lifecycleScope.launch { - NotificationIconContainerViewBinder.bind( - view = view, - viewModel = viewModel, - configuration = configuration, - systemBarUtilsState = systemBarUtilsState, - failureTracker = failureTracker, - viewStore = viewStore, - ) + return traceSection("NICStatusBar#bindWhileAttached") { + view.repeatWhenAttached { + lifecycleScope.launch { + NotificationIconContainerViewBinder.bind( + view = view, + viewModel = viewModel, + configuration = configuration, + systemBarUtilsState = systemBarUtilsState, + failureTracker = failureTracker, + viewStore = viewStore, + ) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt index b76cdb8a5a3c..ae772880f148 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt @@ -24,6 +24,8 @@ import android.widget.FrameLayout import androidx.annotation.ColorInt import androidx.collection.ArrayMap import androidx.lifecycle.lifecycleScope +import com.android.app.tracing.traceSection +import com.android.internal.R as RInternal import com.android.internal.statusbar.StatusBarIcon import com.android.internal.util.ContrastColorUtil import com.android.systemui.common.ui.ConfigurationState @@ -48,8 +50,10 @@ import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.Job import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** Binds a view-model to a [NotificationIconContainer]. */ @@ -65,8 +69,8 @@ object NotificationIconContainerViewBinder { ): Unit = coroutineScope { launch { val contrastColorUtil = ContrastColorUtil.getInstance(view.context) - val iconColors: Flow<NotificationIconColors> = - viewModel.iconColors.mapNotNull { it.iconColors(view.viewBounds) } + val iconColors: StateFlow<NotificationIconColors> = + viewModel.iconColors.mapNotNull { it.iconColors(view.viewBounds) }.stateIn(this) viewModel.icons.bindIcons( view, configuration, @@ -111,6 +115,14 @@ object NotificationIconContainerViewBinder { ): Unit = coroutineScope { view.setUseIncreasedIconScale(true) launch { + // Collect state shared across all icon views, so that we are not duplicating collects + // for each individual icon. + val color: StateFlow<Int> = + configuration + .getColorAttr(R.attr.wallpaperTextColor, DEFAULT_AOD_ICON_COLOR) + .stateIn(this) + val tintAlpha = viewModel.tintAlpha.stateIn(this) + val animsEnabled = viewModel.areIconAnimationsEnabled.stateIn(this) viewModel.icons.bindIcons( view, configuration, @@ -118,30 +130,16 @@ object NotificationIconContainerViewBinder { notifyBindingFailures = { failureTracker.aodFailures = it }, viewStore, ) { _, sbiv -> - viewModel.bindAodStatusBarIconView(sbiv, configuration) + coroutineScope { + launch { StatusBarIconViewBinder.bindColor(sbiv, color) } + launch { StatusBarIconViewBinder.bindTintAlpha(sbiv, tintAlpha) } + launch { StatusBarIconViewBinder.bindAnimationsEnabled(sbiv, animsEnabled) } + } } } launch { viewModel.areContainerChangesAnimated.bindAnimationsEnabled(view) } } - private suspend fun NotificationIconContainerAlwaysOnDisplayViewModel.bindAodStatusBarIconView( - sbiv: StatusBarIconView, - configuration: ConfigurationState, - ) { - coroutineScope { - launch { - val color: Flow<Int> = - configuration.getColorAttr( - R.attr.wallpaperTextColor, - DEFAULT_AOD_ICON_COLOR, - ) - StatusBarIconViewBinder.bindColor(sbiv, color) - } - launch { StatusBarIconViewBinder.bindTintAlpha(sbiv, tintAlpha) } - launch { StatusBarIconViewBinder.bindAnimationsEnabled(sbiv, areIconAnimationsEnabled) } - } - } - /** Binds to [NotificationIconContainer.setAnimationsEnabled] */ private suspend fun Flow<Boolean>.bindAnimationsEnabled(view: NotificationIconContainer) { collect(view::setAnimationsEnabled) @@ -184,21 +182,20 @@ object NotificationIconContainerViewBinder { notifyBindingFailures: (Collection<String>) -> Unit, viewStore: IconViewStore, bindIcon: suspend (iconKey: String, view: StatusBarIconView) -> Unit = { _, _ -> }, - ) { + ): Unit = coroutineScope { val iconSizeFlow: Flow<Int> = - configuration.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_icon_size_sp, - ) + configuration.getDimensionPixelSize(RInternal.dimen.status_bar_icon_size_sp) val iconHorizontalPaddingFlow: Flow<Int> = configuration.getDimensionPixelSize(R.dimen.status_bar_icon_horizontal_margin) val layoutParams: Flow<FrameLayout.LayoutParams> = combine(iconSizeFlow, iconHorizontalPaddingFlow, systemBarUtilsState.statusBarHeight) { - iconSize, - iconHPadding, - statusBarHeight, - -> - FrameLayout.LayoutParams(iconSize + 2 * iconHPadding, statusBarHeight) - } + iconSize, + iconHPadding, + statusBarHeight, + -> + FrameLayout.LayoutParams(iconSize + 2 * iconHPadding, statusBarHeight) + } + .stateIn(this) try { bindIcons(view, layoutParams, notifyBindingFailures, viewStore, bindIcon) } finally { @@ -217,7 +214,7 @@ object NotificationIconContainerViewBinder { val failedBindings = mutableSetOf<String>() val boundViewsByNotifKey = ArrayMap<String, Pair<StatusBarIconView, Job>>() var prevIcons = NotificationIconsViewData() - collect { iconsData: NotificationIconsViewData -> + collectTracingEach("NotifIconContainer#bindIcons") { iconsData: NotificationIconsViewData -> val iconsDiff = NotificationIconsViewData.computeDifference(iconsData, prevIcons) prevIcons = iconsData @@ -231,8 +228,10 @@ object NotificationIconContainerViewBinder { for (notifKey in iconsDiff.removed) { failedBindings.remove(notifKey) val (child, job) = boundViewsByNotifKey.remove(notifKey) ?: continue - view.removeView(child) - job.cancel() + traceSection("removeIcon") { + view.removeView(child) + job.cancel() + } } // Add and bind. @@ -245,27 +244,32 @@ object NotificationIconContainerViewBinder { continue } failedBindings.remove(notifKey) - (sbiv.parent as? ViewGroup)?.run { - if (this !== view) { - Log.wtf(TAG, "StatusBarIconView($notifKey) has an unexpected parent") + traceSection("addIcon") { + (sbiv.parent as? ViewGroup)?.run { + if (this !== view) { + Log.wtf( + TAG, + "StatusBarIconView($notifKey) has an unexpected parent", + ) + } + // If the container was re-inflated and re-bound, then SBIVs might still + // be attached to the prior view. + removeView(sbiv) + // The view might still be transiently added if it was just removed and + // added again. + removeTransientView(sbiv) } - // If the container was re-inflated and re-bound, then SBIVs might still be - // attached to the prior view. - removeView(sbiv) - // The view might still be transiently added if it was just removed and - // added again. - removeTransientView(sbiv) + view.addView(sbiv) + boundViewsByNotifKey.remove(notifKey)?.second?.cancel() + boundViewsByNotifKey[notifKey] = + Pair( + sbiv, + launch { + launch { layoutParams.collect { sbiv.layoutParams = it } } + bindIcon(notifKey, sbiv) + }, + ) } - view.addView(sbiv) - boundViewsByNotifKey.remove(notifKey)?.second?.cancel() - boundViewsByNotifKey[notifKey] = - Pair( - sbiv, - launch { - launch { layoutParams.collect { sbiv.layoutParams = it } } - bindIcon(notifKey, sbiv) - }, - ) } // Set the maximum number of icons to show in the container. Any icons over this @@ -273,10 +277,10 @@ object NotificationIconContainerViewBinder { val maxIconsAmount: Int = when (iconsData.limitType) { LimitType.MaximumIndex -> { - iconsData.visibleIcons - .asSequence() - .take(iconsData.iconLimit) - .count { info -> info.notifKey in boundViewsByNotifKey } + iconsData.visibleIcons.asSequence().take(iconsData.iconLimit).count { + info -> + info.notifKey in boundViewsByNotifKey + } } LimitType.MaximumAmount -> { iconsData.iconLimit @@ -289,19 +293,21 @@ object NotificationIconContainerViewBinder { // Re-sort notification icons view.changeViewPositions { - val expectedChildren: List<StatusBarIconView> = - iconsData.visibleIcons.mapNotNull { - boundViewsByNotifKey[it.notifKey]?.first - } - val childCount = view.childCount - for (i in 0 until childCount) { - val actual = view.getChildAt(i) - val expected = expectedChildren[i] - if (actual === expected) { - continue + traceSection("re-sort") { + val expectedChildren: List<StatusBarIconView> = + iconsData.visibleIcons.mapNotNull { + boundViewsByNotifKey[it.notifKey]?.first + } + val childCount = view.childCount + for (i in 0 until childCount) { + val actual = view.getChildAt(i) + val expected = expectedChildren[i] + if (actual === expected) { + continue + } + view.removeView(expected) + view.addView(expected, i) } - view.removeView(expected) - view.addView(expected, i) } } } @@ -362,3 +368,7 @@ private val View.viewBounds: Rect /* bottom = */ top + height, ) } + +private suspend fun <T> Flow<T>.collectTracingEach(tag: String, collector: (T) -> Unit) { + collect { traceSection(tag) { collector(it) } } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt index 9cb60d56f277..d903f066cde9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel import android.content.res.Resources import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -25,8 +26,10 @@ import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.icon.domain.interactor.AlwaysOnDisplayNotificationIconsInteractor import javax.inject.Inject +import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart @@ -35,46 +38,57 @@ import kotlinx.coroutines.flow.onStart class NotificationIconContainerAlwaysOnDisplayViewModel @Inject constructor( + @Background bgContext: CoroutineContext, iconsInteractor: AlwaysOnDisplayNotificationIconsInteractor, keyguardInteractor: KeyguardInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, @Main resources: Resources, shadeInteractor: ShadeInteractor, ) { - private val maxIcons = resources.getInteger(R.integer.max_notif_icons_on_aod) /** Are changes to the icon container animated? */ val areContainerChangesAnimated: Flow<Boolean> = combine( - shadeInteractor.isShadeTouchable, - keyguardInteractor.isKeyguardVisible, - ) { panelTouchesEnabled, isKeyguardVisible -> - panelTouchesEnabled && isKeyguardVisible - } + shadeInteractor.isShadeTouchable, + keyguardInteractor.isKeyguardVisible, + ) { panelTouchesEnabled, isKeyguardVisible -> + panelTouchesEnabled && isKeyguardVisible + } + .flowOn(bgContext) /** Amount of a "white" tint to be applied to the icons. */ val tintAlpha: Flow<Float> = combine( - keyguardTransitionInteractor.transitionValue(KeyguardState.AOD).onStart { emit(0f) }, - keyguardTransitionInteractor.transitionValue(KeyguardState.DOZING).onStart { emit(0f) }, - ) { aodAmt, dozeAmt -> - aodAmt + dozeAmt // If transitioning between them, they should sum to 1f - } + keyguardTransitionInteractor.transitionValue(KeyguardState.AOD).onStart { + emit(0f) + }, + keyguardTransitionInteractor.transitionValue(KeyguardState.DOZING).onStart { + emit(0f) + }, + ) { aodAmt, dozeAmt -> + aodAmt + dozeAmt // If transitioning between them, they should sum to 1f + } + .flowOn(bgContext) /** Are notification icons animated (ex: animated gif)? */ val areIconAnimationsEnabled: Flow<Boolean> = - keyguardTransitionInteractor.isFinishedInStateWhere { - // Don't animate icons when we're on AOD / dozing - it != KeyguardState.AOD && it != KeyguardState.DOZING - } + keyguardTransitionInteractor + .isFinishedInStateWhere { + // Don't animate icons when we're on AOD / dozing + it != KeyguardState.AOD && it != KeyguardState.DOZING + } + .flowOn(bgContext) + .onStart { emit(true) } /** [NotificationIconsViewData] indicating which icons to display in the view. */ val icons: Flow<NotificationIconsViewData> = - iconsInteractor.aodNotifs.map { entries -> - NotificationIconsViewData( - visibleIcons = entries.mapNotNull { it.toIconInfo(it.aodIcon) }, - iconLimit = maxIcons, - ) - } + iconsInteractor.aodNotifs + .map { entries -> + NotificationIconsViewData( + visibleIcons = entries.mapNotNull { it.toIconInfo(it.aodIcon) }, + iconLimit = maxIcons, + ) + } + .flowOn(bgContext) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt index 8484fdc92d4f..357482847700 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt @@ -15,38 +15,45 @@ */ package com.android.systemui.statusbar.notification.icon.ui.viewmodel +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.notification.icon.domain.interactor.NotificationIconsInteractor import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconsViewData.LimitType import javax.inject.Inject +import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map /** View-model for the overflow row of notification icons displayed in the notification shade. */ class NotificationIconContainerShelfViewModel @Inject constructor( + @Background bgContext: CoroutineContext, interactor: NotificationIconsInteractor, ) { /** [NotificationIconsViewData] indicating which icons to display in the view. */ val icons: Flow<NotificationIconsViewData> = - interactor.filteredNotifSet().map { entries -> - var firstAmbient = 0 - val visibleKeys = buildList { - for (entry in entries) { - entry.toIconInfo(entry.shelfIcon)?.let { info -> - add(info) - // NOTE: we assume that all ambient notifications will be at the end of the - // list - if (!entry.isAmbient) { - firstAmbient++ + interactor + .filteredNotifSet() + .map { entries -> + var firstAmbient = 0 + val visibleKeys = buildList { + for (entry in entries) { + entry.toIconInfo(entry.shelfIcon)?.let { info -> + add(info) + // NOTE: we assume that all ambient notifications will be at the end of + // the list + if (!entry.isAmbient) { + firstAmbient++ + } } } } + NotificationIconsViewData( + visibleKeys, + iconLimit = firstAmbient, + limitType = LimitType.MaximumIndex, + ) } - NotificationIconsViewData( - visibleKeys, - iconLimit = firstAmbient, - limitType = LimitType.MaximumIndex, - ) - } + .flowOn(bgContext) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt index d00cd1fcfed9..38921c2f773b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt @@ -17,12 +17,12 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel import android.content.res.Resources import android.graphics.Rect +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.DarkIconDispatcher import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor -import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor import com.android.systemui.statusbar.notification.icon.domain.interactor.StatusBarNotificationIconsInteractor import com.android.systemui.statusbar.phone.domain.interactor.DarkIconInteractor @@ -32,21 +32,23 @@ import com.android.systemui.util.ui.AnimatableEvent import com.android.systemui.util.ui.AnimatedValue import com.android.systemui.util.ui.toAnimatedValueFlow import javax.inject.Inject +import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map /** View-model for the row of notification icons displayed in the status bar, */ class NotificationIconContainerStatusBarViewModel @Inject constructor( + @Background bgContext: CoroutineContext, darkIconInteractor: DarkIconInteractor, iconsInteractor: StatusBarNotificationIconsInteractor, headsUpIconInteractor: HeadsUpNotificationIconInteractor, keyguardInteractor: KeyguardInteractor, - notificationsInteractor: ActiveNotificationsInteractor, @Main resources: Resources, shadeInteractor: ShadeInteractor, ) { @@ -56,37 +58,36 @@ constructor( /** Are changes to the icon container animated? */ val animationsEnabled: Flow<Boolean> = combine( - shadeInteractor.isShadeTouchable, - keyguardInteractor.isKeyguardShowing, - ) { panelTouchesEnabled, isKeyguardShowing -> - panelTouchesEnabled && !isKeyguardShowing - } + shadeInteractor.isShadeTouchable, + keyguardInteractor.isKeyguardShowing, + ) { panelTouchesEnabled, isKeyguardShowing -> + panelTouchesEnabled && !isKeyguardShowing + } + .flowOn(bgContext) /** The colors with which to display the notification icons. */ val iconColors: Flow<NotificationIconColorLookup> = - combine( - darkIconInteractor.tintAreas, - darkIconInteractor.tintColor, - // Included so that tints are re-applied after entries are changed. - notificationsInteractor.topLevelRepresentativeNotifications, - ) { areas, tint, _ -> - NotificationIconColorLookup { viewBounds: Rect -> - if (DarkIconDispatcher.isInAreas(areas, viewBounds)) { - IconColorsImpl(tint, areas) - } else { - null + combine(darkIconInteractor.tintAreas, darkIconInteractor.tintColor) { areas, tint -> + NotificationIconColorLookup { viewBounds: Rect -> + if (DarkIconDispatcher.isInAreas(areas, viewBounds)) { + IconColorsImpl(tint, areas) + } else { + null + } } } - } + .flowOn(bgContext) /** [NotificationIconsViewData] indicating which icons to display in the view. */ val icons: Flow<NotificationIconsViewData> = - iconsInteractor.statusBarNotifs.map { entries -> - NotificationIconsViewData( - visibleIcons = entries.mapNotNull { it.toIconInfo(it.statusBarIcon) }, - iconLimit = maxIcons, - ) - } + iconsInteractor.statusBarNotifs + .map { entries -> + NotificationIconsViewData( + visibleIcons = entries.mapNotNull { it.toIconInfo(it.statusBarIcon) }, + iconLimit = maxIcons, + ) + } + .flowOn(bgContext) /** An Icon to show "isolated" in the IconContainer. */ val isolatedIcon: Flow<AnimatedValue<NotificationIconInfo?>> = @@ -97,6 +98,7 @@ constructor( } } .distinctUntilChanged() + .flowOn(bgContext) .pairwise(initialValue = null) .sample(shadeInteractor.shadeExpansion) { (prev, iconInfo), shadeExpansion -> val animate = 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 index 5ab4d4eae929..819527ee1eca 100644 --- 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 @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.shelf.ui.viewbinder +import com.android.app.tracing.traceSection import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.NotificationShelf import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerShelfViewBinder @@ -38,10 +39,12 @@ object NotificationShelfViewBinder { ): Unit = coroutineScope { ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager) shelf.apply { - if (NotificationIconContainerRefactor.isEnabled) { - launch { nicBinder.bind(shelfIcons) } - } else { - notificationIconAreaController.setShelfIcons(shelfIcons) + traceSection("NotifShelf#bindShelfIcons") { + if (NotificationIconContainerRefactor.isEnabled) { + launch { nicBinder.bind(shelfIcons) } + } else { + notificationIconAreaController.setShelfIcons(shelfIcons) + } } launch { viewModel.canModifyColorOfNotifications.collect(::setCanModifyColorOfNotifications) 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 0f640c9c2608..805b44cc0673 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 @@ -4455,9 +4455,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mSectionsManager.setHeaderForegroundColors(onSurface, onSurfaceVariant); - mFooterView.updateColors(); + if (mFooterView != null) { + mFooterView.updateColors(); + } - mEmptyShadeView.setTextColors(onSurface, onSurfaceVariant); + if (mEmptyShadeView != null) { + mEmptyShadeView.setTextColors(onSurface, onSurfaceVariant); + } } void goToFullShade(long delay) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerModule.kt new file mode 100644 index 000000000000..fc3456ad6a23 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerModule.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone + +import com.android.systemui.CoreStartable +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +interface ConfigurationControllerModule { + + /** Starts [ConfigurationControllerStartable] */ + @Binds + @IntoMap + @ClassKey(ConfigurationControllerStartable::class) + fun bindConfigControllerStartable(impl: ConfigurationControllerStartable): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index 600d4afde935..45005cbc28a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -55,11 +55,12 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.util.Assert; +import dagger.Lazy; + import java.util.ArrayList; import javax.inject.Inject; -import dagger.Lazy; import kotlinx.coroutines.ExperimentalCoroutinesApi; /** @@ -175,6 +176,16 @@ public final class DozeServiceHost implements DozeHost { } } + /** + * Notify the registered callback about SPFS fingerprint acquisition started event. + */ + public void fireSideFpsAcquisitionStarted() { + Assert.isMainThread(); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onSideFingerprintAcquisitionStarted(); + } + } + void fireNotificationPulse(NotificationEntry entry) { Runnable pulseSuppressedListener = () -> { if (NotificationIconContainerRefactor.isEnabled()) { 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 af6da3fb6e51..3394eacddbd8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -149,6 +149,14 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh return create(new DialogDelegate<>(){}, mContext); } + /** Creates a new instance of {@link SystemUIDialog} with no customized behavior. + * + * When you just need a dialog created with a specific {@link Context}, call this. + */ + public SystemUIDialog create(Context context) { + return create(new DialogDelegate<>(){}, context); + } + /** * Creates a new instance of {@link SystemUIDialog} with {@code delegate} as the {@link * Delegate}. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index b048da492eb1..942d186e7005 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -16,16 +16,12 @@ package com.android.systemui.statusbar.phone.dagger; -import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.CentralSurfacesImpl; -import com.android.systemui.statusbar.phone.ConfigurationControllerStartable; import dagger.Binds; import dagger.Module; -import dagger.multibindings.ClassKey; -import dagger.multibindings.IntoMap; /** * Dagger Module providing {@link CentralSurfacesImpl}. @@ -38,12 +34,4 @@ public interface StatusBarPhoneModule { @Binds @SysUISingleton CentralSurfaces bindsCentralSurfaces(CentralSurfacesImpl impl); - - /** - * Starts {@link ConfigurationControllerStartable} - */ - @Binds - @IntoMap - @ClassKey(ConfigurationControllerStartable.class) - CoreStartable bindConfigControllerStartable(ConfigurationControllerStartable impl); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index 11456ffaa4f3..617e1076fca3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java @@ -20,6 +20,7 @@ import android.app.Fragment; import android.database.ContentObserver; import android.os.Bundle; import android.os.Parcelable; +import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.telephony.SubscriptionManager; @@ -451,6 +452,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue /** Initializes views related to the notification icon area. */ public void initNotificationIconArea() { + Trace.beginSection("CollapsedStatusBarFragment#initNotifIconArea"); ViewGroup notificationIconArea = mStatusBar.requireViewById(R.id.notification_icon_area); if (NotificationIconContainerRefactor.isEnabled()) { LayoutInflater.from(getContext()) @@ -470,6 +472,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue } updateNotificationIconAreaAndCallChip(/* animate= */ false); + Trace.endSection(); } /** 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 be2c21be816d..f44401ba4702 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 @@ -325,8 +325,13 @@ class MobileConnectionRepositoryImpl( override val cdmaRoaming: StateFlow<Boolean> = telephonyPollingEvent .mapLatest { - val cdmaEri = telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber - cdmaEri == ERI_ON || cdmaEri == ERI_FLASH + try { + val cdmaEri = telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber + cdmaEri == ERI_ON || cdmaEri == ERI_FLASH + } catch (e: UnsupportedOperationException) { + // Handles the same as a function call failure + false + } } .stateIn(scope, SharingStarted.WhileSubscribed(), false) diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java index 8087a8755a6e..550a65c01bfc 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java @@ -48,6 +48,8 @@ import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.util.leak.LeakDetector; +import dagger.Lazy; + import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -87,6 +89,7 @@ public class TunerServiceImpl extends TunerService { // Set of all tunables, used for leak detection. private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null; private final Context mContext; + private final Lazy<SystemUIDialog.Factory> mSystemUIDialogFactoryLazy; private final LeakDetector mLeakDetector; private final DemoModeController mDemoModeController; @@ -104,9 +107,11 @@ public class TunerServiceImpl extends TunerService { @Main Handler mainHandler, LeakDetector leakDetector, DemoModeController demoModeController, - UserTracker userTracker) { + UserTracker userTracker, + Lazy<SystemUIDialog.Factory> systemUIDialogFactoryLazy) { super(context); mContext = context; + mSystemUIDialogFactoryLazy = systemUIDialogFactoryLazy; mContentResolver = mContext.getContentResolver(); mLeakDetector = leakDetector; mDemoModeController = demoModeController; @@ -301,7 +306,7 @@ public class TunerServiceImpl extends TunerService { @Override public void showResetRequest(Runnable onDisabled) { - SystemUIDialog dialog = new SystemUIDialog(mContext); + SystemUIDialog dialog = mSystemUIDialogFactoryLazy.get().create(); dialog.setShowForAllUsers(true); dialog.setMessage(R.string.remove_from_settings_prompt); dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt index 3f76d303898e..8858d132c4be 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt @@ -51,6 +51,7 @@ import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import dagger.Lazy @SmallTest class ActiveUnlockConfigTest : SysuiTestCase() { @@ -60,6 +61,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + @Mock private lateinit var lazyKeyguardUpdateMonitor: Lazy<KeyguardUpdateMonitor> @Mock private lateinit var mockPrintWriter: PrintWriter @Captor private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver> @@ -72,6 +74,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) whenever(selectedUserInteractor.getSelectedUserId()).thenReturn(currentUser) + whenever(lazyKeyguardUpdateMonitor.get()).thenReturn(keyguardUpdateMonitor) secureSettings = FakeSettings() activeUnlockConfig = ActiveUnlockConfig( @@ -79,6 +82,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() { secureSettings, contentResolver, selectedUserInteractor, + lazyKeyguardUpdateMonitor, dumpManager ) } @@ -260,7 +264,6 @@ class ActiveUnlockConfigTest : SysuiTestCase() { updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) // GIVEN fingerprint and face are NOT enrolled - activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor `when`(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(false) `when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(false) @@ -290,7 +293,6 @@ class ActiveUnlockConfigTest : SysuiTestCase() { updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) // GIVEN fingerprint and face are both enrolled - activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor `when`(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(true) `when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(true) diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java index 9ce9bd6865a4..08c1de168439 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java @@ -55,10 +55,10 @@ import android.testing.AndroidTestingRunner; import android.text.TextUtils; import com.android.keyguard.logging.CarrierTextManagerLogger; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.dump.LogBufferHelperKt; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.log.LogBufferHelperKt; +import com.android.systemui.res.R; 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; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index 7f20d9aa9451..51ceda339778 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -37,11 +37,11 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.flags.FakeFeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.res.R; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; @@ -98,7 +98,6 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { .thenReturn(mKeyguardMessageArea); when(mAbsKeyInputView.getResources()).thenReturn(getContext().getResources()); mFeatureFlags = new FakeFeatureFlags(); - mFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, false); mKeyguardAbsKeyInputViewController = createTestObject(); mKeyguardAbsKeyInputViewController.init(); reset(mKeyguardMessageAreaController); // Clear out implicit call to init. @@ -127,7 +126,7 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { @Test public void withFeatureFlagOn_oldMessage_isHidden() { - mFeatureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true); + mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES); KeyguardAbsKeyInputViewController underTest = createTestObject(); underTest.init(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 1ab634c46de9..c5ce856e9785 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -30,6 +30,7 @@ import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING_RESTARTING; +import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_STOPPED; import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT; import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT; import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED; @@ -1973,6 +1974,24 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void detectFingerprint_onSuccess_biometricStateStopped() { + // GIVEN FP detection is running + givenDetectFingerprintWithClearingFingerprintManagerInvocations(); + + // WHEN detection is successful + ArgumentCaptor<FingerprintManager.FingerprintDetectionCallback> fpDetectCallbackCaptor = + ArgumentCaptor.forClass(FingerprintManager.FingerprintDetectionCallback.class); + verify(mFingerprintManager).detectFingerprint( + any(), fpDetectCallbackCaptor.capture(), any()); + fpDetectCallbackCaptor.getValue().onFingerprintDetected(0, 0, true); + mTestableLooper.processAllMessages(); + + // THEN fingerprint detect state should immediately update to STOPPED + assertThat(mKeyguardUpdateMonitor.mFingerprintRunningState) + .isEqualTo(BIOMETRIC_STATE_STOPPED); + } + + @Test public void testFingerprintSensorProperties() throws RemoteException { mFingerprintAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered( new ArrayList<>()); @@ -2283,6 +2302,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { Optional.of(mInteractiveToAuthProvider), mTaskStackChangeListeners, mSelectedUserInteractor, mActivityTaskManager); setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker); + start(); } public boolean hasSimStateJustChanged() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt index 9fe32f1e378b..b45c8948e763 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt @@ -16,16 +16,21 @@ package com.android.keyguard.mediator -import android.os.Handler import android.os.Looper +import android.platform.test.flag.junit.SetFlagsRule +import android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.unfold.FoldAodAnimationController import com.android.systemui.unfold.SysUIUnfoldComponent import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation import com.android.systemui.util.mockito.capture +import com.android.systemui.utils.os.FakeHandler +import com.android.systemui.utils.os.FakeHandler.Mode.QUEUEING import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -52,10 +57,13 @@ class ScreenOnCoordinatorTest : SysuiTestCase() { @Captor private lateinit var readyCaptor: ArgumentCaptor<Runnable> - private val testHandler = Handler(Looper.getMainLooper()) + private val testHandler = FakeHandler(Looper.getMainLooper()).apply { setMode(QUEUEING) } private lateinit var screenOnCoordinator: ScreenOnCoordinator + @get:Rule + val setFlagsRule = SetFlagsRule(DEVICE_DEFAULT) + @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -77,7 +85,7 @@ class ScreenOnCoordinatorTest : SysuiTestCase() { onUnfoldOverlayReady() onFoldAodReady() - waitHandlerIdle(testHandler) + waitHandlerIdle() // Should be called when both unfold overlay and keyguard drawn ready verify(runnable).run() @@ -90,7 +98,7 @@ class ScreenOnCoordinatorTest : SysuiTestCase() { onUnfoldOverlayReady() onFoldAodReady() - waitHandlerIdle(testHandler) + waitHandlerIdle() // Should be called when both unfold overlay and keyguard drawn ready verify(runnable).run() @@ -104,7 +112,8 @@ class ScreenOnCoordinatorTest : SysuiTestCase() { onUnfoldOverlayReady() onFoldAodReady() - waitHandlerIdle(testHandler) + waitHandlerIdle() + // Should not be called because this screen turning on call is not valid anymore verify(runnable, never()).run() @@ -112,13 +121,43 @@ class ScreenOnCoordinatorTest : SysuiTestCase() { @Test fun testUnfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() { + setFlagsRule.disableFlags(Flags.FLAG_ENABLE_BACKGROUND_KEYGUARD_ONDRAWN_CALLBACK) // Recreate with empty unfoldComponent screenOnCoordinator = ScreenOnCoordinator( Optional.empty(), testHandler ) screenOnCoordinator.onScreenTurningOn(runnable) - waitHandlerIdle(testHandler) + waitHandlerIdle() + + // Should be called when only keyguard drawn + verify(runnable).run() + } + @Test + fun testUnfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_usesMainHandler() { + setFlagsRule.disableFlags(Flags.FLAG_ENABLE_BACKGROUND_KEYGUARD_ONDRAWN_CALLBACK) + // Recreate with empty unfoldComponent + screenOnCoordinator = ScreenOnCoordinator( + Optional.empty(), + testHandler + ) + screenOnCoordinator.onScreenTurningOn(runnable) + + // Never called as the main handler didn't schedule it yet. + verify(runnable, never()).run() + } + + @Test + fun unfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_bgCallback_callsDrawnCallback() { + setFlagsRule.enableFlags(Flags.FLAG_ENABLE_BACKGROUND_KEYGUARD_ONDRAWN_CALLBACK) + // Recreate with empty unfoldComponent + screenOnCoordinator = ScreenOnCoordinator( + Optional.empty(), + testHandler + ) + screenOnCoordinator.onScreenTurningOn(runnable) + // No need to wait for the handler to be idle, as it shouldn't be used + // waitHandlerIdle() // Should be called when only keyguard drawn verify(runnable).run() @@ -134,7 +173,7 @@ class ScreenOnCoordinatorTest : SysuiTestCase() { readyCaptor.value.run() } - private fun waitHandlerIdle(handler: Handler) { - handler.runWithScissors({}, /* timeout= */ 0) + private fun waitHandlerIdle() { + testHandler.dispatchQueuedMessages() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt index 2d5c2ab981b6..342494d8997b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt @@ -26,8 +26,8 @@ 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.log.logcatLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index b3eab8a5b79f..c094df5dd569 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -21,7 +21,7 @@ import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.google.common.truth.Truth.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/SystemUIApplicationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/SystemUIApplicationTest.kt new file mode 100644 index 000000000000..202d9ce27a34 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/SystemUIApplicationTest.kt @@ -0,0 +1,180 @@ +/* + * 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.os.Looper +import android.platform.test.flag.junit.SetFlagsRule +import android.testing.TestableLooper.RunWithLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.dagger.GlobalRootComponent +import com.android.systemui.dagger.SysUIComponent +import com.android.systemui.dump.dumpManager +import com.android.systemui.flags.systemPropertiesHelper +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.process.processWrapper +import com.android.systemui.startable.Dependencies +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import javax.inject.Provider +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@RunWith(AndroidJUnit4::class) +@SmallTest +@RunWithLooper +class SystemUIApplicationTest : SysuiTestCase() { + + private val app: SystemUIApplication = SystemUIApplication() + private lateinit var contextAvailableCallback: + SystemUIAppComponentFactoryBase.ContextAvailableCallback + + @get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT) + + val kosmos = Kosmos() + @Mock private lateinit var initializer: SystemUIInitializer + @Mock private lateinit var rootComponent: GlobalRootComponent + @Mock private lateinit var sysuiComponent: SysUIComponent + @Mock private lateinit var bootCompleteCache: BootCompleteCacheImpl + @Mock private lateinit var initController: InitController + + private val startableA = StartableA() + private val startableB = StartableB() + private val startableC = StartableC() + private val startableD = StartableD() + private val startableE = StartableE() + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + app.attachBaseContext(context) + contextAvailableCallback = + SystemUIAppComponentFactoryBase.ContextAvailableCallback { initializer } + whenever(initializer.rootComponent).thenReturn(rootComponent) + whenever(initializer.sysUIComponent).thenReturn(sysuiComponent) + whenever(rootComponent.mainLooper).thenReturn(Looper.myLooper()) + whenever(rootComponent.systemPropertiesHelper).thenReturn(kosmos.systemPropertiesHelper) + whenever(rootComponent.processWrapper).thenReturn(kosmos.processWrapper) + whenever(sysuiComponent.provideBootCacheImpl()).thenReturn(bootCompleteCache) + whenever(sysuiComponent.createDumpManager()).thenReturn(kosmos.dumpManager) + whenever(sysuiComponent.initController).thenReturn(initController) + kosmos.processWrapper.systemUser = true + + app.setContextAvailableCallback(contextAvailableCallback) + } + + @Test + fun testAppOnCreate() { + app.onCreate() + } + + @Test + fun testStartServices_singleService() { + whenever(sysuiComponent.startables) + .thenReturn(mutableMapOf(StartableA::class.java to Provider { startableA })) + app.onCreate() + app.startServicesIfNeeded() + assertThat(startableA.started).isTrue() + } + + @Test + fun testStartServices_twoServices() { + whenever(sysuiComponent.startables) + .thenReturn( + mutableMapOf( + StartableA::class.java to Provider { startableA }, + StartableB::class.java to Provider { startableB } + ) + ) + app.onCreate() + app.startServicesIfNeeded() + assertThat(startableA.started).isTrue() + assertThat(startableB.started).isTrue() + } + + @Test + fun testStartServices_simpleDependency() { + whenever(sysuiComponent.startables) + .thenReturn( + mutableMapOf( + StartableC::class.java to Provider { startableC }, + StartableA::class.java to Provider { startableA }, + StartableB::class.java to Provider { startableB } + ) + ) + app.onCreate() + app.startServicesIfNeeded() + assertThat(startableA.started).isTrue() + assertThat(startableB.started).isTrue() + assertThat(startableC.started).isTrue() + assertThat(startableC.order).isGreaterThan(startableA.order) + } + + @Test + fun testStartServices_complexDependency() { + whenever(sysuiComponent.startables) + .thenReturn( + mutableMapOf( + StartableE::class.java to Provider { startableE }, + StartableC::class.java to Provider { startableC }, + StartableD::class.java to Provider { startableD }, + StartableA::class.java to Provider { startableA }, + StartableB::class.java to Provider { startableB } + ) + ) + app.onCreate() + app.startServicesIfNeeded() + assertThat(startableA.started).isTrue() + assertThat(startableB.started).isTrue() + assertThat(startableC.started).isTrue() + assertThat(startableD.started).isTrue() + assertThat(startableE.started).isTrue() + assertThat(startableC.order).isGreaterThan(startableA.order) + assertThat(startableD.order).isGreaterThan(startableA.order) + assertThat(startableD.order).isGreaterThan(startableB.order) + assertThat(startableE.order).isGreaterThan(startableB.order) + assertThat(startableE.order).isGreaterThan(startableD.order) + } + + open class TestableStartable : CoreStartable { + companion object { + var startOrder = 0 + } + + var started = false + var order = -1 + + override fun start() { + started = true + order = startOrder + startOrder++ + } + } + + class StartableA : TestableStartable() + class StartableB : TestableStartable() + + @Dependencies(StartableA::class) class StartableC : TestableStartable() + + @Dependencies(StartableA::class, StartableB::class) class StartableD : TestableStartable() + + @Dependencies(StartableD::class, StartableB::class) class StartableE : TestableStartable() +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt index bfb5485e47b7..c52571188256 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt @@ -120,7 +120,7 @@ class FontScalingDialogDelegateTest : SysuiTestCase() { fontScalingDialogDelegate ) - whenever(dialogFactory.create(any())).thenReturn(dialog) + whenever(dialogFactory.create(any(), any())).thenReturn(dialog) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt index 4c510ee0b8a6..1f7dd6dd9a9c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -29,7 +29,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.keyguard.logging.KeyguardLogger import com.android.systemui.Flags.FLAG_LIGHT_REVEAL_MIGRATION import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.flags.FeatureFlags import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.plugins.statusbar.StatusBarStateController diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt index 67d3a20bd5c5..8adee8d81ee4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt @@ -36,15 +36,24 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation.ROTATION_90 import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING +import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN +import com.android.systemui.keyguard.shared.model.KeyguardState.OFF +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope import com.android.systemui.log.SideFpsLogger +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.res.R +import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -62,9 +71,10 @@ import org.mockito.junit.MockitoJUnit @SmallTest @RunWith(JUnit4::class) class SideFpsSensorInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() @JvmField @Rule var mockitoRule = MockitoJUnit.rule() - private val testScope = TestScope(StandardTestDispatcher()) + private val testScope = kosmos.testScope private val fingerprintRepository = FakeFingerprintPropertyRepository() @@ -101,6 +111,7 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { windowManager, displayStateInteractor, Optional.of(fingerprintInteractiveToAuthProvider), + kosmos.keyguardTransitionInteractor, SideFpsLogger(logcatLogBuffer("SfpsLogger")) ) } @@ -129,11 +140,62 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { assertThat(isAvailable).isFalse() } + private suspend fun sendTransition(from: KeyguardState, to: KeyguardState) { + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf( + TransitionStep( + from = from, + to = to, + transitionState = TransitionState.STARTED, + ), + TransitionStep( + from = from, + to = to, + transitionState = TransitionState.FINISHED, + value = 1.0f + ) + ), + testScope + ) + } + @Test - fun authenticationDurationIsAvailableWhenSFPSSensorIsAvailable() = + fun authenticationDurationIsLongerIfScreenIsOff() = testScope.runTest { - assertThat(underTest.authenticationDuration) - .isEqualTo(context.resources.getInteger(R.integer.config_restToUnlockDuration)) + val authenticationDuration by collectLastValue(underTest.authenticationDuration) + val longDuration = + context.resources.getInteger(R.integer.config_restToUnlockDurationScreenOff) + sendTransition(LOCKSCREEN, OFF) + + runCurrent() + assertThat(authenticationDuration).isEqualTo(longDuration) + } + + @Test + fun authenticationDurationIsLongerIfScreenIsDozing() = + testScope.runTest { + val authenticationDuration by collectLastValue(underTest.authenticationDuration) + val longDuration = + context.resources.getInteger(R.integer.config_restToUnlockDurationScreenOff) + sendTransition(LOCKSCREEN, DOZING) + runCurrent() + assertThat(authenticationDuration).isEqualTo(longDuration) + } + + @Test + fun authenticationDurationIsShorterIfScreenIsNotDozingOrOff() = + testScope.runTest { + val authenticationDuration by collectLastValue(underTest.authenticationDuration) + val shortDuration = + context.resources.getInteger(R.integer.config_restToUnlockDurationDefault) + val allOtherKeyguardStates = KeyguardState.entries.filter { it != OFF && it != DOZING } + + allOtherKeyguardStates.forEach { destinationState -> + sendTransition(OFF, destinationState) + + runCurrent() + assertThat(authenticationDuration).isEqualTo(shortDuration) + } } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt index 42d2c98f324c..755fa021b07c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt @@ -58,7 +58,6 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.bouncer.ui.BouncerView import com.android.systemui.classifier.FalsingCollector import com.android.systemui.display.data.repository.FakeDisplayRepository -import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository @@ -67,6 +66,7 @@ import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlay import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel import com.android.systemui.log.SideFpsLogger +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR @@ -75,6 +75,7 @@ import com.android.systemui.unfold.compat.ScreenSizeFoldProvider import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import java.util.Optional @@ -82,6 +83,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before @@ -235,15 +237,18 @@ class SideFpsOverlayViewBinderTest : SysuiTestCase() { windowManager, displayStateInteractor, Optional.of(fingerprintInteractiveToAuthProvider), + mock(), SideFpsLogger(logcatLogBuffer("SfpsLogger")) ) sideFpsProgressBarViewModel = SideFpsProgressBarViewModel( mContext, - deviceEntryFingerprintAuthRepository, + mock(), sfpsSensorInteractor, + mock(), displayStateInteractor, + UnconfinedTestDispatcher(), testScope.backgroundScope, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt index 983e4b3a9922..bdca948da6e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt @@ -56,7 +56,6 @@ import com.android.systemui.bouncer.ui.BouncerView import com.android.systemui.classifier.FalsingCollector import com.android.systemui.coroutines.collectLastValue import com.android.systemui.display.data.repository.FakeDisplayRepository -import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository @@ -65,6 +64,7 @@ import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlay import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel import com.android.systemui.log.SideFpsLogger +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR @@ -72,6 +72,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.unfold.compat.ScreenSizeFoldProvider import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat @@ -238,15 +239,18 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { windowManager, displayStateInteractor, Optional.of(fingerprintInteractiveToAuthProvider), + mock(), SideFpsLogger(logcatLogBuffer("SfpsLogger")) ) sideFpsProgressBarViewModel = SideFpsProgressBarViewModel( mContext, - deviceEntryFingerprintAuthRepository, + mock(), sfpsSensorInteractor, + mock(), displayStateInteractor, + StandardTestDispatcher(), testScope.backgroundScope, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java index 4022d4388ab1..3ff43c6a3787 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java @@ -28,8 +28,6 @@ import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.view.LayoutInflater; -import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -95,7 +93,7 @@ public class BroadcastDialogDelegateTest extends SysuiTestCase { mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM, true); when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); - when(mSystemUIDialogFactory.create(any())).thenReturn(mDialog); + when(mSystemUIDialogFactory.create(any(), any())).thenReturn(mDialog); mBroadcastDialogDelegate = new BroadcastDialogDelegate( mContext, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt index aa0d7b621793..45a426e1cb84 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt @@ -25,6 +25,7 @@ import com.android.internal.widget.LockPatternUtils import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.data.repository.FaceSensorInfo import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository @@ -35,8 +36,6 @@ import com.android.systemui.bouncer.shared.model.BouncerMessageModel import com.android.systemui.bouncer.ui.BouncerView import com.android.systemui.classifier.FalsingCollector import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.flags.FakeFeatureFlagsClassic -import com.android.systemui.flags.Flags import com.android.systemui.flags.SystemPropertiesHelper import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository @@ -107,8 +106,7 @@ class BouncerMessageInteractorTest : SysuiTestCase() { suspend fun TestScope.init() { userRepository.setSelectedUserInfo(PRIMARY_USER) - val featureFlags = - FakeFeatureFlagsClassic().apply { set(Flags.REVAMPED_BOUNCER_MESSAGES, true) } + mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES) primaryBouncerInteractor = PrimaryBouncerInteractor( bouncerRepository, @@ -131,7 +129,6 @@ class BouncerMessageInteractorTest : SysuiTestCase() { repository = repository, userRepository = userRepository, countDownTimerUtil = countDownTimerUtil, - featureFlags = featureFlags, updateMonitor = updateMonitor, biometricSettingsRepository = biometricSettingsRepository, applicationScope = this.backgroundScope, diff --git a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt index 65f68f9df3e1..35ac2ae4ed44 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.FeatureFlags import com.android.systemui.model.SysUiState import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.phone.DialogDelegate import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any @@ -69,7 +70,8 @@ class ContrastDialogDelegateTest : SysuiTestCase() { mDependency.injectTestDependency(SysUiState::class.java, sysuiState) mDependency.injectMockDependency(DialogLaunchAnimator::class.java) whenever(sysuiState.setFlag(any(), any())).thenReturn(sysuiState) - whenever(sysuiDialogFactory.create(any())).thenReturn(sysuiDialog) + whenever(sysuiDialogFactory.create(any(SystemUIDialog.Delegate::class.java))) + .thenReturn(sysuiDialog) whenever(sysuiDialog.layoutInflater).thenReturn(LayoutInflater.from(mContext)) whenever(mockUserTracker.userId).thenReturn(context.userId) diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt index 4e8f86615522..7f0ea9a7a6d0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt @@ -17,34 +17,48 @@ package com.android.systemui.controls.management +import android.content.Context import android.content.DialogInterface import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase +import com.android.systemui.res.R import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture -import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mock import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) class PanelConfirmationDialogFactoryTest : SysuiTestCase() { + @Mock private lateinit var mockDialog : SystemUIDialog + @Mock private lateinit var mockDialogFactory : SystemUIDialog.Factory + private lateinit var factory : PanelConfirmationDialogFactory + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + whenever(mockDialogFactory.create(any(Context::class.java))).thenReturn(mockDialog) + whenever(mockDialog.context).thenReturn(mContext) + factory = PanelConfirmationDialogFactory(mockDialogFactory) + } + @Test fun testDialogHasCorrectInfo() { - val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) } - val factory = PanelConfirmationDialogFactory { mockDialog } val appName = "appName" - factory.createConfirmationDialog(context, appName) {} + factory.createConfirmationDialog(mContext, appName) {} verify(mockDialog).setCanceledOnTouchOutside(true) verify(mockDialog) @@ -55,12 +69,9 @@ class PanelConfirmationDialogFactoryTest : SysuiTestCase() { @Test fun testDialogPositiveButton() { - val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) } - val factory = PanelConfirmationDialogFactory { mockDialog } - var response: Boolean? = null - factory.createConfirmationDialog(context, "") { response = it } + factory.createConfirmationDialog(mContext,"") { response = it } val captor: ArgumentCaptor<DialogInterface.OnClickListener> = argumentCaptor() verify(mockDialog).setPositiveButton(eq(R.string.controls_dialog_ok), capture(captor)) @@ -72,12 +83,9 @@ class PanelConfirmationDialogFactoryTest : SysuiTestCase() { @Test fun testDialogNeutralButton() { - val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) } - val factory = PanelConfirmationDialogFactory { mockDialog } - var response: Boolean? = null - factory.createConfirmationDialog(context, "") { response = it } + factory.createConfirmationDialog(mContext, "") { response = it } val captor: ArgumentCaptor<DialogInterface.OnClickListener> = argumentCaptor() verify(mockDialog).setNeutralButton(eq(R.string.cancel), capture(captor)) @@ -89,12 +97,9 @@ class PanelConfirmationDialogFactoryTest : SysuiTestCase() { @Test fun testDialogCancel() { - val mockDialog: SystemUIDialog = mock() { `when`(context).thenReturn(mContext) } - val factory = PanelConfirmationDialogFactory { mockDialog } - var response: Boolean? = null - factory.createConfirmationDialog(context, "") { response = it } + factory.createConfirmationDialog(mContext, "") { response = it } val captor: ArgumentCaptor<DialogInterface.OnCancelListener> = argumentCaptor() verify(mockDialog).setOnCancelListener(capture(captor)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt index 8eebceebe874..38c6a0e236ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt @@ -17,17 +17,23 @@ package com.android.systemui.controls.ui +import android.content.Context import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.res.R import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.FakeSystemUIDialogController +import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.any import org.mockito.Mockito.eq import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) @@ -37,18 +43,24 @@ class ControlsDialogsFactoryTest : SysuiTestCase() { const val APP_NAME = "Test App" } - private val fakeDialogController = FakeSystemUIDialogController() + @Mock + private lateinit var mockDialogFactory : SystemUIDialog.Factory + + private val fakeDialogController = FakeSystemUIDialogController(mContext) private lateinit var underTest: ControlsDialogsFactory @Before fun setup() { - underTest = ControlsDialogsFactory { fakeDialogController.dialog } + MockitoAnnotations.initMocks(this) + whenever(mockDialogFactory.create(any(Context::class.java))) + .thenReturn(fakeDialogController.dialog) + underTest = ControlsDialogsFactory(mockDialogFactory) } @Test fun testCreatesRemoveAppDialog() { - val dialog = underTest.createRemoveAppDialog(context, APP_NAME) {} + val dialog = underTest.createRemoveAppDialog(mContext, APP_NAME) {} verify(dialog) .setTitle( @@ -60,7 +72,7 @@ class ControlsDialogsFactoryTest : SysuiTestCase() { @Test fun testPositiveClickRemoveAppDialogWorks() { var dialogResult: Boolean? = null - underTest.createRemoveAppDialog(context, APP_NAME) { dialogResult = it } + underTest.createRemoveAppDialog(mContext, APP_NAME) { dialogResult = it } fakeDialogController.clickPositive() @@ -70,7 +82,7 @@ class ControlsDialogsFactoryTest : SysuiTestCase() { @Test fun testNeutralClickRemoveAppDialogWorks() { var dialogResult: Boolean? = null - underTest.createRemoveAppDialog(context, APP_NAME) { dialogResult = it } + underTest.createRemoveAppDialog(mContext, APP_NAME) { dialogResult = it } fakeDialogController.clickNeutral() @@ -80,7 +92,7 @@ class ControlsDialogsFactoryTest : SysuiTestCase() { @Test fun testCancelRemoveAppDialogWorks() { var dialogResult: Boolean? = null - underTest.createRemoveAppDialog(context, APP_NAME) { dialogResult = it } + underTest.createRemoveAppDialog(mContext, APP_NAME) { dialogResult = it } fakeDialogController.cancel() diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt index 11bd9cb240a5..36ae0c740c48 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt @@ -51,6 +51,7 @@ import com.android.systemui.flags.FeatureFlags import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSystemUIDialogController import com.android.systemui.util.concurrency.FakeExecutor @@ -97,9 +98,10 @@ class ControlsUiControllerImplTest : SysuiTestCase() { @Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository @Mock lateinit var featureFlags: FeatureFlags @Mock lateinit var packageManager: PackageManager + @Mock lateinit var systemUIDialogFactory: SystemUIDialog.Factory private val preferredPanelRepository = FakeSelectedComponentRepository() - private val fakeDialogController = FakeSystemUIDialogController() + private lateinit var fakeDialogController: FakeSystemUIDialogController private val uiExecutor = FakeExecutor(FakeSystemClock()) private val bgExecutor = FakeExecutor(FakeSystemClock()) @@ -114,6 +116,9 @@ class ControlsUiControllerImplTest : SysuiTestCase() { fun setup() { MockitoAnnotations.initMocks(this) + fakeDialogController = FakeSystemUIDialogController(mContext) + whenever(systemUIDialogFactory.create(any(Context::class.java))) + .thenReturn(fakeDialogController.dialog) controlsSettingsRepository = FakeControlsSettingsRepository() // This way, it won't be cloned every time `LayoutInflater.fromContext` is called, but we @@ -146,10 +151,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { authorizedPanelsRepository, preferredPanelRepository, featureFlags, - ControlsDialogsFactory { - isRemoveAppDialogCreated = true - fakeDialogController.dialog - }, + ControlsDialogsFactory(systemUIDialogFactory), dumpManager, ) `when`(userTracker.userId).thenReturn(0) diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt index 93ce86a2959e..e158e47b3cfa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt @@ -23,7 +23,7 @@ import com.android.systemui.accessibility.data.repository.fakeAccessibilityRepos import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository -import com.android.systemui.deviceentry.data.ui.viewmodel.udfpsAccessibilityOverlayViewModel +import com.android.systemui.deviceentry.data.ui.viewmodel.deviceEntryUdfpsAccessibilityOverlayViewModel import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository @@ -57,7 +57,7 @@ class UdfpsAccessibilityOverlayViewModelTest : SysuiTestCase() { private val deviceEntryFingerprintAuthRepository = kosmos.deviceEntryFingerprintAuthRepository private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository private val shadeRepository = kosmos.fakeShadeRepository - private val underTest = kosmos.udfpsAccessibilityOverlayViewModel + private val underTest = kosmos.deviceEntryUdfpsAccessibilityOverlayViewModel @Test fun visible() = diff --git a/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt index ab6bc2ca2dda..66fdf538e284 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.haptics.slider import android.os.VibrationAttributes import android.os.VibrationEffect import android.view.VelocityTracker -import android.view.animation.AccelerateInterpolator import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -51,8 +50,6 @@ class SliderHapticFeedbackProviderTest : SysuiTestCase() { private val lowTickDuration = 12 // Mocked duration of a low tick private val dragTextureThresholdMillis = lowTickDuration * config.numberOfLowTicks + config.deltaMillisForDragInterval - private val progressInterpolator = AccelerateInterpolator(config.progressInterpolatorFactor) - private val velocityInterpolator = AccelerateInterpolator(config.velocityInterpolatorFactor) private lateinit var sliderHapticFeedbackProvider: SliderHapticFeedbackProvider @Before @@ -60,7 +57,9 @@ class SliderHapticFeedbackProviderTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) whenever(vibratorHelper.getPrimitiveDurations(any())) .thenReturn(intArrayOf(lowTickDuration)) - whenever(velocityTracker.xVelocity).thenReturn(config.maxVelocityToScale) + whenever(velocityTracker.isAxisSupported(config.velocityAxis)).thenReturn(true) + whenever(velocityTracker.getAxisVelocity(config.velocityAxis)) + .thenReturn(config.maxVelocityToScale) sliderHapticFeedbackProvider = SliderHapticFeedbackProvider(vibratorHelper, velocityTracker, config, clock) } 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 index 6eb95bddaf53..769cf45da746 100644 --- 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 @@ -42,7 +42,6 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.bouncer.ui.BouncerView import com.android.systemui.classifier.FalsingCollector import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository @@ -55,6 +54,7 @@ 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.log.logcatLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt index dc0d9c5f987e..070a0ccd1232 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt @@ -17,21 +17,26 @@ package com.android.systemui.keyguard.ui.view.layout.sections +import android.content.pm.PackageManager +import android.content.res.Resources import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.Utils +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.MockitoAnnotations @@ -40,17 +45,10 @@ import org.mockito.MockitoAnnotations class ClockSectionTest : SysuiTestCase() { @Mock private lateinit var keyguardClockInteractor: KeyguardClockInteractor @Mock private lateinit var keyguardClockViewModel: KeyguardClockViewModel - @Mock private lateinit var smartspaceViewModel: KeyguardSmartspaceViewModel @Mock private lateinit var splitShadeStateController: SplitShadeStateController private lateinit var underTest: ClockSection - // smartspaceViewModel.getDimen("date_weather_view_height") - private val SMART_SPACE_DATE_WEATHER_HEIGHT = 10 - - // smartspaceViewModel.getDimen("enhanced_smartspace_height") - private val ENHANCED_SMART_SPACE_HEIGHT = 11 - private val SMALL_CLOCK_TOP_SPLIT_SHADE = context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) @@ -75,15 +73,41 @@ class ClockSectionTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) - whenever(smartspaceViewModel.getDimen("date_weather_view_height")) - .thenReturn(SMART_SPACE_DATE_WEATHER_HEIGHT) - whenever(smartspaceViewModel.getDimen("enhanced_smartspace_height")) - .thenReturn(ENHANCED_SMART_SPACE_HEIGHT) + val remoteResources = mock<Resources>() + whenever( + remoteResources.getIdentifier( + anyString(), + eq("dimen"), + anyString(), + ) + ) + .then { invocation -> + val name = invocation.arguments[0] as String + val index = DIMENSION_BY_IDENTIFIER_NAME.indexOfFirst { (key, _) -> key == name } + if (index == -1) { + error( + "No entry for a dimension named \"$name\", please add it to the list above." + ) + } + index + } + whenever( + remoteResources.getDimensionPixelSize( + anyInt(), + ) + ) + .then { invocation -> + val id = invocation.arguments[0] as Int + DIMENSION_BY_IDENTIFIER_NAME[id].second + } + val packageManager = mock<PackageManager>() + whenever(packageManager.getResourcesForApplication(anyString())).thenReturn(remoteResources) + mContext.setMockPackageManager(packageManager) + underTest = ClockSection( keyguardClockInteractor, keyguardClockViewModel, - smartspaceViewModel, mContext, splitShadeStateController, ) @@ -164,4 +188,14 @@ class ClockSectionTest : SysuiTestCase() { assertThat(smallClockConstraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID) assertThat(smallClockConstraint.layout.topMargin).isEqualTo(expectedSmallClockTopMargin) } + + companion object { + private val SMART_SPACE_DATE_WEATHER_HEIGHT = 10 + private val ENHANCED_SMART_SPACE_HEIGHT = 11 + private val DIMENSION_BY_IDENTIFIER_NAME = + listOf( + "date_weather_view_height" to SMART_SPACE_DATE_WEATHER_HEIGHT, + "enhanced_smartspace_height" to ENHANCED_SMART_SPACE_HEIGHT, + ) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt index 8dd33d5e60bb..1205dceb49e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt @@ -21,11 +21,11 @@ import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest -import com.android.systemui.res.R -import com.android.systemui.SysuiTestCase import com.android.systemui.Flags as AConfigFlags +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.ui.viewmodel.AodAlphaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel +import com.android.systemui.res.R import com.android.systemui.statusbar.KeyguardIndicationController import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -38,8 +38,9 @@ import org.mockito.MockitoAnnotations @RunWith(JUnit4::class) @SmallTest class DefaultIndicationAreaSectionTest : SysuiTestCase() { + @Mock private lateinit var keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel - @Mock private lateinit var keyguardRootViewModel: KeyguardRootViewModel + @Mock private lateinit var aodAlphaViewModel: AodAlphaViewModel @Mock private lateinit var indicationController: KeyguardIndicationController private lateinit var underTest: DefaultIndicationAreaSection @@ -51,7 +52,7 @@ class DefaultIndicationAreaSectionTest : SysuiTestCase() { DefaultIndicationAreaSection( context, keyguardIndicationAreaViewModel, - keyguardRootViewModel, + aodAlphaViewModel, indicationController, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt index 740110b4fee0..28da957d31b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt @@ -29,7 +29,9 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R +import com.android.systemui.shared.R as sharedR import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.StateFlow @@ -50,9 +52,9 @@ class SmartspaceSectionTest : SysuiTestCase() { @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController @Mock private lateinit var hasCustomWeatherDataDisplay: StateFlow<Boolean> - private val smartspaceView = View(mContext).also { it.id = View.generateViewId() } - private val weatherView = View(mContext).also { it.id = View.generateViewId() } - private val dateView = View(mContext).also { it.id = View.generateViewId() } + private val smartspaceView = View(mContext).also { it.id = sharedR.id.bc_smartspace_view } + private val weatherView = View(mContext).also { it.id = sharedR.id.weather_smartspace_view } + private val dateView = View(mContext).also { it.id = sharedR.id.date_smartspace_view } private lateinit var constraintLayout: ConstraintLayout private lateinit var constraintSet: ConstraintSet @@ -69,13 +71,13 @@ class SmartspaceSectionTest : SysuiTestCase() { keyguardUnlockAnimationController, ) constraintLayout = ConstraintLayout(mContext) - whenever(keyguardSmartspaceViewModel.smartspaceView).thenReturn(smartspaceView) - whenever(keyguardSmartspaceViewModel.weatherView).thenReturn(weatherView) - whenever(keyguardSmartspaceViewModel.dateView).thenReturn(dateView) + whenever(lockscreenSmartspaceController.buildAndConnectView(any())) + .thenReturn(smartspaceView) + whenever(lockscreenSmartspaceController.buildAndConnectWeatherView(any())) + .thenReturn(weatherView) + whenever(lockscreenSmartspaceController.buildAndConnectDateView(any())).thenReturn(dateView) whenever(keyguardClockViewModel.hasCustomWeatherDataDisplay) .thenReturn(hasCustomWeatherDataDisplay) - whenever(keyguardSmartspaceViewModel.smartspaceController) - .thenReturn(lockscreenSmartspaceController) constraintSet = ConstraintSet() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt index d4210040faf3..1b4573dafe5e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceConfig import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.shared.clocks.ClockRegistry +import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat @@ -66,6 +67,8 @@ class KeyguardClockViewModelTest : SysuiTestCase() { @Mock private lateinit var largeClock: ClockFaceController @Mock private lateinit var clockFaceConfig: ClockFaceConfig @Mock private lateinit var eventController: ClockEventController + @Mock private lateinit var splitShadeStateController: SplitShadeStateController + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -92,6 +95,7 @@ class KeyguardClockViewModelTest : SysuiTestCase() { keyguardInteractor, keyguardClockInteractor, scope.backgroundScope, + splitShadeStateController, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt deleted file mode 100644 index ee1be10607cf..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ /dev/null @@ -1,498 +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. - * - */ - -@file:OptIn(ExperimentalCoroutinesApi::class) - -package com.android.systemui.keyguard.ui.viewmodel - -import android.view.View -import androidx.test.filters.SmallTest -import com.android.systemui.Flags as AConfigFlags -import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION -import com.android.systemui.SysuiTestCase -import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository -import com.android.systemui.common.ui.domain.interactor.configurationInteractor -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository -import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor -import com.android.systemui.flags.featureFlagsClassic -import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository -import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.BurnInInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor -import com.android.systemui.keyguard.shared.model.BurnInModel -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.kosmos.testScope -import com.android.systemui.plugins.clocks.ClockController -import com.android.systemui.statusbar.notification.data.repository.fakeNotificationsKeyguardViewStateRepository -import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor -import com.android.systemui.statusbar.phone.dozeParameters -import com.android.systemui.statusbar.phone.screenOffAnimationController -import com.android.systemui.testKosmos -import com.android.systemui.util.mockito.whenever -import com.android.systemui.util.ui.isAnimating -import com.android.systemui.util.ui.stopAnimating -import com.android.systemui.util.ui.value -import com.google.common.truth.Truth.assertThat -import javax.inject.Provider -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.emptyFlow -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.junit.runners.JUnit4 -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Mockito.RETURNS_DEEP_STUBS -import org.mockito.Mockito.anyInt -import org.mockito.MockitoAnnotations - -@SmallTest -@RunWith(JUnit4::class) -class KeyguardRootViewModelTest : SysuiTestCase() { - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - private val repository = kosmos.fakeKeyguardRepository - private val configurationRepository = kosmos.fakeConfigurationRepository - private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository - private val screenOffAnimationController = kosmos.screenOffAnimationController - private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository - private val notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor - private val fakeNotificationsKeyguardViewStateRepository = - kosmos.fakeNotificationsKeyguardViewStateRepository - private val dozeParameters = kosmos.dozeParameters - private lateinit var underTest: KeyguardRootViewModel - - @Mock private lateinit var burnInInteractor: BurnInInteractor - private val burnInFlow = MutableStateFlow(BurnInModel()) - - @Mock private lateinit var goneToAodTransitionViewModel: GoneToAodTransitionViewModel - private val enterFromTopAnimationAlpha = MutableStateFlow(0f) - - @Mock - private lateinit var aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel - @Mock - private lateinit var occludedToLockscreenTransitionViewModel: - OccludedToLockscreenTransitionViewModel - private val occludedToLockscreenTranslationY = MutableStateFlow(0f) - private val occludedToLockscreenAlpha = MutableStateFlow(0f) - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var clockController: ClockController - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - - mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR) - mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION) - mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - - whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt())) - .thenReturn(emptyFlow<Float>()) - whenever(goneToAodTransitionViewModel.enterFromTopAnimationAlpha) - .thenReturn(enterFromTopAnimationAlpha) - - whenever(burnInInteractor.keyguardBurnIn).thenReturn(burnInFlow) - - whenever(occludedToLockscreenTransitionViewModel.lockscreenTranslationY) - .thenReturn(occludedToLockscreenTranslationY) - whenever(occludedToLockscreenTransitionViewModel.lockscreenAlpha) - .thenReturn(occludedToLockscreenAlpha) - - underTest = - KeyguardRootViewModel( - configurationInteractor = kosmos.configurationInteractor, - deviceEntryInteractor = kosmos.deviceEntryInteractor, - dozeParameters = kosmos.dozeParameters, - keyguardInteractor = kosmos.keyguardInteractor, - keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor, - notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor, - burnInInteractor = burnInInteractor, - keyguardClockViewModel = kosmos.keyguardClockViewModel, - goneToAodTransitionViewModel = goneToAodTransitionViewModel, - aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel, - occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, - screenOffAnimationController = screenOffAnimationController, - // TODO(b/310989341): remove after change to aconfig - featureFlags = kosmos.featureFlagsClassic - ) - - underTest.clockControllerProvider = Provider { clockController } - } - - @Test - fun alpha() = - testScope.runTest { - val alpha by collectLastValue(underTest.alpha) - - keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.OFF, - to = KeyguardState.LOCKSCREEN, - testScope = testScope, - ) - - repository.setKeyguardAlpha(0.1f) - assertThat(alpha).isEqualTo(0.1f) - repository.setKeyguardAlpha(0.5f) - assertThat(alpha).isEqualTo(0.5f) - repository.setKeyguardAlpha(0.2f) - assertThat(alpha).isEqualTo(0.2f) - repository.setKeyguardAlpha(0f) - assertThat(alpha).isEqualTo(0f) - occludedToLockscreenAlpha.value = 0.8f - assertThat(alpha).isEqualTo(0.8f) - } - - @Test - fun alphaWhenGoneEqualsZero() = - testScope.runTest { - val alpha by collectLastValue(underTest.alpha) - - keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.LOCKSCREEN, - to = KeyguardState.GONE, - testScope = testScope, - ) - - repository.setKeyguardAlpha(0.1f) - assertThat(alpha).isEqualTo(0f) - repository.setKeyguardAlpha(0.5f) - assertThat(alpha).isEqualTo(0f) - repository.setKeyguardAlpha(1f) - assertThat(alpha).isEqualTo(0f) - } - - @Test - fun translationYInitialValueIsZero() = - testScope.runTest { - val translationY by collectLastValue(underTest.translationY) - assertThat(translationY).isEqualTo(0) - } - - @Test - fun translationAndScaleFromBurnInNotDozing() = - testScope.runTest { - val translationX by collectLastValue(underTest.translationX) - val translationY by collectLastValue(underTest.translationY) - val scale by collectLastValue(underTest.scale) - - // Set to not dozing (on lockscreen) - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.AOD, - to = KeyguardState.LOCKSCREEN, - value = 1f, - transitionState = TransitionState.FINISHED - ), - validateStep = false, - ) - - // Trigger a change to the burn-in model - burnInFlow.value = - BurnInModel( - translationX = 20, - translationY = 30, - scale = 0.5f, - ) - - assertThat(translationX).isEqualTo(0) - assertThat(translationY).isEqualTo(0) - assertThat(scale).isEqualTo(Pair(1f, true /* scaleClockOnly */)) - } - - @Test - fun translationAndScaleFromBurnFullyDozing() = - testScope.runTest { - val translationX by collectLastValue(underTest.translationX) - val translationY by collectLastValue(underTest.translationY) - val scale by collectLastValue(underTest.scale) - - underTest.statusViewTop = 100 - - // Set to dozing (on AOD) - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.AOD, - value = 1f, - transitionState = TransitionState.FINISHED - ), - validateStep = false, - ) - // Trigger a change to the burn-in model - burnInFlow.value = - BurnInModel( - translationX = 20, - translationY = 30, - scale = 0.5f, - ) - - assertThat(translationX).isEqualTo(20) - assertThat(translationY).isEqualTo(30) - assertThat(scale).isEqualTo(Pair(0.5f, true /* scaleClockOnly */)) - - // Set to the beginning of GONE->AOD transition - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.AOD, - value = 0f, - transitionState = TransitionState.STARTED - ), - validateStep = false, - ) - assertThat(translationX).isEqualTo(0) - assertThat(translationY).isEqualTo(0) - assertThat(scale).isEqualTo(Pair(1f, true /* scaleClockOnly */)) - } - - @Test - fun translationAndScaleFromBurnFullyDozingStaysOutOfTopInset() = - testScope.runTest { - val translationX by collectLastValue(underTest.translationX) - val translationY by collectLastValue(underTest.translationY) - val scale by collectLastValue(underTest.scale) - - underTest.statusViewTop = 100 - underTest.topInset = 80 - - // Set to dozing (on AOD) - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.AOD, - value = 1f, - transitionState = TransitionState.FINISHED - ), - validateStep = false, - ) - - // Trigger a change to the burn-in model - burnInFlow.value = - BurnInModel( - translationX = 20, - translationY = -30, - scale = 0.5f, - ) - assertThat(translationX).isEqualTo(20) - // -20 instead of -30, due to inset of 80 - assertThat(translationY).isEqualTo(-20) - assertThat(scale).isEqualTo(Pair(0.5f, true /* scaleClockOnly */)) - - // Set to the beginning of GONE->AOD transition - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.AOD, - value = 0f, - transitionState = TransitionState.STARTED - ), - validateStep = false, - ) - assertThat(translationX).isEqualTo(0) - assertThat(translationY).isEqualTo(0) - assertThat(scale).isEqualTo(Pair(1f, true /* scaleClockOnly */)) - } - - @Test - fun translationAndScaleFromBurnInUseScaleOnly() = - testScope.runTest { - whenever(clockController.config.useAlternateSmartspaceAODTransition).thenReturn(true) - - val translationX by collectLastValue(underTest.translationX) - val translationY by collectLastValue(underTest.translationY) - val scale by collectLastValue(underTest.scale) - - // Set to dozing (on AOD) - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.AOD, - value = 1f, - transitionState = TransitionState.FINISHED - ), - validateStep = false, - ) - - // Trigger a change to the burn-in model - burnInFlow.value = - BurnInModel( - translationX = 20, - translationY = 30, - scale = 0.5f, - ) - - assertThat(translationX).isEqualTo(0) - assertThat(translationY).isEqualTo(0) - assertThat(scale).isEqualTo(Pair(0.5f, false /* scaleClockOnly */)) - } - - @Test - fun burnInLayerVisibility() = - testScope.runTest { - val burnInLayerVisibility by collectLastValue(underTest.burnInLayerVisibility) - - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.LOCKSCREEN, - to = KeyguardState.AOD, - value = 0f, - transitionState = TransitionState.STARTED - ), - validateStep = false, - ) - assertThat(burnInLayerVisibility).isEqualTo(View.VISIBLE) - } - - @Test - fun burnInLayerAlpha() = - testScope.runTest { - val burnInLayerAlpha by collectLastValue(underTest.burnInLayerAlpha) - - enterFromTopAnimationAlpha.value = 0.2f - assertThat(burnInLayerAlpha).isEqualTo(0.2f) - - enterFromTopAnimationAlpha.value = 1f - assertThat(burnInLayerAlpha).isEqualTo(1f) - } - - @Test - fun iconContainer_isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - keyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.OFF, - to = KeyguardState.GONE, - testScope, - ) - whenever(screenOffAnimationController.shouldShowAodIconsWhenShade()).thenReturn(false) - runCurrent() - - assertThat(isVisible?.value).isFalse() - assertThat(isVisible?.isAnimating).isFalse() - } - - @Test - fun iconContainer_isVisible_bypassEnabled() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - deviceEntryRepository.setBypassEnabled(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - } - - @Test - fun iconContainer_isNotVisible_pulseExpanding_notBypassing() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(true) - deviceEntryRepository.setBypassEnabled(false) - runCurrent() - - assertThat(isVisible?.value).isEqualTo(false) - } - - @Test - fun iconContainer_isVisible_notifsFullyHidden_bypassEnabled() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(true) - fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isTrue() - } - - @Test - fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParameters.alwaysOn).thenReturn(false) - fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isFalse() - } - - @Test - fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParameters.alwaysOn).thenReturn(true) - whenever(dozeParameters.displayNeedsBlanking).thenReturn(true) - fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isFalse() - } - - @Test - fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParameters.alwaysOn).thenReturn(true) - whenever(dozeParameters.displayNeedsBlanking).thenReturn(false) - fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isTrue() - } - - @Test - fun isIconContainerVisible_stopAnimation() = - testScope.runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParameters.alwaysOn).thenReturn(true) - whenever(dozeParameters.displayNeedsBlanking).thenReturn(false) - fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.isAnimating).isEqualTo(true) - isVisible?.stopAnimating() - runCurrent() - - assertThat(isVisible?.isAnimating).isEqualTo(false) - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java index ce999cb41e60..72847a6b6c45 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java @@ -71,13 +71,13 @@ import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.nearby.NearbyMediaDevicesManager; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.res.R; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; @@ -584,7 +584,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { } @Test - public void addDeviceToPlayMedia_triggersFromLocalMediaManager() { + public void addDeviceToPlayMedia_callsLocalMediaManager() { MediaOutputController testMediaOutputController = new MediaOutputController(mSpyContext, null, mMediaSessionManager, mLocalBluetoothManager, mStarter, @@ -592,16 +592,15 @@ public class MediaOutputControllerTest extends SysuiTestCase { mNearbyMediaDevicesManager, mAudioManager, mPowerExemptionManager, mKeyguardManager, mFlags, mUserTracker); - LocalMediaManager testLocalMediaManager = spy(testMediaOutputController.mLocalMediaManager); - testMediaOutputController.mLocalMediaManager = testLocalMediaManager; + LocalMediaManager mockLocalMediaManager = mock(LocalMediaManager.class); + testMediaOutputController.mLocalMediaManager = mockLocalMediaManager; testMediaOutputController.addDeviceToPlayMedia(mMediaDevice2); - - verify(testLocalMediaManager).addDeviceToPlayMedia(mMediaDevice2); + verify(mockLocalMediaManager).addDeviceToPlayMedia(mMediaDevice2); } @Test - public void removeDeviceFromPlayMedia_triggersFromLocalMediaManager() { + public void removeDeviceFromPlayMedia_callsLocalMediaManager() { MediaOutputController testMediaOutputController = new MediaOutputController(mSpyContext, null, mMediaSessionManager, mLocalBluetoothManager, mStarter, @@ -609,12 +608,11 @@ public class MediaOutputControllerTest extends SysuiTestCase { mNearbyMediaDevicesManager, mAudioManager, mPowerExemptionManager, mKeyguardManager, mFlags, mUserTracker); - LocalMediaManager testLocalMediaManager = spy(testMediaOutputController.mLocalMediaManager); - testMediaOutputController.mLocalMediaManager = testLocalMediaManager; + LocalMediaManager mockLocalMediaManager = mock(LocalMediaManager.class); + testMediaOutputController.mLocalMediaManager = mockLocalMediaManager; testMediaOutputController.removeDeviceFromPlayMedia(mMediaDevice2); - - verify(testLocalMediaManager).removeDeviceFromPlayMedia(mMediaDevice2); + verify(mockLocalMediaManager).removeDeviceFromPlayMedia(mMediaDevice2); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java index 6248bb1009dc..1a303b08b396 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java @@ -55,6 +55,7 @@ import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.util.NotificationChannels; import com.android.systemui.util.settings.FakeGlobalSettings; @@ -77,7 +78,6 @@ public class PowerNotificationWarningsTest extends SysuiTestCase { public static final String FORMATTED_45M = "0h 45m"; public static final String FORMATTED_HOUR = "1h 0m"; private final NotificationManager mMockNotificationManager = mock(NotificationManager.class); - private final GlobalSettings mGlobalSettings = new FakeGlobalSettings(); private PowerNotificationWarnings mPowerNotificationWarnings; @Mock @@ -90,6 +90,10 @@ public class PowerNotificationWarningsTest extends SysuiTestCase { private UserTracker mUserTracker; @Mock private View mView; + @Mock + private SystemUIDialog.Factory mSystemUIDialogFactory; + @Mock + private SystemUIDialog mSystemUIDialog; private BroadcastReceiver mReceiver; @@ -113,9 +117,16 @@ public class PowerNotificationWarningsTest extends SysuiTestCase { when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser()); when(mUserTracker.getUserHandle()).thenReturn( UserHandle.of(ActivityManager.getCurrentUser())); - mPowerNotificationWarnings = new PowerNotificationWarnings(wrapper, starter, - broadcastSender, () -> mBatteryController, mDialogLaunchAnimator, mUiEventLogger, - mGlobalSettings, mUserTracker); + when(mSystemUIDialogFactory.create()).thenReturn(mSystemUIDialog); + mPowerNotificationWarnings = new PowerNotificationWarnings( + wrapper, + starter, + broadcastSender, + () -> mBatteryController, + mDialogLaunchAnimator, + mUiEventLogger, + mUserTracker, + mSystemUIDialogFactory); BatteryStateSnapshot snapshot = new BatteryStateSnapshot(100, false, false, 1, BatteryManager.BATTERY_HEALTH_GOOD, 5, 15); mPowerNotificationWarnings.updateSnapshot(snapshot); @@ -251,7 +262,7 @@ public class PowerNotificationWarningsTest extends SysuiTestCase { verify(mDialogLaunchAnimator, never()).showFromView(any(), any()); - assertThat(mPowerNotificationWarnings.getSaverConfirmationDialog().isShowing()).isTrue(); + verify(mPowerNotificationWarnings.getSaverConfirmationDialog()).show(); mPowerNotificationWarnings.getSaverConfirmationDialog().dismiss(); } @@ -266,7 +277,7 @@ public class PowerNotificationWarningsTest extends SysuiTestCase { verify(mDialogLaunchAnimator, never()).showFromView(any(), any()); - assertThat(mPowerNotificationWarnings.getSaverConfirmationDialog().isShowing()).isTrue(); + verify(mPowerNotificationWarnings.getSaverConfirmationDialog()).show(); mPowerNotificationWarnings.getSaverConfirmationDialog().dismiss(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java index f5a3becc7017..698868d67071 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.IActivityManager; import android.app.IForegroundServiceObserver; @@ -53,6 +54,7 @@ import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -95,6 +97,10 @@ public class FgsManagerControllerTest extends SysuiTestCase { BroadcastDispatcher mBroadcastDispatcher; @Mock DumpManager mDumpManager; + @Mock + SystemUIDialog.Factory mSystemUIDialogFactory; + @Mock + SystemUIDialog mSystemUIDialog; private FgsManagerController mFmc; @@ -114,6 +120,7 @@ public class FgsManagerControllerTest extends SysuiTestCase { mSystemClock = new FakeSystemClock(); mMainExecutor = new FakeExecutor(mSystemClock); mBackgroundExecutor = new FakeExecutor(mSystemClock); + when(mSystemUIDialogFactory.create()).thenReturn(mSystemUIDialog); mUserProfiles = new ArrayList<>(); Mockito.doReturn(mUserProfiles).when(mUserTracker).getUserProfiles(); @@ -325,7 +332,8 @@ public class FgsManagerControllerTest extends SysuiTestCase { mDeviceConfigProxyFake, mDialogLaunchAnimator, mBroadcastDispatcher, - mDumpManager + mDumpManager, + mSystemUIDialogFactory ); fmc.init(); Assert.assertTrue(fmc.getIncludesUserVisibleJobs()); @@ -351,7 +359,8 @@ public class FgsManagerControllerTest extends SysuiTestCase { mDeviceConfigProxyFake, mDialogLaunchAnimator, mBroadcastDispatcher, - mDumpManager + mDumpManager, + mSystemUIDialogFactory ); fmc.init(); Assert.assertFalse(fmc.getIncludesUserVisibleJobs()); @@ -457,7 +466,8 @@ public class FgsManagerControllerTest extends SysuiTestCase { mDeviceConfigProxyFake, mDialogLaunchAnimator, mBroadcastDispatcher, - mDumpManager + mDumpManager, + mSystemUIDialogFactory ); result.init(); 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 51e95be3611b..c109a1e95f66 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 @@ -32,7 +32,9 @@ 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 import com.android.systemui.statusbar.policy.DataSaverController +import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before @@ -49,8 +51,6 @@ class DataSaverTileTest : SysuiTestCase() { @Mock private lateinit var mHost: QSHost @Mock private lateinit var mMetricsLogger: MetricsLogger - @Mock private lateinit var mStatusBarStateController: StatusBarStateController - @Mock private lateinit var mActivityStarter: ActivityStarter @Mock private lateinit var mQsLogger: QSLogger private val falsingManager = FalsingManagerFake() @Mock private lateinit var statusBarStateController: StatusBarStateController @@ -58,6 +58,8 @@ class DataSaverTileTest : SysuiTestCase() { @Mock private lateinit var dataSaverController: DataSaverController @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator @Mock private lateinit var uiEventLogger: QsEventLogger + @Mock private lateinit var systemUIDialogFactory: SystemUIDialog.Factory + @Mock private lateinit var systemUIDialog: SystemUIDialog private lateinit var testableLooper: TestableLooper private lateinit var tile: DataSaverTile @@ -67,7 +69,8 @@ class DataSaverTileTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) - Mockito.`when`(mHost.context).thenReturn(mContext) + whenever(mHost.context).thenReturn(mContext) + whenever(systemUIDialogFactory.create()).thenReturn(systemUIDialog) tile = DataSaverTile( @@ -81,7 +84,8 @@ class DataSaverTileTest : SysuiTestCase() { activityStarter, mQsLogger, dataSaverController, - dialogLaunchAnimator + dialogLaunchAnimator, + systemUIDialogFactory ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt index 0a34810f4d3f..945490f1983d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt @@ -36,6 +36,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -56,6 +57,8 @@ import org.mockito.MockitoAnnotations class UserSwitchDialogControllerTest : SysuiTestCase() { @Mock + private lateinit var dialogFactory: SystemUIDialog.Factory + @Mock private lateinit var dialog: SystemUIDialog @Mock private lateinit var falsingManager: FalsingManager @@ -80,7 +83,8 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) - `when`(dialog.context).thenReturn(mContext) + whenever(dialog.context).thenReturn(mContext) + whenever(dialogFactory.create()).thenReturn(dialog) controller = UserSwitchDialogController( { userDetailViewAdapter }, @@ -88,7 +92,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { falsingManager, dialogLaunchAnimator, uiEventLogger, - { dialog } + dialogFactory ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java index 273ce85f89f5..35bf7753358e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java @@ -18,25 +18,42 @@ package com.android.systemui.reardisplay; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotSame; -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.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.res.Configuration; +import android.content.res.Resources; import android.hardware.devicestate.DeviceStateManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.LayoutInflater; +import android.view.View; import android.widget.TextView; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.res.R; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; +import com.android.systemui.model.SysUiState; +import com.android.systemui.res.R; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.SystemUIDialog; 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.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -45,24 +62,49 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { @Mock private CommandQueue mCommandQueue; + @Mock + private SystemUIDialog.Factory mSystemUIDialogFactory; + @Mock + private SystemUIDialog mSystemUIDialog; + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); + @Mock + private SysUiState mSysUiState; + @Mock + private Resources mResources; - private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); + LayoutInflater mLayoutInflater = LayoutInflater.from(mContext); + private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); private static final int CLOSED_BASE_STATE = 0; private static final int OPEN_BASE_STATE = 1; + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM, true); + when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); + when(mSystemUIDialogFactory.create()).thenReturn(mSystemUIDialog); + when(mSystemUIDialog.getContext()).thenReturn(mContext); + } @Test public void testClosedDialogIsShown() { - RearDisplayDialogController controller = new RearDisplayDialogController(mContext, - mCommandQueue, mFakeExecutor); + RearDisplayDialogController controller = new RearDisplayDialogController( + mCommandQueue, + mFakeExecutor, + mResources, + mLayoutInflater, + mSystemUIDialogFactory); controller.setDeviceStateManagerCallback(new TestDeviceStateManagerCallback()); controller.setFoldedStates(new int[]{0}); controller.setAnimationRepeatCount(0); controller.showRearDisplayDialog(CLOSED_BASE_STATE); - assertTrue(controller.mRearDisplayEducationDialog.isShowing()); - TextView deviceClosedTitleTextView = controller.mRearDisplayEducationDialog.findViewById( + verify(mSystemUIDialog).show(); + + View container = getDialogViewContainer(); + TextView deviceClosedTitleTextView = container.findViewById( R.id.rear_display_title_text_view); assertEquals(deviceClosedTitleTextView.getText().toString(), getContext().getResources().getString( @@ -71,20 +113,28 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { @Test public void testClosedDialogIsRefreshedOnConfigurationChange() { - RearDisplayDialogController controller = new RearDisplayDialogController(mContext, - mCommandQueue, mFakeExecutor); + RearDisplayDialogController controller = new RearDisplayDialogController( + mCommandQueue, + mFakeExecutor, + mResources, + mLayoutInflater, + mSystemUIDialogFactory); controller.setDeviceStateManagerCallback(new TestDeviceStateManagerCallback()); controller.setFoldedStates(new int[]{0}); controller.setAnimationRepeatCount(0); controller.showRearDisplayDialog(CLOSED_BASE_STATE); - assertTrue(controller.mRearDisplayEducationDialog.isShowing()); - TextView deviceClosedTitleTextView = controller.mRearDisplayEducationDialog.findViewById( + verify(mSystemUIDialog).show(); + View container = getDialogViewContainer(); + TextView deviceClosedTitleTextView = container.findViewById( R.id.rear_display_title_text_view); + reset(mSystemUIDialog); + when(mSystemUIDialog.isShowing()).thenReturn(true); + when(mSystemUIDialog.getContext()).thenReturn(mContext); + controller.onConfigChanged(new Configuration()); - assertTrue(controller.mRearDisplayEducationDialog.isShowing()); - TextView deviceClosedTitleTextView2 = controller.mRearDisplayEducationDialog.findViewById( + TextView deviceClosedTitleTextView2 = container.findViewById( R.id.rear_display_title_text_view); assertNotSame(deviceClosedTitleTextView, deviceClosedTitleTextView2); @@ -92,22 +142,33 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { @Test public void testOpenDialogIsShown() { - RearDisplayDialogController controller = new RearDisplayDialogController(mContext, - mCommandQueue, mFakeExecutor); + RearDisplayDialogController controller = new RearDisplayDialogController( + mCommandQueue, + mFakeExecutor, + mResources, + mLayoutInflater, + mSystemUIDialogFactory); controller.setDeviceStateManagerCallback(new TestDeviceStateManagerCallback()); controller.setFoldedStates(new int[]{0}); controller.setAnimationRepeatCount(0); controller.showRearDisplayDialog(OPEN_BASE_STATE); - assertTrue(controller.mRearDisplayEducationDialog.isShowing()); - TextView deviceClosedTitleTextView = controller.mRearDisplayEducationDialog.findViewById( + verify(mSystemUIDialog).show(); + View container = getDialogViewContainer(); + TextView deviceClosedTitleTextView = container.findViewById( R.id.rear_display_title_text_view); assertEquals(deviceClosedTitleTextView.getText().toString(), getContext().getResources().getString( R.string.rear_display_unfolded_bottom_sheet_title)); } + private View getDialogViewContainer() { + ArgumentCaptor<View> viewCaptor = ArgumentCaptor.forClass(View.class); + verify(mSystemUIDialog).setView(viewCaptor.capture()); + + return viewCaptor.getValue(); + } /** * Empty device state manager callbacks, so we can verify that the correct * dialogs are being created regardless of device state of the test device. 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 e572dcca5a34..22207565a7b7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -19,12 +19,10 @@ package com.android.systemui.shade; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static com.android.keyguard.KeyguardClockSwitch.LARGE; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.google.common.truth.Truth.assertThat; -import static kotlinx.coroutines.flow.FlowKt.emptyFlow; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; @@ -39,6 +37,8 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static kotlinx.coroutines.flow.FlowKt.emptyFlow; + import android.annotation.IdRes; import android.content.ContentResolver; import android.content.res.Configuration; @@ -341,7 +341,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock private JavaAdapter mJavaAdapter; @Mock private CastController mCastController; @Mock private SharedNotificationContainerInteractor mSharedNotificationContainerInteractor; - @Mock private ActiveNotificationsInteractor mActiveNotificationsInteractor; + @Mock protected ActiveNotificationsInteractor mActiveNotificationsInteractor; @Mock private KeyguardClockPositionAlgorithm mKeyguardClockPositionAlgorithm; @Mock private NaturalScrollingSettingObserver mNaturalScrollingSettingObserver; 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 28fe8e4e8d3a..3cbb9bb2df97 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -456,11 +456,13 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo enableSplitShade(/* enabled= */ true); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); mNotificationPanelViewController.updateResources(); assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd) .isEqualTo(R.id.qs_edge_guideline); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); mNotificationPanelViewController.updateResources(); assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd) .isEqualTo(ConstraintSet.PARENT_ID); @@ -469,6 +471,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void keyguardStatusView_splitShade_dozing_alwaysDozingOn_isCentered() { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -480,6 +483,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void keyguardStatusView_splitShade_dozing_alwaysDozingOff_isNotCentered() { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -491,6 +495,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void keyguardStatusView_splitShade_notDozing_alwaysDozingOn_isNotCentered() { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -502,6 +507,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void keyguardStatusView_splitShade_pulsing_isNotCentered() { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); when(mNotificationListContainer.hasPulsingNotifications()).thenReturn(true); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -514,6 +520,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void keyguardStatusView_splitShade_notPulsing_isNotCentered() { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); when(mNotificationListContainer.hasPulsingNotifications()).thenReturn(false); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -529,6 +536,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo // The conditions below would make the clock NOT be centered on split shade. // On single shade it should always be centered though. when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); when(mNotificationListContainer.hasPulsingNotifications()).thenReturn(false); mStatusBarStateController.setState(KEYGUARD); setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false); @@ -539,6 +547,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void keyguardStatusView_willPlayDelayedDoze_isCentered_thenNot() { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -553,6 +562,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void keyguardStatusView_willPlayDelayedDoze_notifiesKeyguardMediaController() { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -564,6 +574,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo @Test public void keyguardStatusView_willPlayDelayedDoze_isCentered_thenStillCenteredIfNoNotifs() { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); @@ -700,10 +711,12 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo mStatusBarStateController.setState(KEYGUARD); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); triggerPositionClockAndNotifications(); verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); triggerPositionClockAndNotifications(); verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate */ true); } @@ -715,10 +728,12 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo clearInvocations(mKeyguardStatusViewController); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); triggerPositionClockAndNotifications(); verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); triggerPositionClockAndNotifications(); verify(mKeyguardStatusViewController, times(2)) .displayClock(LARGE, /* animate */ true); @@ -730,6 +745,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo public void testHasNotifications_switchesToLargeClockWhenEnteringSplitShade() { mStatusBarStateController.setState(KEYGUARD); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); enableSplitShade(/* enabled= */ true); @@ -740,6 +756,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo public void testNoNotifications_switchesToLargeClockWhenEnteringSplitShade() { mStatusBarStateController.setState(KEYGUARD); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); enableSplitShade(/* enabled= */ true); @@ -752,6 +769,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo enableSplitShade(/* enabled= */ true); clearInvocations(mKeyguardStatusViewController); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); enableSplitShade(/* enabled= */ false); @@ -764,6 +782,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo enableSplitShade(/* enabled= */ true); clearInvocations(mKeyguardStatusViewController); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); enableSplitShade(/* enabled= */ false); @@ -777,6 +796,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo enableSplitShade(/* enabled= */ true); when(mMediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); clearInvocations(mKeyguardStatusViewController); mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false); @@ -791,6 +811,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo enableSplitShade(/* enabled= */ true); when(mMediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); clearInvocations(mKeyguardStatusViewController); mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false); @@ -847,6 +868,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo clearInvocations(mKeyguardStatusViewController); when(mMediaDataManager.hasActiveMedia()).thenReturn(true); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); mNotificationPanelViewController.setDozing(true, false); @@ -863,6 +885,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo when(mResources.getBoolean(R.bool.force_small_clock_on_lockscreen)).thenReturn(true); when(mMediaDataManager.hasActiveMedia()).thenReturn(false); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); clearInvocations(mKeyguardStatusViewController); enableSplitShade(/* enabled= */ true); @@ -881,6 +904,7 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo when(mResources.getBoolean(R.bool.force_small_clock_on_lockscreen)).thenReturn(true); when(mMediaDataManager.hasActiveMedia()).thenReturn(false); when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); clearInvocations(mKeyguardStatusViewController); enableSplitShade(/* enabled= */ true); @@ -898,11 +922,13 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo // one notification + media player visible when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); triggerPositionClockAndNotifications(); verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate */ true); // only media player visible when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); + when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); triggerPositionClockAndNotifications(); verify(mKeyguardStatusViewController, times(2)).displayClock(SMALL, true); verify(mKeyguardStatusViewController, never()).displayClock(LARGE, /* animate */ true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 86d8d54684ac..c21addc444b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -48,10 +48,9 @@ import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.compose.ComposeFacade.isComposeAvailable import com.android.systemui.dock.DockManager import com.android.systemui.dump.DumpManager -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED -import com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES import com.android.systemui.flags.Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION import com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON import com.android.systemui.flags.Flags.TRACKPAD_GESTURE_FEATURES @@ -67,12 +66,9 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteracto import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler -import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel -import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.log.BouncerLogger -import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler import com.android.systemui.statusbar.DragDownHelper @@ -81,7 +77,6 @@ import com.android.systemui.statusbar.NotificationInsetsController import com.android.systemui.statusbar.NotificationShadeDepthController import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.SysuiStatusBarStateController -import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor import com.android.systemui.statusbar.notification.stack.AmbientState @@ -101,7 +96,6 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat -import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.test.TestScope @@ -116,8 +110,9 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import java.util.Optional +import org.mockito.Mockito.`when` as whenever @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -197,9 +192,9 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { featureFlagsClassic.set(TRACKPAD_GESTURE_COMMON, true) featureFlagsClassic.set(TRACKPAD_GESTURE_FEATURES, false) featureFlagsClassic.set(SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true) - featureFlagsClassic.set(REVAMPED_BOUNCER_MESSAGES, true) featureFlagsClassic.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + mSetFlagsRule.enableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES) testScope = TestScope() fakeClock = FakeSystemClock() @@ -242,7 +237,6 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { repository = BouncerMessageRepositoryImpl(), userRepository = FakeUserRepository(), countDownTimerUtil = mock(CountDownTimerUtil::class.java), - featureFlags = featureFlagsClassic, updateMonitor = mock(KeyguardUpdateMonitor::class.java), biometricSettingsRepository = FakeBiometricSettingsRepository(), applicationScope = testScope.backgroundScope, @@ -278,11 +272,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { alternateBouncerInteractor, mSelectedUserInteractor, { mock (JavaAdapter::class.java )}, - { mock(AlternateBouncerViewModel::class.java) }, - { mock(FalsingManager::class.java) }, - { mock(SwipeUpAnywhereGestureHandler::class.java) }, - { mock(TapGestureDetector::class.java) }, - { mock(AlternateBouncerUdfpsIconViewModel::class.java) }, + { mock(AlternateBouncerDependencies::class.java) }, ) underTest.setupExpandedStatusBar() underTest.setDragDownHelper(dragDownHelper) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index d9ff892145c7..33d60ea9f45c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -28,6 +28,7 @@ import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.LockIconViewController import com.android.keyguard.dagger.KeyguardBouncerComponent +import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl @@ -43,7 +44,6 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.dock.DockManager import com.android.systemui.dump.DumpManager -import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.flags.SystemPropertiesHelper @@ -55,11 +55,10 @@ import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepo import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.FakeTrustRepository import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler -import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel -import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.log.BouncerLogger +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler @@ -69,7 +68,6 @@ import com.android.systemui.statusbar.NotificationInsetsController import com.android.systemui.statusbar.NotificationShadeDepthController import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.SysuiStatusBarStateController -import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor import com.android.systemui.statusbar.notification.stack.AmbientState @@ -189,9 +187,9 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { featureFlags.set(Flags.TRACKPAD_GESTURE_COMMON, true) featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false) featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true) - featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) - mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + mSetFlagsRule.disableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES) testScope = TestScope() controller = NotificationShadeWindowViewController( @@ -232,7 +230,6 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { repository = BouncerMessageRepositoryImpl(), userRepository = FakeUserRepository(), countDownTimerUtil = Mockito.mock(CountDownTimerUtil::class.java), - featureFlags = featureFlags, updateMonitor = Mockito.mock(KeyguardUpdateMonitor::class.java), biometricSettingsRepository = FakeBiometricSettingsRepository(), applicationScope = testScope.backgroundScope, @@ -268,11 +265,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { alternateBouncerInteractor, mSelectedUserInteractor, { Mockito.mock(JavaAdapter::class.java) }, - { Mockito.mock(AlternateBouncerViewModel::class.java) }, - { Mockito.mock(FalsingManager::class.java) }, - { Mockito.mock(SwipeUpAnywhereGestureHandler::class.java) }, - { Mockito.mock(TapGestureDetector::class.java) }, - { Mockito.mock(AlternateBouncerUdfpsIconViewModel::class.java) }, + { Mockito.mock(AlternateBouncerDependencies::class.java) }, ) controller.setupExpandedStatusBar() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java index 76c401547ce9..e1d928272e16 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java @@ -17,7 +17,7 @@ package com.android.systemui.statusbar; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; import static com.google.common.truth.Truth.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index 42c7375bfb2e..757f16cac227 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -19,9 +19,12 @@ package com.android.systemui.statusbar; import static android.app.Notification.VISIBILITY_PRIVATE; import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE; +import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; +import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; +import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS; import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; import static android.os.UserHandle.USER_ALL; import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; @@ -111,7 +114,9 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { @Parameters(name = "{0}") public static List<FlagsParameterization> getParams() { - return FlagsParameterization.allCombinationsOf(FLAG_ALLOW_PRIVATE_PROFILE); + return FlagsParameterization.allCombinationsOf( + FLAG_ALLOW_PRIVATE_PROFILE, + FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS); } public NotificationLockscreenUserManagerTest(FlagsParameterization flags) { @@ -245,6 +250,19 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) + public void testInit() { + when(mKeyguardManager.getPrivateNotificationsAllowed()).thenReturn(false); + mLockscreenUserManager = new TestNotificationLockscreenUserManager(mContext); + mLockscreenUserManager.setUpWithPresenter(mPresenter); + + mBackgroundExecutor.runAllReady(); + + assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif)); + assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif)); + } + + @Test public void testGetCurrentProfiles() { final SparseArray<UserInfo> expectedCurProfiles = new SparseArray<>(); expectedCurProfiles.put(mCurrentUser.id, mCurrentUser); @@ -579,6 +597,40 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) + public void testEarlyUserSwitch() { + mLockscreenUserManager = + new TestNotificationLockscreenUserManager(mContext); + mBackgroundExecutor.runAllReady(); + mLockscreenUserManager.mUserChangedCallback.onUserChanging( + mCurrentUser.id, mContext); + // no crash! + } + + @Test + @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) + public void testKeyguardManager_noPrivateNotifications() { + Mockito.clearInvocations(mDevicePolicyManager); + // User allows notifications + mSettings.putIntForUser(LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, mCurrentUser.id); + changeSetting(LOCK_SCREEN_SHOW_NOTIFICATIONS); + + BroadcastReceiver.PendingResult pr = new BroadcastReceiver.PendingResult( + 0, null, null, 0, true, false, null, mCurrentUser.id, 0); + mLockscreenUserManager.mAllUsersReceiver.setPendingResult(pr); + mLockscreenUserManager.mAllUsersReceiver.onReceive(mContext, + new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) + .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true)); + + assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif)); + // it's a global field, confirm secondary too + assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif)); + assertFalse(mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(mCurrentUser.id)); + assertFalse(mLockscreenUserManager.userAllowsPrivateNotificationsInPublic( + mSecondaryUser.id)); + } + + @Test public void testDevicePolicy_noPrivateNotifications() { Mockito.clearInvocations(mDevicePolicyManager); // User allows notifications @@ -699,6 +751,29 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) + public void testShouldShowLockscreenNotifications_keyguardManagerNoPrivateNotifications_show() { + // KeyguardManager does not allow notifications + when(mKeyguardManager.getPrivateNotificationsAllowed()).thenReturn(false); + // User allows notifications + mSettings.putIntForUser(LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, mCurrentUser.id); + changeSetting(LOCK_SCREEN_SHOW_NOTIFICATIONS); + // DevicePolicy allows notifications + when(mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUser.id)) + .thenReturn(0); + BroadcastReceiver.PendingResult pr = new BroadcastReceiver.PendingResult( + 0, null, null, 0, true, false, null, mCurrentUser.id, 0); + mLockscreenUserManager.mKeyguardReceiver.setPendingResult(pr); + mLockscreenUserManager.mKeyguardReceiver.onReceive(mContext, + new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) + .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false)); + + assertTrue(mLockscreenUserManager.shouldShowLockscreenNotifications()); + assertTrue(mLockscreenUserManager.userAllowsNotificationsInPublic(mCurrentUser.id)); + } + + @Test + @DisableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) public void testShouldShowLockscreenNotifications_keyguardManagerNoPrivateNotifications() { // KeyguardManager does not allow notifications when(mKeyguardManager.getPrivateNotificationsAllowed()).thenReturn(false); @@ -718,6 +793,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { } @Test + @DisableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) public void testUserAllowsNotificationsInPublic_keyguardManagerNoPrivateNotifications() { // DevicePolicy allows notifications when(mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUser.id)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index 560ebc6c3d98..d3850be7c192 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static junit.framework.Assert.assertTrue; 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 40edea2149ce..438b33d9afbc 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 @@ -22,7 +22,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.animation.AnimatorTestRule import com.android.systemui.dump.DumpManager -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeViewController.Companion.WAKEUP_ANIMATION_DELAY_MS import com.android.systemui.statusbar.StatusBarState diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java index 104b751af26b..2cf599a99c63 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java @@ -26,7 +26,7 @@ import static android.service.notification.NotificationListenerService.REASON_CL import static android.service.notification.NotificationStats.DISMISSAL_SHADE; import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN; import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.DISMISSED; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java index 8cf64a5aa8fc..4ff09d3bc6af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.collection; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpTree; import static com.android.systemui.statusbar.notification.collection.ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java index 3dcfcfa2977b..b1180aebe9bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.collection.coalescer; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt index 362da0b5a46c..a652ad64ea8d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt @@ -20,7 +20,7 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt index 4f1581cced91..a8be62b367b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt @@ -21,7 +21,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.NotificationRemoteInputManager import com.android.systemui.statusbar.notification.NotifPipelineFlags import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder 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 2ee016b2c87c..5ff73538b359 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 @@ -24,7 +24,7 @@ import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index 548ecdeb1f47..58eec2e71d32 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import static android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY; import static org.junit.Assert.assertFalse; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt index 069eec22cc34..56f16f32ec15 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt @@ -21,7 +21,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt index 255cf6fbed63..9b4a100a1d64 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifStackC import com.android.systemui.statusbar.notification.collection.render.NotifStats import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.RenderNotificationListInteractor +import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT @@ -80,7 +81,7 @@ class StackCoordinatorTest : SysuiTestCase() { } @Test - @DisableFlags(NotificationIconContainerRefactor.FLAG_NAME) + @DisableFlags(NotificationIconContainerRefactor.FLAG_NAME, FooterViewRefactor.FLAG_NAME) fun testUpdateNotificationIcons() { afterRenderListListener.onAfterRenderList(listOf(entry), stackController) verify(notificationIconAreaController).updateNotificationIcons(eq(listOf(entry))) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt index 0b61a8df4891..22f6bdc54b85 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt @@ -21,7 +21,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.util.mockito.eq diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt index bad56a3413a2..11996fef6255 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification.collection.render import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt index 9a602728f4ba..eeabc744987b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt @@ -22,7 +22,7 @@ import android.view.ViewGroup import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.logcatLogBuffer +import com.android.systemui.log.logcatLogBuffer import org.junit.Assert import org.junit.Before import org.junit.Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java index 04ffab3f3a1c..60eea9beb2e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.interruption; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt index 7c8199eaa0e5..9547af19b36b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt @@ -27,8 +27,8 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.statusbar.IStatusBarService import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FeatureFlags +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.PluginManager import com.android.systemui.plugins.statusbar.StatusBarStateController diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java index cf5b3cda6a18..6faebf6ce335 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.row; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 0cd834ded638..a6bfaa4887eb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -21,7 +21,7 @@ import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking; import static org.junit.Assert.assertEquals; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java index 32f0fe7d136a..76470dbe6d21 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.row; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index 1236fcf7f3d0..88662b60c7d1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.stack; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index e1bd89fa7c34..2b1f5fca8feb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler; import static junit.framework.Assert.assertFalse; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 592c78fe2b81..597e2e34f1d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -20,7 +20,7 @@ import static android.service.notification.NotificationListenerService.REASON_CL import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.google.common.truth.Truth.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java index 4c893e3538a3..6a3b2c3ea55c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.policy; import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler; import static com.google.common.truth.Truth.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java index bfc5bdb70c7e..0581e0ea7b6e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java @@ -18,7 +18,7 @@ package com.android.systemui.toast; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; -import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer; +import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.google.common.truth.Truth.assertThat; @@ -62,10 +62,10 @@ import android.widget.Toast; import androidx.test.filters.SmallTest; import com.android.internal.util.IntPair; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.PluginManager; +import com.android.systemui.res.R; import com.android.systemui.statusbar.CommandQueue; import org.junit.Before; diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt index de310b49b8cc..e24ba265e260 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt @@ -50,7 +50,9 @@ private constructor( @Module interface Bindings { + @Binds @Main fun bindMainContext(dispatcher: TestDispatcher): CoroutineContext @Binds @Main fun bindMainDispatcher(dispatcher: TestDispatcher): CoroutineDispatcher + @Binds @Background fun bindBgContext(dispatcher: TestDispatcher): CoroutineContext @Binds @Background fun bindBgDispatcher(dispatcher: TestDispatcher): CoroutineDispatcher } } 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 29e737eac99b..d23dae9c762c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java @@ -33,6 +33,7 @@ import android.testing.TestWithLooperRule; import android.testing.TestableLooper; import android.util.Log; +import androidx.annotation.NonNull; import androidx.core.animation.AndroidXAnimatorIsolationRule; import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.UiDevice; @@ -68,8 +69,20 @@ public abstract class SysuiTestCase { public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); @Rule - public SysuiTestableContext mContext = new SysuiTestableContext( - InstrumentationRegistry.getContext(), getLeakCheck()); + public SysuiTestableContext mContext = createTestableContext(); + + @NonNull + private SysuiTestableContext createTestableContext() { + SysuiTestableContext context = new SysuiTestableContext( + InstrumentationRegistry.getContext(), getLeakCheck()); + if (isRobolectricTest()) { + // Manually associate a Display to context for Robolectric test. Similar to b/214297409 + return context.createDefaultDisplayContext(); + } else { + return context; + } + } + @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); @@ -84,10 +97,6 @@ public abstract class SysuiTestCase { @Before public void SysuiSetup() throws Exception { - // Manually associate a Display to context for Robolectric test. Similar to b/214297409 - if (isRobolectricTest()) { - mContext = mContext.createDefaultDisplayContext(); - } mSysuiDependency = new SysuiTestDependency(mContext, shouldFailOnLeakedReceiver()); mDependency = mSysuiDependency.install(); mRealInstrumentation = InstrumentationRegistry.getInstrumentation(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt index 848650810582..a6dd3cd7d30a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt @@ -16,6 +16,7 @@ package com.android.systemui.authentication.data.repository +import android.os.UserHandle import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockPatternView import com.android.internal.widget.LockscreenCredential @@ -105,6 +106,13 @@ class FakeAuthenticationRepository( lockoutStartedReportCount++ } + override suspend fun getMaxFailedUnlockAttemptsForWipe(): Int = + MAX_FAILED_AUTH_TRIES_BEFORE_WIPE + + var profileWithMinFailedUnlockAttemptsForWipe: Int = UserHandle.USER_SYSTEM + override suspend fun getProfileWithMinFailedUnlockAttemptsForWipe(): Int = + profileWithMinFailedUnlockAttemptsForWipe + override suspend fun getPinLength(): Int { return (credentialOverride ?: DEFAULT_PIN).size } @@ -169,6 +177,9 @@ class FakeAuthenticationRepository( AuthenticationPatternCoordinate(0, 2), ) const val MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT = 5 + const val MAX_FAILED_AUTH_TRIES_BEFORE_WIPE = + MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT + + LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE const val LOCKOUT_DURATION_SECONDS = 30 const val LOCKOUT_DURATION_MS = LOCKOUT_DURATION_SECONDS * 1000 const val HINTING_PIN_LENGTH = 6 diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt index 05cb059a00cd..7c8a7c8d1c87 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt @@ -19,11 +19,13 @@ package com.android.systemui.authentication.domain.interactor import com.android.systemui.authentication.data.repository.authenticationRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.user.domain.interactor.selectedUserInteractor val Kosmos.authenticationInteractor by Kosmos.Fixture { AuthenticationInteractor( applicationScope = applicationCoroutineScope, repository = authenticationRepository, + selectedUserInteractor = selectedUserInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt index 9175f093c171..cdeade1876a7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt @@ -18,14 +18,16 @@ package com.android.systemui.deviceentry.data.ui.viewmodel import com.android.systemui.accessibility.domain.interactor.accessibilityInteractor import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor -import com.android.systemui.deviceentry.ui.viewmodel.UdfpsAccessibilityOverlayViewModel +import com.android.systemui.deviceentry.ui.viewmodel.DeviceEntryUdfpsAccessibilityOverlayViewModel import com.android.systemui.keyguard.ui.viewmodel.deviceEntryForegroundIconViewModel import com.android.systemui.keyguard.ui.viewmodel.deviceEntryIconViewModel import com.android.systemui.kosmos.Kosmos +import kotlinx.coroutines.ExperimentalCoroutinesApi -val Kosmos.udfpsAccessibilityOverlayViewModel by +@ExperimentalCoroutinesApi +val Kosmos.deviceEntryUdfpsAccessibilityOverlayViewModel by Kosmos.Fixture { - UdfpsAccessibilityOverlayViewModel( + DeviceEntryUdfpsAccessibilityOverlayViewModel( udfpsOverlayInteractor = udfpsOverlayInteractor, accessibilityInteractor = accessibilityInteractor, deviceEntryIconViewModel = deviceEntryIconViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt index b0d941dc6c24..a9d89a37c542 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt @@ -26,7 +26,7 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi -val Kosmos.burnInInteractor by Fixture { +var Kosmos.burnInInteractor by Fixture { BurnInInteractor( context = applicationContext, burnInHelperWrapper = burnInHelperWrapper, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractorKosmos.kt new file mode 100644 index 000000000000..a3955f7634eb --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractorKosmos.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.domain.interactor + +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.keyguardBottomAreaInteractor by Fixture { + KeyguardBottomAreaInteractor( + repository = keyguardRepository, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt new file mode 100644 index 000000000000..6b89e0f8901a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModelKosmos.kt @@ -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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.aodAlphaViewModel by Fixture { + AodAlphaViewModel( + keyguardInteractor = keyguardInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt new file mode 100644 index 000000000000..35cfa89e56ed --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt @@ -0,0 +1,39 @@ +/* + * 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.keyguard.ui.viewmodel + +import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.keyguard.domain.interactor.burnInInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.aodBurnInViewModel by Fixture { + AodBurnInViewModel( + burnInInteractor = burnInInteractor, + configurationInteractor = configurationInteractor, + keyguardInteractor = keyguardInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + goneToAodTransitionViewModel = goneToAodTransitionViewModel, + occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, + keyguardClockViewModel = keyguardClockViewModel, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt index 14e2cff6a7a5..00ece1482236 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt @@ -25,7 +25,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi -val Kosmos.goneToAodTransitionViewModel by Fixture { +var Kosmos.goneToAodTransitionViewModel by Fixture { GoneToAodTransitionViewModel( interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt index d8786830f536..5ca0439c1313 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt @@ -20,6 +20,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.statusbar.policy.splitShadeStateController val Kosmos.keyguardClockViewModel by Kosmos.Fixture { @@ -27,5 +28,6 @@ val Kosmos.keyguardClockViewModel by keyguardInteractor = keyguardInteractor, keyguardClockInteractor = keyguardClockInteractor, applicationScope = applicationCoroutineScope, + splitShadeStateController = splitShadeStateController, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index 13ee74738437..933f50c36b7b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -18,10 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor -import com.android.systemui.flags.FakeFeatureFlagsClassic -import com.android.systemui.keyguard.domain.interactor.burnInInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos @@ -33,18 +30,14 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.keyguardRootViewModel by Fixture { KeyguardRootViewModel( - configurationInteractor = configurationInteractor, deviceEntryInteractor = deviceEntryInteractor, dozeParameters = dozeParameters, keyguardInteractor = keyguardInteractor, keyguardTransitionInteractor = keyguardTransitionInteractor, notificationsKeyguardInteractor = notificationsKeyguardInteractor, - burnInInteractor = burnInInteractor, - goneToAodTransitionViewModel = goneToAodTransitionViewModel, aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel, - occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, screenOffAnimationController = screenOffAnimationController, - keyguardClockViewModel = keyguardClockViewModel, - featureFlags = FakeFeatureFlagsClassic(), + aodBurnInViewModel = aodBurnInViewModel, + aodAlphaViewModel = aodAlphaViewModel, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt index 5bbde2b1c419..93ecb7968ee2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt @@ -26,7 +26,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi -val Kosmos.occludedToLockscreenTransitionViewModel by Fixture { +var Kosmos.occludedToLockscreenTransitionViewModel by Fixture { OccludedToLockscreenTransitionViewModel( interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogBufferHelper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogBufferHelper.kt index 0538227abd3f..45ecb4c2b14f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogBufferHelper.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/log/LogBufferHelper.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,23 +14,18 @@ * limitations under the License. */ -package com.android.systemui.dump +package com.android.systemui.log -import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel -import com.android.systemui.log.LogcatEchoTracker -/** - * Creates a LogBuffer that will echo everything to logcat, which is useful for debugging tests. - */ +/** Creates a LogBuffer that will echo everything to logcat, which is useful for debugging tests. */ @JvmOverloads fun logcatLogBuffer(name: String = "EchoToLogcatLogBuffer") = LogBuffer(name, 50, LogcatEchoTrackerAlways()) -/** - * A [LogcatEchoTracker] that always allows echoing to the logcat. - */ +/** A [LogcatEchoTracker] that always allows echoing to the logcat. */ class LogcatEchoTrackerAlways : LogcatEchoTracker { override fun isBufferLoggable(bufferName: String, level: LogLevel): Boolean = true + override fun isTagLoggable(tagName: String, level: LogLevel): Boolean = true } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/process/ProcessKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/process/ProcessKosmos.kt new file mode 100644 index 000000000000..79167f840f60 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/process/ProcessKosmos.kt @@ -0,0 +1,21 @@ +/* + * 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.process + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.processWrapper: ProcessWrapperFake by Kosmos.Fixture { ProcessWrapperFake() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/process/ProcessWrapperFake.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/process/ProcessWrapperFake.kt new file mode 100644 index 000000000000..9841778f835b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/process/ProcessWrapperFake.kt @@ -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. + */ + +package com.android.systemui.process + +class ProcessWrapperFake : ProcessWrapper() { + + var systemUser: Boolean = false + + override fun isSystemUser(): Boolean { + return systemUser + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt index 25b97b3dab5d..9f71161e4452 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt @@ -17,6 +17,7 @@ package com.android.systemui.scene import android.app.ActivityTaskManager +import android.app.admin.DevicePolicyManager import android.content.Context import android.content.Intent import android.content.pm.UserInfo @@ -96,6 +97,7 @@ import com.android.systemui.user.ui.viewmodel.UserActionViewModel import com.android.systemui.user.ui.viewmodel.UserViewModel import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.time.SystemClock import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf @@ -103,7 +105,6 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.currentTime import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString -import org.mockito.Mockito /** * Utilities for creating scene container framework related repositories, interactors, and @@ -144,18 +145,20 @@ class SceneTestUtils( ) } val telephonyRepository: FakeTelephonyRepository by lazy { FakeTelephonyRepository() } - val bouncerRepository = BouncerRepository(featureFlags) val communalRepository: FakeCommunalRepository by lazy { FakeCommunalRepository() } val keyguardRepository: FakeKeyguardRepository by lazy { FakeKeyguardRepository() } val powerRepository: FakePowerRepository by lazy { FakePowerRepository() } val simBouncerRepository: FakeSimBouncerRepository by lazy { FakeSimBouncerRepository() } - val telephonyManager: TelephonyManager = - Mockito.mock(TelephonyManager::class.java).apply { - whenever(createForSubscriptionId(anyInt())).thenReturn(this) - whenever(supplyIccLockPin(anyString())) - .thenReturn(PinResult(PIN_RESULT_TYPE_SUCCESS, 3)) - } + + val clock: SystemClock = mock { + whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } + } + val telephonyManager: TelephonyManager = mock { + whenever(createForSubscriptionId(anyInt())).thenReturn(this) + whenever(supplyIccLockPin(anyString())).thenReturn(PinResult(PIN_RESULT_TYPE_SUCCESS, 3)) + } + val devicePolicyManager: DevicePolicyManager = mock {} val mobileConnectionsRepository: FakeMobileConnectionsRepository by lazy { FakeMobileConnectionsRepository(mock(), mock()) } @@ -235,6 +238,7 @@ class SceneTestUtils( return AuthenticationInteractor( applicationScope = applicationScope(), repository = repository, + selectedUserInteractor = selectedUserInteractor(), ) } @@ -292,7 +296,7 @@ class SceneTestUtils( fun bouncerViewModel( bouncerInteractor: BouncerInteractor, authenticationInteractor: AuthenticationInteractor, - actionButtonInteractor: BouncerActionButtonInteractor, + actionButtonInteractor: BouncerActionButtonInteractor = bouncerActionButtonInteractor(), users: List<UserViewModel> = createUsers(), ): BouncerViewModel { return BouncerViewModel( @@ -300,14 +304,15 @@ class SceneTestUtils( applicationScope = applicationScope(), mainDispatcher = testDispatcher, bouncerInteractor = bouncerInteractor, + simBouncerInteractor = simBouncerInteractor, authenticationInteractor = authenticationInteractor, flags = sceneContainerFlags, selectedUser = flowOf(users.first { it.isSelectionMarkerVisible }), users = flowOf(users), userSwitcherMenu = flowOf(createMenuActions()), - actionButtonInteractor = actionButtonInteractor, - simBouncerInteractor = simBouncerInteractor, - clock = mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } }, + actionButton = actionButtonInteractor.actionButton, + clock = clock, + devicePolicyManager = devicePolicyManager, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt index 2d2f546a05b4..774782cc019c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt @@ -21,6 +21,7 @@ package com.android.systemui.statusbar.notification.icon.domain.interactor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.statusbar.data.repository.notificationListenerSettingsRepository import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor @@ -30,16 +31,20 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alwaysOnDisplayNotificationIconsInteractor by Fixture { AlwaysOnDisplayNotificationIconsInteractor( + bgContext = testDispatcher, deviceEntryInteractor = deviceEntryInteractor, iconsInteractor = notificationIconsInteractor, ) } + val Kosmos.statusBarNotificationIconsInteractor by Fixture { StatusBarNotificationIconsInteractor( + bgContext = testDispatcher, iconsInteractor = notificationIconsInteractor, settingsRepository = notificationListenerSettingsRepository, ) } + val Kosmos.notificationIconsInteractor by Fixture { NotificationIconsInteractor( activeNotificationsInteractor = activeNotificationsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelKosmos.kt index 6295b83a2bd0..18c063faad0e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelKosmos.kt @@ -20,12 +20,14 @@ import android.content.res.mainResources import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.notification.icon.domain.interactor.alwaysOnDisplayNotificationIconsInteractor val Kosmos.notificationIconContainerAlwaysOnDisplayViewModel by Kosmos.Fixture { NotificationIconContainerAlwaysOnDisplayViewModel( + bgContext = testDispatcher, iconsInteractor = alwaysOnDisplayNotificationIconsInteractor, keyguardInteractor = keyguardInteractor, keyguardTransitionInteractor = keyguardTransitionInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModelKosmos.kt index d679bb696ce6..4492af590d84 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModelKosmos.kt @@ -17,11 +17,13 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.statusbar.notification.icon.domain.interactor.notificationIconsInteractor val Kosmos.notificationIconContainerShelfViewModel by Kosmos.Fixture { NotificationIconContainerShelfViewModel( + bgContext = testDispatcher, interactor = notificationIconsInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelKosmos.kt index 04bb52d101db..3632a3deed29 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelKosmos.kt @@ -19,8 +19,8 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel import android.content.res.mainResources import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor import com.android.systemui.statusbar.notification.icon.domain.interactor.statusBarNotificationIconsInteractor import com.android.systemui.statusbar.phone.domain.interactor.darkIconInteractor @@ -28,11 +28,11 @@ import com.android.systemui.statusbar.phone.domain.interactor.darkIconInteractor val Kosmos.notificationIconContainerStatusBarViewModel by Kosmos.Fixture { NotificationIconContainerStatusBarViewModel( + bgContext = testDispatcher, darkIconInteractor = darkIconInteractor, iconsInteractor = statusBarNotificationIconsInteractor, headsUpIconInteractor = headsUpNotificationIconInteractor, keyguardInteractor = keyguardInteractor, - notificationsInteractor = activeNotificationsInteractor, resources = mainResources, shadeInteractor = shadeInteractor, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSystemUIDialogController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSystemUIDialogController.kt index 0c9ce0f145f1..697b5087a865 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSystemUIDialogController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSystemUIDialogController.kt @@ -17,6 +17,7 @@ package com.android.systemui.util +import android.content.Context import android.content.DialogInterface import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.mockito.any @@ -27,13 +28,15 @@ import org.mockito.Mockito.doAnswer import org.mockito.Mockito.verify import org.mockito.stubbing.Stubber -class FakeSystemUIDialogController { +class FakeSystemUIDialogController(context: Context) { val dialog: SystemUIDialog = mock() + private val clickListeners: MutableMap<Int, DialogInterface.OnClickListener> = mutableMapOf() init { + whenever(dialog.context).thenReturn(context) saveListener(DialogInterface.BUTTON_POSITIVE) .whenever(dialog) .setPositiveButton(any(), any()) 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 843cc3b78031..54d805409c51 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 @@ -41,8 +41,6 @@ class UnfoldRemoteFilter( if (inProgress) { logCounter({ "$TAG#filtered_progress" }, newProgress) listener.onTransitionProgress(newProgress) - } else { - Log.e(TAG, "Filtered progress received received while animation not in progress.") } field = newProgress } diff --git a/packages/overlays/Android.bp b/packages/overlays/Android.bp new file mode 100644 index 000000000000..5e001fba6aa1 --- /dev/null +++ b/packages/overlays/Android.bp @@ -0,0 +1,44 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "frameworks_base_license", + ], +} + +phony { + name: "frameworks-base-overlays", + required: [ + "DisplayCutoutEmulationCornerOverlay", + "DisplayCutoutEmulationDoubleOverlay", + "DisplayCutoutEmulationHoleOverlay", + "DisplayCutoutEmulationTallOverlay", + "DisplayCutoutEmulationWaterfallOverlay", + "FontNotoSerifSourceOverlay", + "NavigationBarMode3ButtonOverlay", + "NavigationBarModeGesturalOverlay", + "NavigationBarModeGesturalOverlayNarrowBack", + "NavigationBarModeGesturalOverlayWideBack", + "NavigationBarModeGesturalOverlayExtraWideBack", + "TransparentNavigationBarOverlay", + "NotesRoleEnabledOverlay", + "preinstalled-packages-platform-overlays.xml", + ], +} + +phony { + name: "frameworks-base-overlays-debug", +} diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk deleted file mode 100644 index a41d0e57cd21..000000000000 --- a/packages/overlays/Android.mk +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) 2019 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := frameworks-base-overlays -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_REQUIRED_MODULES := \ - DisplayCutoutEmulationCornerOverlay \ - DisplayCutoutEmulationDoubleOverlay \ - DisplayCutoutEmulationHoleOverlay \ - DisplayCutoutEmulationTallOverlay \ - DisplayCutoutEmulationWaterfallOverlay \ - FontNotoSerifSourceOverlay \ - NavigationBarMode3ButtonOverlay \ - NavigationBarModeGesturalOverlay \ - NavigationBarModeGesturalOverlayNarrowBack \ - NavigationBarModeGesturalOverlayWideBack \ - NavigationBarModeGesturalOverlayExtraWideBack \ - TransparentNavigationBarOverlay \ - NotesRoleEnabledOverlay \ - preinstalled-packages-platform-overlays.xml - -include $(BUILD_PHONY_PACKAGE) -include $(CLEAR_VARS) - -LOCAL_MODULE := frameworks-base-overlays-debug -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE - -include $(BUILD_PHONY_PACKAGE) -include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig index a19920f4fc02..993b2544f110 100644 --- a/services/accessibility/accessibility.aconfig +++ b/services/accessibility/accessibility.aconfig @@ -59,13 +59,6 @@ flag { } flag { - name: "reduce_touch_exploration_sensitivity" - namespace: "accessibility" - description: "Reduces touch exploration sensitivity by only sending a hover event when the ifnger has moved the amount of pixels defined by the system's touch slop." - bug: "303677860" -} - -flag { name: "scan_packages_without_lock" namespace: "accessibility" description: "Scans packages for accessibility service/activity info without holding the A11yMS lock" diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index fc8d4f89e6a7..c4184854e690 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -882,22 +882,10 @@ public class TouchExplorer extends BaseEventStreamTransformation final int pointerIndex = event.findPointerIndex(pointerId); switch (event.getPointerCount()) { case 1: - // Touch exploration. + // Touch exploration. sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags); - if (Flags.reduceTouchExplorationSensitivity() - && mState.getLastInjectedHoverEvent() != null) { - final MotionEvent lastEvent = mState.getLastInjectedHoverEvent(); - final float deltaX = lastEvent.getX() - rawEvent.getX(); - final float deltaY = lastEvent.getY() - rawEvent.getY(); - final double moveDelta = Math.hypot(deltaX, deltaY); - if (moveDelta > mTouchSlop) { - mDispatcher.sendMotionEvent( - event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags); - } - } else { - mDispatcher.sendMotionEvent( - event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags); - } + mDispatcher.sendMotionEvent( + event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags); break; case 2: if (mGestureDetector.isMultiFingerGesturesEnabled() diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index 4688658bf1c3..6d0915bf7d92 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -38,6 +38,7 @@ import android.service.autofill.ISaveCallback; import android.service.autofill.SaveRequest; import android.text.format.DateUtils; import android.util.Slog; +import android.view.autofill.IAutoFillManagerClient; import com.android.internal.infra.AbstractRemoteService; import com.android.internal.infra.ServiceConnector; @@ -56,12 +57,22 @@ final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> { private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; + private static final ComponentName CREDMAN_SERVICE_COMPONENT_NAME = + new ComponentName("com.android.credentialmanager", + "com.android.credentialmanager.autofill.CredentialAutofillService"); + private final FillServiceCallbacks mCallbacks; private final Object mLock = new Object(); private CompletableFuture<FillResponse> mPendingFillRequest; private int mPendingFillRequestId = INVALID_REQUEST_ID; private final ComponentName mComponentName; + private final boolean mIsCredentialAutofillService; + + public boolean isCredentialAutofillService() { + return mIsCredentialAutofillService; + } + public interface FillServiceCallbacks extends AbstractRemoteService.VultureCallback<RemoteFillService> { void onFillRequestSuccess(int requestId, @Nullable FillResponse response, @@ -83,6 +94,7 @@ final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> { userId, IAutoFillService.Stub::asInterface); mCallbacks = callbacks; mComponentName = componentName; + mIsCredentialAutofillService = mComponentName.equals(CREDMAN_SERVICE_COMPONENT_NAME); } @Override // from ServiceConnector.Impl @@ -117,6 +129,10 @@ final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> { super.addLast(iAutoFillServiceJob); } + public ComponentName getComponentName() { + return mComponentName; + } + /** * Cancel the currently pending request. * @@ -134,6 +150,78 @@ final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> { } } + public void onFillCredentialRequest(@NonNull FillRequest request, + IAutoFillManagerClient autofillCallback) { + if (sVerbose) { + Slog.v(TAG, "onFillRequest:" + request); + } + AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); + AtomicReference<CompletableFuture<FillResponse>> futureRef = new AtomicReference<>(); + + CompletableFuture<FillResponse> connectThenFillRequest = postAsync(remoteService -> { + if (sVerbose) { + Slog.v(TAG, "calling onFillRequest() for id=" + request.getId()); + } + + CompletableFuture<FillResponse> fillRequest = new CompletableFuture<>(); + remoteService.onFillCredentialRequest(request, new IFillCallback.Stub() { + @Override + public void onCancellable(ICancellationSignal cancellation) { + CompletableFuture<FillResponse> future = futureRef.get(); + if (future != null && future.isCancelled()) { + dispatchCancellationSignal(cancellation); + } else { + cancellationSink.set(cancellation); + } + } + + @Override + public void onSuccess(FillResponse response) { + fillRequest.complete(response); + } + + @Override + public void onFailure(int requestId, CharSequence message) { + String errorMessage = message == null ? "" : String.valueOf(message); + fillRequest.completeExceptionally( + new RuntimeException(errorMessage)); + } + }, autofillCallback); + return fillRequest; + }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS); + futureRef.set(connectThenFillRequest); + + synchronized (mLock) { + mPendingFillRequest = connectThenFillRequest; + mPendingFillRequestId = request.getId(); + } + + connectThenFillRequest.whenComplete((res, err) -> Handler.getMain().post(() -> { + synchronized (mLock) { + mPendingFillRequest = null; + mPendingFillRequestId = INVALID_REQUEST_ID; + } + if (mCallbacks == null) { + Slog.w(TAG, "Error calling RemoteFillService - service already unbound"); + return; + } + if (err == null) { + mCallbacks.onFillRequestSuccess(request.getId(), res, + mComponentName.getPackageName(), request.getFlags()); + } else { + Slog.e(TAG, "Error calling on fill request", err); + if (err instanceof TimeoutException) { + dispatchCancellationSignal(cancellationSink.get()); + mCallbacks.onFillRequestTimeout(request.getId()); + } else if (err instanceof CancellationException) { + dispatchCancellationSignal(cancellationSink.get()); + } else { + mCallbacks.onFillRequestFailure(request.getId(), err.getMessage()); + } + } + })); + } + public void onFillRequest(@NonNull FillRequest request) { if (sVerbose) { Slog.v(TAG, "onFillRequest:" + request); diff --git a/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java index 4a6d5c9bc65e..553ba124402c 100644 --- a/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java +++ b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java @@ -16,14 +16,19 @@ package com.android.server.autofill; +import static com.android.server.autofill.Session.SESSION_ID_KEY; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; +import android.os.Bundle; import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; import android.util.Slog; +import android.view.autofill.IAutoFillManagerClient; +import android.view.inputmethod.InlineSuggestionsRequest; /** * Requests autofill response from a Remote Autofill Service. This autofill service can be @@ -95,10 +100,33 @@ final class SecondaryProviderHandler implements RemoteFillService.FillServiceCal /** * Requests a new fill response. */ - public void onFillRequest(FillRequest pendingFillRequest, int flag) { + public void onFillRequest(FillRequest pendingFillRequest, + InlineSuggestionsRequest pendingInlineSuggestionsRequest, int flag, int id, + IAutoFillManagerClient client) { Slog.v(TAG, "Requesting fill response to secondary provider."); mLastFlag = flag; - mRemoteFillService.onFillRequest(pendingFillRequest); + if (mRemoteFillService != null && mRemoteFillService.isCredentialAutofillService()) { + Slog.v(TAG, "About to call CredAutofill service as secondary provider"); + addSessionIdToClientState(pendingFillRequest, pendingInlineSuggestionsRequest, id); + mRemoteFillService.onFillCredentialRequest(pendingFillRequest, client); + } else { + mRemoteFillService.onFillRequest(pendingFillRequest); + } + } + + private FillRequest addSessionIdToClientState(FillRequest pendingFillRequest, + InlineSuggestionsRequest pendingInlineSuggestionsRequest, int id) { + if (pendingFillRequest.getClientState() == null) { + pendingFillRequest = new FillRequest(pendingFillRequest.getId(), + pendingFillRequest.getFillContexts(), + pendingFillRequest.getHints(), + new Bundle(), + pendingFillRequest.getFlags(), + pendingInlineSuggestionsRequest, + pendingFillRequest.getDelayedFillIntentSender()); + } + pendingFillRequest.getClientState().putInt(SESSION_ID_KEY, id); + return pendingFillRequest; } public void destroy() { diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index c4e8f12b72f5..a49f9dbe7d91 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -141,6 +141,7 @@ import android.service.autofill.FillEventHistory.Event; import android.service.autofill.FillEventHistory.Event.NoSaveReason; import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; +import android.service.autofill.Flags; import android.service.autofill.InlinePresentation; import android.service.autofill.InternalSanitizer; import android.service.autofill.InternalValidator; @@ -233,6 +234,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState new ComponentName("com.android.credentialmanager", "com.android.credentialmanager.autofill.CredentialAutofillService"); + static final String SESSION_ID_KEY = "session_id"; + final Object mLock; private final AutofillManagerServiceImpl mService; @@ -382,7 +385,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ private boolean mHasCallback; - /** Whether the session has credential provider as the primary provider. */ + /** Whether the session has credential manager provider as the primary provider. */ private boolean mIsPrimaryCredential; @GuardedBy("mLock") @@ -579,6 +582,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private AutofillId[] mLastFillDialogTriggerIds; + private boolean mIgnoreViewStateResetToEmpty; + void onSwitchInputMethodLocked() { // One caveat is that for the case where the focus is on a field for which regular autofill // returns null, and augmented autofill is triggered, and then the user switches the input @@ -720,9 +725,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState && mSecondaryProviderHandler != null) { Slog.v(TAG, "Requesting fill response to secondary provider."); mSecondaryProviderHandler.onFillRequest(mPendingFillRequest, - mPendingFillRequest.getFlags()); + mPendingInlineSuggestionsRequest, + mPendingFillRequest.getFlags(), id, mClient); } else if (mRemoteFillService != null) { - mRemoteFillService.onFillRequest(mPendingFillRequest); + if (mIsPrimaryCredential) { + mPendingFillRequest = addSessionIdToClientState(mPendingFillRequest, + mPendingInlineSuggestionsRequest, id); + mRemoteFillService.onFillCredentialRequest(mPendingFillRequest, mClient); + } else { + mRemoteFillService.onFillRequest(mPendingFillRequest); + } } mPendingInlineSuggestionsRequest = null; mWaitForInlineRequest = false; @@ -865,6 +877,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } + private FillRequest addSessionIdToClientState(FillRequest pendingFillRequest, + InlineSuggestionsRequest pendingInlineSuggestionsRequest, int id) { + if (pendingFillRequest.getClientState() == null) { + pendingFillRequest = new FillRequest(pendingFillRequest.getId(), + pendingFillRequest.getFillContexts(), + pendingFillRequest.getHints(), + new Bundle(), + pendingFillRequest.getFlags(), + pendingInlineSuggestionsRequest, + pendingFillRequest.getDelayedFillIntentSender()); + } + pendingFillRequest.getClientState().putInt(SESSION_ID_KEY, id); + return pendingFillRequest; + } + /** * Get the list of valid autofill hint types from Device flags * Returns empty list if PCC is off or no types available @@ -1441,6 +1468,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mSessionCommittedEventLogger.maybeSetComponentPackageUid(uid); mSaveEventLogger = SaveEventLogger.forSessionId(sessionId); mIsPrimaryCredential = isPrimaryCredential; + mIgnoreViewStateResetToEmpty = Flags.ignoreViewStateResetToEmpty(); synchronized (mLock) { mSessionFlags = new SessionFlags(); @@ -4419,6 +4447,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private void updateViewStateAndUiOnValueChangedLocked(AutofillId id, AutofillValue value, ViewState viewState, int flags) { + if (mIgnoreViewStateResetToEmpty && (value == null || value.isEmpty()) + && viewState.getCurrentValue() != null && viewState.getCurrentValue().isText() + && viewState.getCurrentValue().getTextValue() != null + && viewState.getCurrentValue().getTextValue().length() > 1) { + if (sVerbose) { + Slog.v(TAG, "Ignoring view state reset to empty on id " + id); + } + return; + } final String textValue; if (value == null || !value.isText()) { textValue = null; diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java index 69647633eaff..a6ed8464128a 100644 --- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java +++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java @@ -37,6 +37,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UserIdInt; +import android.app.ActivityOptions; import android.app.PendingIntent; import android.companion.AssociatedDevice; import android.companion.AssociationInfo; @@ -285,32 +286,33 @@ class AssociationRequestsProcessor { selfManaged, /* notifyOnDeviceNearby */ false, /* revoked */ false, timestamp, Long.MAX_VALUE, /* systemDataSyncFlags */ 0); - if (deviceProfile != null) { - // If the "Device Profile" is specified, make the companion application a holder of the - // corresponding role. - addRoleHolderForAssociation(mService.getContext(), association, success -> { - if (success) { - addAssociationToStore(association, deviceProfile); - - sendCallbackAndFinish(association, callback, resultReceiver); - } else { - Slog.e(TAG, "Failed to add u" + userId + "\\" + packageName - + " to the list of " + deviceProfile + " holders."); - - sendCallbackAndFinish(null, callback, resultReceiver); - } - }); - } else { - addAssociationToStore(association, null); - - sendCallbackAndFinish(association, callback, resultReceiver); - } + // Add role holder for association (if specified) and add new association to store. + maybeGrantRoleAndStoreAssociation(association, callback, resultReceiver); // Don't need to update the mRevokedAssociationsPendingRoleHolderRemoval since // maybeRemoveRoleHolderForAssociation in PackageInactivityListener will handle the case // that there are other devices with the same profile, so the role holder won't be removed. } + public void maybeGrantRoleAndStoreAssociation(@NonNull AssociationInfo association, + @Nullable IAssociationRequestCallback callback, + @Nullable ResultReceiver resultReceiver) { + // If the "Device Profile" is specified, make the companion application a holder of the + // corresponding role. + // If it is null, then the operation will succeed without granting any role. + addRoleHolderForAssociation(mService.getContext(), association, success -> { + if (success) { + addAssociationToStore(association); + sendCallbackAndFinish(association, callback, resultReceiver); + } else { + Slog.e(TAG, "Failed to add u" + association.getUserId() + + "\\" + association.getPackageName() + + " to the list of " + association.getDeviceProfile() + " holders."); + sendCallbackAndFinish(null, callback, resultReceiver); + } + }); + } + public void enableSystemDataSync(int associationId, int flags) { AssociationInfo association = mAssociationStore.getAssociationById(associationId); AssociationInfo updated = (new AssociationInfo.Builder(association)) @@ -325,15 +327,14 @@ class AssociationRequestsProcessor { mAssociationStore.updateAssociation(updated); } - private void addAssociationToStore(@NonNull AssociationInfo association, - @Nullable String deviceProfile) { + private void addAssociationToStore(@NonNull AssociationInfo association) { Slog.i(TAG, "New CDM association created=" + association); mAssociationStore.addAssociation(association); mService.updateSpecialAccessPermissionForAssociatedPackage(association); - logCreateAssociation(deviceProfile); + logCreateAssociation(association.getDeviceProfile()); } private void sendCallbackAndFinish(@Nullable AssociationInfo association, @@ -398,7 +399,11 @@ class AssociationRequestsProcessor { pendingIntent = PendingIntent.getActivityAsUser( mContext, /*requestCode */ packageUid, intent, FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE, - /* options= */ null, UserHandle.CURRENT); + ActivityOptions.makeBasic() + .setPendingIntentCreatorBackgroundActivityStartMode( + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED) + .toBundle(), + UserHandle.CURRENT); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/companion/java/com/android/server/companion/RolesUtils.java b/services/companion/java/com/android/server/companion/RolesUtils.java index 163f614fb65d..af9d2d783100 100644 --- a/services/companion/java/com/android/server/companion/RolesUtils.java +++ b/services/companion/java/com/android/server/companion/RolesUtils.java @@ -47,6 +47,17 @@ final class RolesUtils { return roleHolders.contains(packageName); } + /** + * Attempt to add the association's companion app as the role holder for the device profile + * specified in the association. If the association does not have any device profile specified, + * then the operation will always be successful as a no-op. + * + * @param context + * @param associationInfo the association for which the role should be granted to the app + * @param roleGrantResult the result callback for adding role holder. True if successful, and + * false if failed. If the association does not have any device profile + * specified, then the operation will always be successful as a no-op. + */ static void addRoleHolderForAssociation( @NonNull Context context, @NonNull AssociationInfo associationInfo, @NonNull Consumer<Boolean> roleGrantResult) { @@ -55,7 +66,11 @@ final class RolesUtils { } final String deviceProfile = associationInfo.getDeviceProfile(); - if (deviceProfile == null) return; + if (deviceProfile == null) { + // If no device profile is specified, then no-op and resolve callback with success. + roleGrantResult.accept(true); + return; + } final RoleManager roleManager = context.getSystemService(RoleManager.class); diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java index bd646fa6bfbc..4e471f5b0bc9 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java @@ -27,6 +27,7 @@ import static com.android.server.companion.Utils.prepareForIpc; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.ActivityOptions; import android.app.PendingIntent; import android.companion.AssociationInfo; import android.companion.DeviceNotAssociatedException; @@ -186,7 +187,11 @@ public class SystemDataTransferProcessor { final long token = Binder.clearCallingIdentity(); try { return PendingIntent.getActivityAsUser(mContext, /*requestCode */ associationId, intent, - FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE, /* options= */ null, + FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE, + ActivityOptions.makeBasic() + .setPendingIntentCreatorBackgroundActivityStartMode( + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED) + .toBundle(), UserHandle.CURRENT); } finally { Binder.restoreCallingIdentity(token); diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index 8c728f1eeffd..31766f2ec4eb 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -288,16 +288,15 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } final UserHandle activityUser = UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid); - if (!mAllowedUsers.contains(activityUser)) { - Slog.d(TAG, "Virtual device launch disallowed from user " + activityUser); - return false; - } - final ComponentName activityComponent = activityInfo.getComponentName(); - if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) { + if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent) && activityUser.isSystem()) { // The error dialog alerting users that streaming is blocked is always allowed. return true; } + if (!mAllowedUsers.contains(activityUser)) { + Slog.d(TAG, "Virtual device launch disallowed from user " + activityUser); + return false; + } if (!activityMatchesDisplayCategory(activityInfo)) { Slog.d(TAG, "The activity's required display category '" + activityInfo.requiredDisplayCategory diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java index 3a90a959b877..73ed97ff7b11 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java @@ -35,8 +35,8 @@ import android.service.contentcapture.SnapshotData; import android.util.LocalLog; import android.util.Slog; import android.view.contentcapture.ContentCaptureContext; +import android.view.contentcapture.ContentCaptureSession; import android.view.contentcapture.ContentCaptureSessionId; -import android.view.contentcapture.MainContentCaptureSession; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; @@ -123,7 +123,7 @@ final class ContentCaptureServerSession { public void setContentCaptureEnabledLocked(boolean enabled) { try { final Bundle extras = new Bundle(); - extras.putBoolean(MainContentCaptureSession.EXTRA_ENABLED_STATE, true); + extras.putBoolean(ContentCaptureSession.EXTRA_ENABLED_STATE, true); mSessionStateReceiver.send(enabled ? RESULT_CODE_TRUE : RESULT_CODE_FALSE, extras); } catch (RemoteException e) { Slog.w(TAG, "Error async reporting result to client: " + e); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 671c8e984253..fddb5707b78e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1221,7 +1221,7 @@ public class ActivityManagerService extends IActivityManager.Stub * by the user ID the sticky is for, and can include UserHandle.USER_ALL * for stickies that are sent to all users. */ - @GuardedBy("this") + @GuardedBy("mStickyBroadcasts") final SparseArray<ArrayMap<String, ArrayList<StickyBroadcast>>> mStickyBroadcasts = new SparseArray<>(); @@ -4398,7 +4398,9 @@ public class ActivityManagerService extends IActivityManager.Stub if (packageName == null) { // Remove all sticky broadcasts from this user. - mStickyBroadcasts.remove(userId); + synchronized (mStickyBroadcasts) { + mStickyBroadcasts.remove(userId); + } } ArrayList<ContentProviderRecord> providers = new ArrayList<>(); @@ -11335,20 +11337,23 @@ public class ActivityManagerService extends IActivityManager.Stub for (BroadcastQueue q : mBroadcastQueues) { q.dumpDebug(proto, ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE); } - for (int user=0; user<mStickyBroadcasts.size(); user++) { - long token = proto.start(ActivityManagerServiceDumpBroadcastsProto.STICKY_BROADCASTS); - proto.write(StickyBroadcastProto.USER, mStickyBroadcasts.keyAt(user)); - for (Map.Entry<String, ArrayList<StickyBroadcast>> ent - : mStickyBroadcasts.valueAt(user).entrySet()) { - long actionToken = proto.start(StickyBroadcastProto.ACTIONS); - proto.write(StickyBroadcastProto.StickyAction.NAME, ent.getKey()); - for (StickyBroadcast broadcast : ent.getValue()) { - broadcast.intent.dumpDebug(proto, StickyBroadcastProto.StickyAction.INTENTS, - false, true, true, false); + synchronized (mStickyBroadcasts) { + for (int user = 0; user < mStickyBroadcasts.size(); user++) { + long token = proto.start( + ActivityManagerServiceDumpBroadcastsProto.STICKY_BROADCASTS); + proto.write(StickyBroadcastProto.USER, mStickyBroadcasts.keyAt(user)); + for (Map.Entry<String, ArrayList<StickyBroadcast>> ent + : mStickyBroadcasts.valueAt(user).entrySet()) { + long actionToken = proto.start(StickyBroadcastProto.ACTIONS); + proto.write(StickyBroadcastProto.StickyAction.NAME, ent.getKey()); + for (StickyBroadcast broadcast : ent.getValue()) { + broadcast.intent.dumpDebug(proto, StickyBroadcastProto.StickyAction.INTENTS, + false, true, true, false); + } + proto.end(actionToken); } - proto.end(actionToken); + proto.end(token); } - proto.end(token); } long handlerToken = proto.start(ActivityManagerServiceDumpBroadcastsProto.HANDLER); @@ -11488,45 +11493,50 @@ public class ActivityManagerService extends IActivityManager.Stub needSep = true; - if (!onlyHistory && !onlyReceivers && mStickyBroadcasts != null && dumpPackage == null) { - for (int user=0; user<mStickyBroadcasts.size(); user++) { - if (needSep) { - pw.println(); - } - needSep = true; - printedAnything = true; - pw.print(" Sticky broadcasts for user "); - pw.print(mStickyBroadcasts.keyAt(user)); pw.println(":"); - StringBuilder sb = new StringBuilder(128); - for (Map.Entry<String, ArrayList<StickyBroadcast>> ent - : mStickyBroadcasts.valueAt(user).entrySet()) { - pw.print(" * Sticky action "); pw.print(ent.getKey()); - if (dumpAll) { - pw.println(":"); - ArrayList<StickyBroadcast> broadcasts = ent.getValue(); - final int N = broadcasts.size(); - for (int i=0; i<N; i++) { - final Intent intent = broadcasts.get(i).intent; - final boolean deferUntilActive = broadcasts.get(i).deferUntilActive; - sb.setLength(0); - sb.append(" Intent: "); - intent.toShortString(sb, false, true, false, false); - pw.print(sb); - if (deferUntilActive) { - pw.print(" [D]"); - } - pw.println(); - pw.print(" originalCallingUid: "); - pw.println(broadcasts.get(i).originalCallingUid); - pw.println(); - Bundle bundle = intent.getExtras(); - if (bundle != null) { - pw.print(" extras: "); - pw.println(bundle); + synchronized (mStickyBroadcasts) { + if (!onlyHistory && !onlyReceivers && mStickyBroadcasts != null + && dumpPackage == null) { + for (int user = 0; user < mStickyBroadcasts.size(); user++) { + if (needSep) { + pw.println(); + } + needSep = true; + printedAnything = true; + pw.print(" Sticky broadcasts for user "); + pw.print(mStickyBroadcasts.keyAt(user)); + pw.println(":"); + StringBuilder sb = new StringBuilder(128); + for (Map.Entry<String, ArrayList<StickyBroadcast>> ent + : mStickyBroadcasts.valueAt(user).entrySet()) { + pw.print(" * Sticky action "); + pw.print(ent.getKey()); + if (dumpAll) { + pw.println(":"); + ArrayList<StickyBroadcast> broadcasts = ent.getValue(); + final int N = broadcasts.size(); + for (int i = 0; i < N; i++) { + final Intent intent = broadcasts.get(i).intent; + final boolean deferUntilActive = broadcasts.get(i).deferUntilActive; + sb.setLength(0); + sb.append(" Intent: "); + intent.toShortString(sb, false, true, false, false); + pw.print(sb); + if (deferUntilActive) { + pw.print(" [D]"); + } + pw.println(); + pw.print(" originalCallingUid: "); + pw.println(broadcasts.get(i).originalCallingUid); + pw.println(); + Bundle bundle = intent.getExtras(); + if (bundle != null) { + pw.print(" extras: "); + pw.println(bundle); + } } + } else { + pw.println(""); } - } else { - pw.println(""); } } } @@ -14191,7 +14201,7 @@ public class ActivityManagerService extends IActivityManager.Stub int callingUid; int callingPid; boolean instantApp; - synchronized(this) { + synchronized (mProcLock) { callerApp = getRecordForAppLOSP(caller); if (callerApp == null) { Slog.w(TAG, "registerReceiverWithFeature: no app for " + caller); @@ -14207,57 +14217,59 @@ public class ActivityManagerService extends IActivityManager.Stub callingPid = callerApp.getPid(); instantApp = isInstantApp(callerApp, callerPackage, callingUid); - userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true, - ALLOW_FULL_ONLY, "registerReceiver", callerPackage); - - // Warn if system internals are registering for important broadcasts - // without also using a priority to ensure they process the event - // before normal apps hear about it - if (UserHandle.isCore(callingUid)) { - final int priority = filter.getPriority(); - final boolean systemPriority = (priority >= IntentFilter.SYSTEM_HIGH_PRIORITY) - || (priority <= IntentFilter.SYSTEM_LOW_PRIORITY); - if (!systemPriority) { - final int N = filter.countActions(); - for (int i = 0; i < N; i++) { - // TODO: expand to additional important broadcasts over time - final String action = filter.getAction(i); - if (action.startsWith("android.intent.action.USER_") - || action.startsWith("android.intent.action.PACKAGE_") - || action.startsWith("android.intent.action.UID_") - || action.startsWith("android.intent.action.EXTERNAL_") - || action.startsWith("android.bluetooth.") - || action.equals(Intent.ACTION_SHUTDOWN)) { - if (DEBUG_BROADCAST) { - Slog.wtf(TAG, - "System internals registering for " + filter.toLongString() - + " with app priority; this will race with apps!", - new Throwable()); - } + } + userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true, + ALLOW_FULL_ONLY, "registerReceiver", callerPackage); + + // Warn if system internals are registering for important broadcasts + // without also using a priority to ensure they process the event + // before normal apps hear about it + if (UserHandle.isCore(callingUid)) { + final int priority = filter.getPriority(); + final boolean systemPriority = (priority >= IntentFilter.SYSTEM_HIGH_PRIORITY) + || (priority <= IntentFilter.SYSTEM_LOW_PRIORITY); + if (!systemPriority) { + final int N = filter.countActions(); + for (int i = 0; i < N; i++) { + // TODO: expand to additional important broadcasts over time + final String action = filter.getAction(i); + if (action.startsWith("android.intent.action.USER_") + || action.startsWith("android.intent.action.PACKAGE_") + || action.startsWith("android.intent.action.UID_") + || action.startsWith("android.intent.action.EXTERNAL_") + || action.startsWith("android.bluetooth.") + || action.equals(Intent.ACTION_SHUTDOWN)) { + if (DEBUG_BROADCAST) { + Slog.wtf(TAG, + "System internals registering for " + filter.toLongString() + + " with app priority; this will race with apps!", + new Throwable()); + } - // When undefined, assume that system internals need - // to hear about the event first; they can use - // SYSTEM_LOW_PRIORITY if they need to hear last - if (priority == 0) { - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - } - break; + // When undefined, assume that system internals need + // to hear about the event first; they can use + // SYSTEM_LOW_PRIORITY if they need to hear last + if (priority == 0) { + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); } + break; } } } + } - Iterator<String> actions = filter.actionsIterator(); - if (actions == null) { - ArrayList<String> noAction = new ArrayList<String>(1); - noAction.add(null); - actions = noAction.iterator(); - } - boolean onlyProtectedBroadcasts = true; + Iterator<String> actions = filter.actionsIterator(); + if (actions == null) { + ArrayList<String> noAction = new ArrayList<String>(1); + noAction.add(null); + actions = noAction.iterator(); + } + boolean onlyProtectedBroadcasts = true; - // Collect stickies of users and check if broadcast is only registered for protected - // broadcasts - int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) }; + // Collect stickies of users and check if broadcast is only registered for protected + // broadcasts + int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) }; + synchronized (mStickyBroadcasts) { while (actions.hasNext()) { String action = actions.next(); for (int id : userIds) { @@ -14283,68 +14295,68 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + } - if (Process.isSdkSandboxUid(Binder.getCallingUid())) { - SdkSandboxManagerLocal sdkSandboxManagerLocal = - LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class); - if (sdkSandboxManagerLocal == null) { - throw new IllegalStateException("SdkSandboxManagerLocal not found when checking" - + " whether SDK sandbox uid can register to broadcast receivers."); - } - if (!sdkSandboxManagerLocal.canRegisterBroadcastReceiver( - /*IntentFilter=*/ filter, flags, onlyProtectedBroadcasts)) { - throw new SecurityException("SDK sandbox not allowed to register receiver" - + " with the given IntentFilter: " + filter.toLongString()); - } + if (Process.isSdkSandboxUid(Binder.getCallingUid())) { + SdkSandboxManagerLocal sdkSandboxManagerLocal = + LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class); + if (sdkSandboxManagerLocal == null) { + throw new IllegalStateException("SdkSandboxManagerLocal not found when checking" + + " whether SDK sandbox uid can register to broadcast receivers."); } - - // If the change is enabled, but neither exported or not exported is set, we need to log - // an error so the consumer can know to explicitly set the value for their flag. - // If the caller is registering for a sticky broadcast with a null receiver, we won't - // require a flag - final boolean explicitExportStateDefined = - (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED)) != 0; - if (((flags & Context.RECEIVER_EXPORTED) != 0) && ( - (flags & Context.RECEIVER_NOT_EXPORTED) != 0)) { - throw new IllegalArgumentException( - "Receiver can't specify both RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED" - + "flag"); + if (!sdkSandboxManagerLocal.canRegisterBroadcastReceiver( + /*IntentFilter=*/ filter, flags, onlyProtectedBroadcasts)) { + throw new SecurityException("SDK sandbox not allowed to register receiver" + + " with the given IntentFilter: " + filter.toLongString()); } + } - // Don't enforce the flag check if we're EITHER registering for only protected - // broadcasts, or the receiver is null (a sticky broadcast). Sticky broadcasts should - // not be used generally, so we will be marking them as exported by default - boolean requireExplicitFlagForDynamicReceivers = CompatChanges.isChangeEnabled( - DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED, callingUid); + // If the change is enabled, but neither exported or not exported is set, we need to log + // an error so the consumer can know to explicitly set the value for their flag. + // If the caller is registering for a sticky broadcast with a null receiver, we won't + // require a flag + final boolean explicitExportStateDefined = + (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED)) != 0; + if (((flags & Context.RECEIVER_EXPORTED) != 0) && ( + (flags & Context.RECEIVER_NOT_EXPORTED) != 0)) { + throw new IllegalArgumentException( + "Receiver can't specify both RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED" + + "flag"); + } - // A receiver that is visible to instant apps must also be exported. - final boolean unexportedReceiverVisibleToInstantApps = - ((flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0) && ( - (flags & Context.RECEIVER_NOT_EXPORTED) != 0); - if (unexportedReceiverVisibleToInstantApps && requireExplicitFlagForDynamicReceivers) { - throw new IllegalArgumentException( - "Receiver can't specify both RECEIVER_VISIBLE_TO_INSTANT_APPS and " - + "RECEIVER_NOT_EXPORTED flag"); - } + // Don't enforce the flag check if we're EITHER registering for only protected + // broadcasts, or the receiver is null (a sticky broadcast). Sticky broadcasts should + // not be used generally, so we will be marking them as exported by default + boolean requireExplicitFlagForDynamicReceivers = CompatChanges.isChangeEnabled( + DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED, callingUid); - if (!onlyProtectedBroadcasts) { - if (receiver == null && !explicitExportStateDefined) { - // sticky broadcast, no flag specified (flag isn't required) - flags |= Context.RECEIVER_EXPORTED; - } else if (requireExplicitFlagForDynamicReceivers && !explicitExportStateDefined) { - throw new SecurityException( - callerPackage + ": One of RECEIVER_EXPORTED or " - + "RECEIVER_NOT_EXPORTED should be specified when a receiver " - + "isn't being registered exclusively for system broadcasts"); - // Assume default behavior-- flag check is not enforced - } else if (!requireExplicitFlagForDynamicReceivers && ( - (flags & Context.RECEIVER_NOT_EXPORTED) == 0)) { - // Change is not enabled, assume exported unless otherwise specified. - flags |= Context.RECEIVER_EXPORTED; - } - } else if ((flags & Context.RECEIVER_NOT_EXPORTED) == 0) { + // A receiver that is visible to instant apps must also be exported. + final boolean unexportedReceiverVisibleToInstantApps = + ((flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0) && ( + (flags & Context.RECEIVER_NOT_EXPORTED) != 0); + if (unexportedReceiverVisibleToInstantApps && requireExplicitFlagForDynamicReceivers) { + throw new IllegalArgumentException( + "Receiver can't specify both RECEIVER_VISIBLE_TO_INSTANT_APPS and " + + "RECEIVER_NOT_EXPORTED flag"); + } + + if (!onlyProtectedBroadcasts) { + if (receiver == null && !explicitExportStateDefined) { + // sticky broadcast, no flag specified (flag isn't required) + flags |= Context.RECEIVER_EXPORTED; + } else if (requireExplicitFlagForDynamicReceivers && !explicitExportStateDefined) { + throw new SecurityException( + callerPackage + ": One of RECEIVER_EXPORTED or " + + "RECEIVER_NOT_EXPORTED should be specified when a receiver " + + "isn't being registered exclusively for system broadcasts"); + // Assume default behavior-- flag check is not enforced + } else if (!requireExplicitFlagForDynamicReceivers && ( + (flags & Context.RECEIVER_NOT_EXPORTED) == 0)) { + // Change is not enabled, assume exported unless otherwise specified. flags |= Context.RECEIVER_EXPORTED; } + } else if ((flags & Context.RECEIVER_NOT_EXPORTED) == 0) { + flags |= Context.RECEIVER_EXPORTED; } // Dynamic receivers are exported by default for versions prior to T @@ -15334,56 +15346,59 @@ public class ActivityManagerService extends IActivityManager.Stub throw new SecurityException( "Sticky broadcasts can't target a specific component"); } - // We use userId directly here, since the "all" target is maintained - // as a separate set of sticky broadcasts. - if (userId != UserHandle.USER_ALL) { - // But first, if this is not a broadcast to all users, then - // make sure it doesn't conflict with an existing broadcast to - // all users. - ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get( - UserHandle.USER_ALL); - if (stickies != null) { - ArrayList<StickyBroadcast> list = stickies.get(intent.getAction()); - if (list != null) { - int N = list.size(); - int i; - for (i=0; i<N; i++) { - if (intent.filterEquals(list.get(i).intent)) { - throw new IllegalArgumentException( - "Sticky broadcast " + intent + " for user " - + userId + " conflicts with existing global broadcast"); + synchronized (mStickyBroadcasts) { + // We use userId directly here, since the "all" target is maintained + // as a separate set of sticky broadcasts. + if (userId != UserHandle.USER_ALL) { + // But first, if this is not a broadcast to all users, then + // make sure it doesn't conflict with an existing broadcast to + // all users. + ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get( + UserHandle.USER_ALL); + if (stickies != null) { + ArrayList<StickyBroadcast> list = stickies.get(intent.getAction()); + if (list != null) { + int N = list.size(); + int i; + for (i = 0; i < N; i++) { + if (intent.filterEquals(list.get(i).intent)) { + throw new IllegalArgumentException("Sticky broadcast " + intent + + " for user " + userId + + " conflicts with existing global broadcast"); + } } } } } - } - ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId); - if (stickies == null) { - stickies = new ArrayMap<>(); - mStickyBroadcasts.put(userId, stickies); - } - ArrayList<StickyBroadcast> list = stickies.get(intent.getAction()); - if (list == null) { - list = new ArrayList<>(); - stickies.put(intent.getAction(), list); - } - final boolean deferUntilActive = BroadcastRecord.calculateDeferUntilActive( - callingUid, brOptions, resultTo, ordered, - BroadcastRecord.calculateUrgent(intent, brOptions)); - final int stickiesCount = list.size(); - int i; - for (i = 0; i < stickiesCount; i++) { - if (intent.filterEquals(list.get(i).intent)) { - // This sticky already exists, replace it. - list.set(i, StickyBroadcast.create(new Intent(intent), deferUntilActive, + ArrayMap<String, ArrayList<StickyBroadcast>> stickies = + mStickyBroadcasts.get(userId); + if (stickies == null) { + stickies = new ArrayMap<>(); + mStickyBroadcasts.put(userId, stickies); + } + ArrayList<StickyBroadcast> list = stickies.get(intent.getAction()); + if (list == null) { + list = new ArrayList<>(); + stickies.put(intent.getAction(), list); + } + final boolean deferUntilActive = BroadcastRecord.calculateDeferUntilActive( + callingUid, brOptions, resultTo, ordered, + BroadcastRecord.calculateUrgent(intent, brOptions)); + final int stickiesCount = list.size(); + int i; + for (i = 0; i < stickiesCount; i++) { + if (intent.filterEquals(list.get(i).intent)) { + // This sticky already exists, replace it. + list.set(i, StickyBroadcast.create(new Intent(intent), deferUntilActive, + callingUid, callerAppProcessState)); + break; + } + } + if (i >= stickiesCount) { + list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive, callingUid, callerAppProcessState)); - break; } } - if (i >= stickiesCount) { - list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive, callingUid, - callerAppProcessState)); - } } int[] users; @@ -15619,13 +15634,15 @@ public class ActivityManagerService extends IActivityManager.Stub } @VisibleForTesting - ArrayList<StickyBroadcast> getStickyBroadcasts(String action, int userId) { - final ArrayMap<String, ArrayList<StickyBroadcast>> stickyBroadcasts = - mStickyBroadcasts.get(userId); - if (stickyBroadcasts == null) { - return null; + ArrayList<StickyBroadcast> getStickyBroadcastsForTest(String action, int userId) { + synchronized (mStickyBroadcasts) { + final ArrayMap<String, ArrayList<StickyBroadcast>> stickyBroadcasts = + mStickyBroadcasts.get(userId); + if (stickyBroadcasts == null) { + return null; + } + return stickyBroadcasts.get(action); } - return stickyBroadcasts.get(action); } /** @@ -15790,6 +15807,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } + @Override public final void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors() == true) { @@ -15799,23 +15817,23 @@ public class ActivityManagerService extends IActivityManager.Stub userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, ALLOW_NON_FULL, "removeStickyBroadcast", null); - synchronized(this) { - if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY) - != PackageManager.PERMISSION_GRANTED) { - String msg = "Permission Denial: unbroadcastIntent() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " requires " + android.Manifest.permission.BROADCAST_STICKY; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } + if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY) + != PackageManager.PERMISSION_GRANTED) { + String msg = "Permission Denial: unbroadcastIntent() from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " requires " + android.Manifest.permission.BROADCAST_STICKY; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + synchronized (mStickyBroadcasts) { ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId); if (stickies != null) { ArrayList<StickyBroadcast> list = stickies.get(intent.getAction()); if (list != null) { int N = list.size(); int i; - for (i=0; i<N; i++) { + for (i = 0; i < N; i++) { if (intent.filterEquals(list.get(i).intent)) { list.remove(i); break; diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 848a2b004f25..57c52c2cf408 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -402,7 +402,7 @@ final class ActivityManagerShellCommand extends ShellCommand { case "get-bg-restriction-level": return runGetBgRestrictionLevel(pw); case "observe-foreground-process": - return runGetCurrentForegroundProcess(pw, mInternal, mTaskInterface); + return runGetCurrentForegroundProcess(pw, mInternal); case "reset-dropbox-rate-limiter": return runResetDropboxRateLimiter(); case "list-displays-for-starting-users": @@ -3690,11 +3690,10 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } - private int runGetCurrentForegroundProcess(PrintWriter pw, - IActivityManager iam, IActivityTaskManager iatm) + private int runGetCurrentForegroundProcess(PrintWriter pw, IActivityManager iam) throws RemoteException { - ProcessObserver observer = new ProcessObserver(pw, iam, iatm, mInternal); + ProcessObserver observer = new ProcessObserver(pw, iam); iam.registerProcessObserver(observer); final InputStream mInput = getRawInputStream(); @@ -3729,15 +3728,10 @@ final class ActivityManagerShellCommand extends ShellCommand { private PrintWriter mPw; private IActivityManager mIam; - private IActivityTaskManager mIatm; - private ActivityManagerService mInternal; - ProcessObserver(PrintWriter mPw, IActivityManager mIam, - IActivityTaskManager mIatm, ActivityManagerService ams) { + ProcessObserver(PrintWriter mPw, IActivityManager mIam) { this.mPw = mPw; this.mIam = mIam; - this.mIatm = mIatm; - this.mInternal = ams; } @Override diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 0b561467a078..c37e619ed985 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -353,8 +353,7 @@ class BroadcastProcessQueue { // If we come across the record that's being enqueued in the queue, then that means // we already enqueued it for a receiver in this process and trying to insert a new // one past this could create priority inversion in the queue, so bail out. - if (record == testRecord && record.blockedUntilBeyondCount[recordIndex] - > testRecord.blockedUntilBeyondCount[testRecordIndex]) { + if (record == testRecord) { break; } if ((record.callingUid == testRecord.callingUid) diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index d0d647c7a669..b20ed7c47fd1 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -181,6 +181,7 @@ public class SettingsToPropertiesMapper { "tv_system_ui", "usb", "vibrator", + "virtualization", "virtual_devices", "wallet_integration", "wear_calling_messaging", diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING index 575db01931e6..e90910a13b3b 100644 --- a/services/core/java/com/android/server/am/TEST_MAPPING +++ b/services/core/java/com/android/server/am/TEST_MAPPING @@ -146,6 +146,15 @@ { "include-filter": "android.app.cts.ServiceTest" }, { "include-filter": "android.app.cts.ActivityManagerFgsBgStartTest" } ] + }, + { + "name": "CtsStatsdAtomHostTestCases", + "options": [ + { "include-filter": "android.cts.statsdatom.appexit.AppExitHostTest" }, + { "exclude-annotation": "androidx.test.filters.LargeTest" }, + { "exclude-annotation": "androidx.test.filters.FlakyTest" }, + { "exclude-annotation": "org.junit.Ignore" } + ] } ] } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index d80638af697e..203ac2cba3ca 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -33,6 +33,7 @@ import static android.app.AppOpsManager.MODE_DEFAULT; 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_BLUETOOTH_CONNECT; import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_CAMERA_SANDBOXED; import static android.app.AppOpsManager.OP_FLAGS_ALL; @@ -2849,6 +2850,11 @@ public class AppOpsService extends IAppOpsService.Stub { verifyIncomingUid(uid); verifyIncomingOp(code); if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) { + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (code == OP_BLUETOOTH_CONNECT) { + Slog.e(TAG, "noting OP_BLUETOOTH_CONNECT returned MODE_ERRORED as incoming " + + "package: " + packageName + " and uid: " + uid + " is invalid"); + } return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag, packageName); } @@ -2877,6 +2883,13 @@ public class AppOpsService extends IAppOpsService.Stub { } } catch (SecurityException e) { logVerifyAndGetBypassFailure(uid, e, "noteOperation"); + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (code == OP_BLUETOOTH_CONNECT) { + Slog.e(TAG, "noting OP_BLUETOOTH_CONNECT returned MODE_ERRORED as" + + " verifyAndGetBypass returned a SecurityException for package: " + + packageName + " and uid: " + uid + " and attributionTag: " + + attributionTag, e); + } return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag, packageName); } @@ -2890,6 +2903,11 @@ public class AppOpsService extends IAppOpsService.Stub { if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid + " package " + packageName + "flags: " + AppOpsManager.flagsToString(flags)); + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (code == OP_BLUETOOTH_CONNECT) { + Slog.e(TAG, "noting OP_BLUETOOTH_CONNECT returned MODE_ERRORED as" + + " #getOpsLocked returned null"); + } return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag, packageName); } @@ -2930,6 +2948,11 @@ public class AppOpsService extends IAppOpsService.Stub { attributedOp.rejected(uidState.getState(), flags); scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags, uidMode); + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (code == OP_BLUETOOTH_CONNECT && uidMode == MODE_ERRORED) { + Slog.e(TAG, "noting OP_BLUETOOTH_CONNECT returned MODE_ERRORED as" + + " uid mode is MODE_ERRORED"); + } return new SyncNotedAppOp(uidMode, code, attributionTag, packageName); } } else { @@ -2949,6 +2972,11 @@ public class AppOpsService extends IAppOpsService.Stub { attributedOp.rejected(uidState.getState(), flags); scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags, mode); + // TODO(b/302609140): Remove extra logging after this issue is diagnosed. + if (code == OP_BLUETOOTH_CONNECT && mode == MODE_ERRORED) { + Slog.e(TAG, "noting OP_BLUETOOTH_CONNECT returned MODE_ERRORED as" + + " package mode is MODE_ERRORED"); + } return new SyncNotedAppOp(mode, code, attributionTag, packageName); } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 37fe38924037..7ac4dd30fe71 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -12684,12 +12684,16 @@ public class AudioService extends IAudioService.Stub public @Nullable AudioHalVersionInfo getHalVersion() { for (AudioHalVersionInfo version : AudioHalVersionInfo.VERSIONS) { try { - // TODO: check AIDL service. String versionStr = version.getMajorVersion() + "." + version.getMinorVersion(); - HwBinder.getService( - String.format("android.hardware.audio@%s::IDevicesFactory", versionStr), - "default"); - return version; + final String aidlStr = "android.hardware.audio.core.IModule/default"; + final String hidlStr = String.format("android.hardware.audio@%s::IDevicesFactory", + versionStr); + if (null != ServiceManager.checkService(aidlStr)) { + return version; + } else { + HwBinder.getService(hidlStr, "default"); + return version; + } } catch (NoSuchElementException e) { // Ignore, the specified HAL interface is not found. } catch (RemoteException re) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java index 0bb6141583d5..90da74ccaa1c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java @@ -147,7 +147,7 @@ public class HidlToAidlSensorAdapter extends Sensor implements IHwBinder.DeathRe gestureAvailabilityDispatcher, () -> mCurrentUserId, getUserSwitchCallback())); mLockoutTracker = new LockoutFrameworkImpl(getContext(), userId -> mLockoutResetDispatcher.notifyLockoutResetCallbacks( - getSensorProperties().sensorId)); + getSensorProperties().sensorId), getHandler()); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java index 2f77275890dd..0e05a7923db4 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java @@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint.hidl; import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -81,19 +82,30 @@ public class LockoutFrameworkImpl implements LockoutTracker { @NonNull LockoutResetCallback lockoutResetCallback) { this(context, lockoutResetCallback, (userId) -> PendingIntent.getBroadcast(context, userId, new Intent(ACTION_LOCKOUT_RESET).putExtra(KEY_LOCKOUT_RESET_USER, userId), - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)); + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE), + null /* handler */); + } + + public LockoutFrameworkImpl(@NonNull Context context, + @NonNull LockoutResetCallback lockoutResetCallback, + @NonNull Handler handler) { + this(context, lockoutResetCallback, (userId) -> PendingIntent.getBroadcast(context, userId, + new Intent(ACTION_LOCKOUT_RESET).putExtra(KEY_LOCKOUT_RESET_USER, userId), + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE), + handler); } @VisibleForTesting LockoutFrameworkImpl(@NonNull Context context, @NonNull LockoutResetCallback lockoutResetCallback, - @NonNull Function<Integer, PendingIntent> lockoutResetIntent) { + @NonNull Function<Integer, PendingIntent> lockoutResetIntent, + @Nullable Handler handler) { mLockoutResetCallback = lockoutResetCallback; mTimedLockoutCleared = new SparseBooleanArray(); mFailedAttempts = new SparseIntArray(); mAlarmManager = context.getSystemService(AlarmManager.class); mLockoutReceiver = new LockoutReceiver(); - mHandler = new Handler(Looper.getMainLooper()); + mHandler = handler == null ? new Handler(Looper.getMainLooper()) : handler; mLockoutResetIntent = lockoutResetIntent; context.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET), diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 56a94ec06ad4..49f607095b90 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -1424,7 +1424,11 @@ public class ClipboardService extends SystemService { String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD, userId); if (!TextUtils.isEmpty(defaultIme)) { - final String imePkg = ComponentName.unflattenFromString(defaultIme).getPackageName(); + final ComponentName imeComponent = ComponentName.unflattenFromString(defaultIme); + if (imeComponent == null) { + return false; + } + final String imePkg = imeComponent.getPackageName(); return imePkg.equals(packageName); } return false; diff --git a/services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java b/services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java index 6978686faa12..544f490913e2 100644 --- a/services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java +++ b/services/core/java/com/android/server/display/config/DisplayBrightnessMappingConfig.java @@ -118,8 +118,13 @@ public class DisplayBrightnessMappingConfig { "The first lux value in the display brightness mapping must be 0"); } - String key = (mapping.getMode() == null ? "default" : mapping.getMode()) + "_" - + (mapping.getSetting() == null ? "normal" : mapping.getSetting()); + String key = (mapping.getMode() == null + ? AutoBrightnessModeName._default.getRawName() + : mapping.getMode().getRawName()) + + "_" + + (mapping.getSetting() == null + ? AutoBrightnessSettingName.normal.getRawName() + : mapping.getSetting().getRawName()); if (mBrightnessLevelsMap.containsKey(key) || mBrightnessLevelsLuxMap.containsKey(key)) { throw new IllegalArgumentException( diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 087c52573118..36dac8316e54 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -48,6 +48,7 @@ import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.IInputManager; import android.hardware.input.IInputSensorEventListener; import android.hardware.input.IKeyboardBacklightListener; +import android.hardware.input.IStickyModifierStateListener; import android.hardware.input.ITabletModeChangedListener; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; @@ -319,6 +320,9 @@ public class InputManagerService extends IInputManager.Stub // Manages Keyboard backlight private final KeyboardBacklightControllerInterface mKeyboardBacklightController; + // Manages Sticky modifier state + private final StickyModifierStateController mStickyModifierStateController; + // Manages Keyboard modifier keys remapping private final KeyRemapper mKeyRemapper; @@ -464,6 +468,7 @@ public class InputManagerService extends IInputManager.Stub ? new KeyboardBacklightController(mContext, mNative, mDataStore, injector.getLooper(), injector.getUEventManager()) : new KeyboardBacklightControllerInterface() {}; + mStickyModifierStateController = new StickyModifierStateController(); mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper()); mUseDevInputEventForAudioJack = @@ -2827,6 +2832,33 @@ public class InputManagerService extends IInputManager.Stub yPosition)).sendToTarget(); } + @Override + @EnforcePermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE) + public void registerStickyModifierStateListener( + @NonNull IStickyModifierStateListener listener) { + super.registerStickyModifierStateListener_enforcePermission(); + Objects.requireNonNull(listener); + mStickyModifierStateController.registerStickyModifierStateListener(listener, + Binder.getCallingPid()); + } + + @Override + @EnforcePermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE) + public void unregisterStickyModifierStateListener( + @NonNull IStickyModifierStateListener listener) { + super.unregisterStickyModifierStateListener_enforcePermission(); + Objects.requireNonNull(listener); + mStickyModifierStateController.unregisterStickyModifierStateListener(listener, + Binder.getCallingPid()); + } + + // Native callback + @SuppressWarnings("unused") + void notifyStickyModifierStateChanged(int modifierState, int lockedModifierState) { + mStickyModifierStateController.notifyStickyModifierStateChanged(modifierState, + lockedModifierState); + } + // Native callback. @SuppressWarnings("unused") boolean isInputMethodConnectionActive() { diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java index c9668a236f48..be8d2a4d0bcb 100644 --- a/services/core/java/com/android/server/input/InputSettingsObserver.java +++ b/services/core/java/com/android/server/input/InputSettingsObserver.java @@ -86,9 +86,9 @@ class InputSettingsObserver extends ContentObserver { (reason) -> updateKeyRepeatInfo()), Map.entry(Settings.System.getUriFor(Settings.System.SHOW_ROTARY_INPUT), (reason) -> updateShowRotaryInput()), - Map.entry(Settings.System.getUriFor(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS), + Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS), (reason) -> updateAccessibilityBounceKeys()), - Map.entry(Settings.System.getUriFor(Settings.Secure.ACCESSIBILITY_STICKY_KEYS), + Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_STICKY_KEYS), (reason) -> updateAccessibilityStickyKeys())); } diff --git a/services/core/java/com/android/server/input/StickyModifierStateController.java b/services/core/java/com/android/server/input/StickyModifierStateController.java new file mode 100644 index 000000000000..5a22c107db56 --- /dev/null +++ b/services/core/java/com/android/server/input/StickyModifierStateController.java @@ -0,0 +1,133 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.input; + +import android.annotation.BinderThread; +import android.hardware.input.IStickyModifierStateListener; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; + +/** + * A thread-safe component of {@link InputManagerService} responsible for managing the sticky + * modifier state for A11y Sticky keys feature. + */ +final class StickyModifierStateController { + + private static final String TAG = "ModifierStateController"; + + // To enable these logs, run: + // 'adb shell setprop log.tag.ModifierStateController DEBUG' (requires restart) + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + // List of currently registered sticky modifier state listeners + @GuardedBy("mStickyModifierStateListenerRecords") + private final SparseArray<StickyModifierStateListenerRecord> + mStickyModifierStateListenerRecords = new SparseArray<>(); + + public void notifyStickyModifierStateChanged(int modifierState, int lockedModifierState) { + if (DEBUG) { + Slog.d(TAG, "Sticky modifier state changed, modifierState = " + modifierState + + ", lockedModifierState = " + lockedModifierState); + } + + synchronized (mStickyModifierStateListenerRecords) { + for (int i = 0; i < mStickyModifierStateListenerRecords.size(); i++) { + mStickyModifierStateListenerRecords.valueAt(i).notifyStickyModifierStateChanged( + modifierState, lockedModifierState); + } + } + } + + /** Register the sticky modifier state listener for a process. */ + @BinderThread + public void registerStickyModifierStateListener(IStickyModifierStateListener listener, + int pid) { + synchronized (mStickyModifierStateListenerRecords) { + if (mStickyModifierStateListenerRecords.get(pid) != null) { + throw new IllegalStateException("The calling process has already registered " + + "a StickyModifierStateListener."); + } + StickyModifierStateListenerRecord record = new StickyModifierStateListenerRecord(pid, + listener); + try { + listener.asBinder().linkToDeath(record, 0); + } catch (RemoteException ex) { + throw new RuntimeException(ex); + } + mStickyModifierStateListenerRecords.put(pid, record); + } + } + + /** Unregister the sticky modifier state listener for a process. */ + @BinderThread + public void unregisterStickyModifierStateListener(IStickyModifierStateListener listener, + int pid) { + synchronized (mStickyModifierStateListenerRecords) { + StickyModifierStateListenerRecord record = mStickyModifierStateListenerRecords.get(pid); + if (record == null) { + throw new IllegalStateException("The calling process has no registered " + + "StickyModifierStateListener."); + } + if (record.mListener.asBinder() != listener.asBinder()) { + throw new IllegalStateException("The calling process has a different registered " + + "StickyModifierStateListener."); + } + record.mListener.asBinder().unlinkToDeath(record, 0); + mStickyModifierStateListenerRecords.remove(pid); + } + } + + private void onStickyModifierStateListenerDied(int pid) { + synchronized (mStickyModifierStateListenerRecords) { + mStickyModifierStateListenerRecords.remove(pid); + } + } + + // A record of a registered sticky modifier state listener from one process. + private class StickyModifierStateListenerRecord implements IBinder.DeathRecipient { + public final int mPid; + public final IStickyModifierStateListener mListener; + + StickyModifierStateListenerRecord(int pid, IStickyModifierStateListener listener) { + mPid = pid; + mListener = listener; + } + + @Override + public void binderDied() { + if (DEBUG) { + Slog.d(TAG, "Sticky modifier state listener for pid " + mPid + " died."); + } + onStickyModifierStateListenerDied(mPid); + } + + public void notifyStickyModifierStateChanged(int modifierState, int lockedModifierState) { + try { + mListener.onStickyModifierStateChanged(modifierState, lockedModifierState); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to notify process " + mPid + + " that sticky modifier state changed, assuming it died.", ex); + binderDied(); + } + } + } +} diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java index 66807aeb6629..f96bb8fb6c6f 100644 --- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java +++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java @@ -52,6 +52,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.OptionalInt; +import java.util.function.IntConsumer; // TODO(b/210039666): See if we can make this class thread-safe. final class HandwritingModeController { @@ -84,14 +85,14 @@ final class HandwritingModeController { private boolean mDelegatorFromDefaultHomePackage; private Runnable mDelegationIdleTimeoutRunnable; private Handler mDelegationIdleTimeoutHandler; - + private IntConsumer mPointerToolTypeConsumer; private HandwritingEventReceiverSurface mHandwritingSurface; private int mCurrentRequestId; @AnyThread HandwritingModeController(Context context, Looper uiThreadLooper, - Runnable inkWindowInitRunnable) { + Runnable inkWindowInitRunnable, IntConsumer toolTypeConsumer) { mContext = context; mLooper = uiThreadLooper; mCurrentDisplayId = Display.INVALID_DISPLAY; @@ -100,6 +101,7 @@ final class HandwritingModeController { mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mCurrentRequestId = 0; mInkWindowInitRunnable = inkWindowInitRunnable; + mPointerToolTypeConsumer = toolTypeConsumer; } /** @@ -355,6 +357,11 @@ final class HandwritingModeController { return false; } final MotionEvent event = (MotionEvent) ev; + if (mPointerToolTypeConsumer != null && event.getAction() == MotionEvent.ACTION_DOWN) { + int toolType = event.getToolType(event.getActionIndex()); + // notify IME of change in tool type. + mPointerToolTypeConsumer.accept(toolType); + } if (!event.isStylusPointer()) { return false; } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 0d29b7dca8d4..24bcb4ece7aa 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -124,6 +124,7 @@ import android.view.WindowManager.DisplayImePolicy; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.Flags; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputConnection; @@ -206,6 +207,7 @@ import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.IntConsumer; /** * This class provides a system service that manages input methods. @@ -276,7 +278,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub final Context mContext; final Resources mRes; private final Handler mHandler; - final InputMethodSettings mSettings; + private final InputMethodSettings mSettings; final SettingsObserver mSettingsObserver; private final SparseBooleanArray mLoggedDeniedGetInputMethodWindowVisibleHeightForUid = new SparseBooleanArray(0); @@ -316,7 +318,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // Mapping from deviceId to the device-specific imeId for that device. private final SparseArray<String> mVirtualDeviceMethodMap = new SparseArray<>(); - final InputMethodSubtypeSwitchingController mSwitchingController; + private final InputMethodSubtypeSwitchingController mSwitchingController; final HardwareKeyboardShortcutController mHardwareKeyboardShortcutController = new HardwareKeyboardShortcutController(); @@ -1619,7 +1621,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (userId != currentUserId) { return; } - mSettings.switchCurrentUser(currentUserId, !mSystemReady); + mSettings.switchCurrentUser(currentUserId); if (mSystemReady) { // We need to rebuild IMEs. buildInputMethodListLocked(false /* resetDefaultEnabledIme */); @@ -1693,7 +1695,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub mLastSwitchUserId = userId; // mSettings should be created before buildInputMethodListLocked - mSettings = new InputMethodSettings(mMethodMap, userId, !mSystemReady); + mSettings = new InputMethodSettings(mMethodMap, userId); AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId); mSwitchingController = @@ -1713,8 +1715,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); mNonPreemptibleInputMethods = mRes.getStringArray( com.android.internal.R.array.config_nonPreemptibleInputMethods); + IntConsumer toolTypeConsumer = + Flags.useHandwritingListenerForTooltype() + ? toolType -> onUpdateEditorToolType(toolType) : null; mHwController = new HandwritingModeController(mContext, thread.getLooper(), - new InkWindowInitializer()); + new InkWindowInitializer(), toolTypeConsumer); registerDeviceListenerAndCheckStylusSupport(); } @@ -1735,6 +1740,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } + private void onUpdateEditorToolType(int toolType) { + synchronized (ImfLock.class) { + IInputMethodInvoker curMethod = getCurMethodLocked(); + if (curMethod != null) { + curMethod.updateEditorToolType(toolType); + } + } + } + @GuardedBy("ImfLock.class") private void resetDefaultImeLocked(Context context) { // Do not reset the default (current) IME when it is a 3rd-party IME @@ -1811,7 +1825,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // copy-on-write settings. final boolean useCopyOnWriteSettings = !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId); - mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings); + mSettings.switchCurrentUser(newUserId); // Additional subtypes should be reset when the user is changed AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId); final String defaultImiId = mSettings.getSelectedInputMethod(); @@ -1873,8 +1887,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (!mSystemReady) { mSystemReady = true; final int currentUserId = mSettings.getCurrentUserId(); - mSettings.switchCurrentUser(currentUserId, - !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId)); + mSettings.switchCurrentUser(currentUserId); mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class); hideStatusBarIconLocked(); @@ -2023,7 +2036,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub //TODO(b/197848765): This can be optimized by caching multi-user methodMaps/methodList. //TODO(b/210039666): use cache. final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings(methodMap, userId, true); + final InputMethodSettings settings = new InputMethodSettings(methodMap, userId); final InputMethodInfo imi = methodMap.get(settings.getSelectedInputMethod()); return imi != null && imi.supportsStylusHandwriting(); } @@ -2059,7 +2072,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub AdditionalSubtypeUtils.load(additionalSubtypeMap, userId); queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap, methodList, directBootAwareness); - settings = new InputMethodSettings(methodMap, userId, true /* copyOnWrite */); + settings = new InputMethodSettings(methodMap, userId); } // filter caller's access to input methods methodList.removeIf(imi -> @@ -2077,7 +2090,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub settings = mSettings; } else { final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - settings = new InputMethodSettings(methodMap, userId, true /* copyOnWrite */); + settings = new InputMethodSettings(methodMap, userId); methodList = settings.getEnabledInputMethodListLocked(); } // filter caller's access to input methods @@ -2157,7 +2170,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (imi == null) { return Collections.emptyList(); } - final InputMethodSettings settings = new InputMethodSettings(methodMap, userId, true); + final InputMethodSettings settings = new InputMethodSettings(methodMap, userId); if (!canCallerAccessInputMethod(imi.getPackageName(), callingUid, userId, settings)) { return Collections.emptyList(); } @@ -3526,7 +3539,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_HAS_IME); mCurStatsToken = null; - if (lastClickToolType != MotionEvent.TOOL_TYPE_UNKNOWN) { + if (!Flags.useHandwritingListenerForTooltype() + && lastClickToolType != MotionEvent.TOOL_TYPE_UNKNOWN) { curMethod.updateEditorToolType(lastClickToolType); } mVisibilityApplier.performShowIme(windowToken, statsToken, @@ -4134,7 +4148,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings(methodMap, userId, false); + final InputMethodSettings settings = new InputMethodSettings(methodMap, userId); return settings.getLastInputMethodSubtypeLocked(); } } @@ -4186,7 +4200,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub AdditionalSubtypeUtils.load(additionalSubtypeMap, userId); queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap, methodList, DirectBootAwareness.AUTO); - final InputMethodSettings settings = new InputMethodSettings(methodMap, userId, false); + final InputMethodSettings settings = new InputMethodSettings(methodMap, userId); settings.setAdditionalInputMethodSubtypes(imiId, toBeAdded, additionalSubtypeMap, mPackageManagerInternal, callingUid); } @@ -4215,8 +4229,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub final boolean currentUser = (mSettings.getCurrentUserId() == userId); final InputMethodSettings settings = currentUser ? mSettings - : new InputMethodSettings(queryMethodMapForUser(userId), userId, - !mUserManagerInternal.isUserUnlocked(userId)); + : new InputMethodSettings(queryMethodMapForUser(userId), userId); if (!settings.setEnabledInputMethodSubtypes(imeId, subtypeHashCodes)) { return; } @@ -4814,7 +4827,20 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1); return false; } - mMenuController.showInputMethodMenu(showAuxSubtypes, displayId); + synchronized (ImfLock.class) { + final boolean isScreenLocked = mWindowManagerInternal.isKeyguardLocked() + && mWindowManagerInternal.isKeyguardSecure( + mSettings.getCurrentUserId()); + final String lastInputMethodId = mSettings.getSelectedInputMethod(); + int lastInputMethodSubtypeId = + mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId); + + final List<ImeSubtypeListItem> imList = mSwitchingController + .getSortedInputMethodAndSubtypeListForImeMenuLocked( + showAuxSubtypes, isScreenLocked); + mMenuController.showInputMethodMenuLocked(showAuxSubtypes, displayId, + lastInputMethodId, lastInputMethodSubtypeId, imList); + } return true; // --------------------------------------------------------- @@ -5264,21 +5290,21 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ @GuardedBy("ImfLock.class") private boolean setInputMethodEnabledLocked(String id, boolean enabled) { - List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings - .getEnabledInputMethodsAndSubtypeListLocked(); - if (enabled) { - for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) { - if (pair.first.equals(id)) { - // We are enabling this input method, but it is already enabled. - // Nothing to do. The previous state was enabled. - return true; - } + final String enabledImeIdsStr = mSettings.getEnabledInputMethodsStr(); + final String newEnabledImeIdsStr = InputMethodUtils.concatEnabledImeIds( + enabledImeIdsStr, id); + if (TextUtils.equals(enabledImeIdsStr, newEnabledImeIdsStr)) { + // We are enabling this input method, but it is already enabled. + // Nothing to do. The previous state was enabled. + return true; } - mSettings.appendAndPutEnabledInputMethodLocked(id); + mSettings.putEnabledInputMethodsStr(newEnabledImeIdsStr); // Previous state was disabled. return false; } else { + final List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings + .getEnabledInputMethodsAndSubtypeListLocked(); StringBuilder builder = new StringBuilder(); if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked( builder, enabledInputMethodsList, id)) { @@ -5365,7 +5391,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings(methodMap, userId, false); + final InputMethodSettings settings = new InputMethodSettings(methodMap, userId); return settings.getCurrentInputMethodSubtypeForNonCurrentUsers(); } } @@ -5438,7 +5464,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub AdditionalSubtypeUtils.load(additionalSubtypeMap, userId); queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap, methodList, DirectBootAwareness.AUTO); - InputMethodSettings settings = new InputMethodSettings(methodMap, userId, true); + InputMethodSettings settings = new InputMethodSettings(methodMap, userId); return methodMap.get(settings.getSelectedInputMethod()); } @@ -5465,7 +5491,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return true; } final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings(methodMap, userId, false); + final InputMethodSettings settings = new InputMethodSettings(methodMap, userId); if (!methodMap.containsKey(imeId) || !settings.getEnabledInputMethodListLocked().contains(methodMap.get(imeId))) { return false; // IME is not found or not enabled. @@ -5604,15 +5630,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return true; } final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings(methodMap, - userId, false); + final InputMethodSettings settings = new InputMethodSettings(methodMap, userId); if (!methodMap.containsKey(imeId)) { return false; // IME is not found. } if (enabled) { - if (!settings.getEnabledInputMethodListLocked().contains( - methodMap.get(imeId))) { - settings.appendAndPutEnabledInputMethodLocked(imeId); + final String enabledImeIdsStr = settings.getEnabledInputMethodsStr(); + final String newEnabledImeIdsStr = InputMethodUtils.concatEnabledImeIds( + enabledImeIdsStr, imeId); + if (!TextUtils.equals(enabledImeIdsStr, newEnabledImeIdsStr)) { + settings.putEnabledInputMethodsStr(newEnabledImeIdsStr); } } else { settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked( @@ -6346,19 +6373,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } else { final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); - final InputMethodSettings settings = new InputMethodSettings(methodMap, userId, false); + final InputMethodSettings settings = new InputMethodSettings(methodMap, userId); if (enabled) { if (!methodMap.containsKey(imeId)) { failedToEnableUnknownIme = true; } else { - for (InputMethodInfo imi : settings.getEnabledInputMethodListLocked()) { - if (TextUtils.equals(imi.getId(), imeId)) { - previouslyEnabled = true; - break; - } - } + final String enabledImeIdsStr = settings.getEnabledInputMethodsStr(); + final String newEnabledImeIdsStr = InputMethodUtils.concatEnabledImeIds( + enabledImeIdsStr, imeId); + previouslyEnabled = TextUtils.equals(enabledImeIdsStr, newEnabledImeIdsStr); if (!previouslyEnabled) { - settings.appendAndPutEnabledInputMethodLocked(imeId); + settings.putEnabledInputMethodsStr(newEnabledImeIdsStr); } } } else { @@ -6491,7 +6516,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap, methodList, DirectBootAwareness.AUTO); final InputMethodSettings settings = new InputMethodSettings( - methodMap, userId, false); + methodMap, userId); nextEnabledImes = InputMethodInfoUtils.getDefaultEnabledImes(mContext, methodList); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java index efa1e0d66f35..6ed4848c20b4 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java @@ -19,12 +19,14 @@ 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.NonNull; import android.annotation.Nullable; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; +import android.provider.Settings; import android.text.TextUtils; import android.util.Slog; import android.view.LayoutInflater; @@ -51,8 +53,6 @@ final class InputMethodMenuController { private static final String TAG = InputMethodMenuController.class.getSimpleName(); private final InputMethodManagerService mService; - private final InputMethodUtils.InputMethodSettings mSettings; - private final InputMethodSubtypeSwitchingController mSwitchingController; private final WindowManagerInternal mWindowManagerInternal; private AlertDialog.Builder mDialogBuilder; @@ -69,145 +69,141 @@ final class InputMethodMenuController { InputMethodMenuController(InputMethodManagerService service) { mService = service; - mSettings = mService.mSettings; - mSwitchingController = mService.mSwitchingController; mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); } - void showInputMethodMenu(boolean showAuxSubtypes, int displayId) { + @GuardedBy("ImfLock.class") + void showInputMethodMenuLocked(boolean showAuxSubtypes, int displayId, + String preferredInputMethodId, int preferredInputMethodSubtypeId, + @NonNull List<ImeSubtypeListItem> imList) { if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes); - synchronized (ImfLock.class) { - final boolean isScreenLocked = mWindowManagerInternal.isKeyguardLocked() - && mWindowManagerInternal.isKeyguardSecure( - mService.getCurrentImeUserIdLocked()); - final String lastInputMethodId = mSettings.getSelectedInputMethod(); - int lastInputMethodSubtypeId = - mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId); - if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId); - - final List<ImeSubtypeListItem> imList = mSwitchingController - .getSortedInputMethodAndSubtypeListForImeMenuLocked( - showAuxSubtypes, isScreenLocked); - if (imList.isEmpty()) { - return; - } + final int userId = mService.getCurrentImeUserIdLocked(); - hideInputMethodMenuLocked(); + if (imList.isEmpty()) { + return; + } - if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) { - final InputMethodSubtype currentSubtype = - mService.getCurrentInputMethodSubtypeLocked(); - if (currentSubtype != null) { - final String curMethodId = mService.getSelectedMethodIdLocked(); - final InputMethodInfo currentImi = - mService.queryInputMethodForCurrentUserLocked(curMethodId); - lastInputMethodSubtypeId = SubtypeUtils.getSubtypeIdFromHashCode( - currentImi, currentSubtype.hashCode()); - } + hideInputMethodMenuLocked(); + + if (preferredInputMethodSubtypeId == NOT_A_SUBTYPE_ID) { + final InputMethodSubtype currentSubtype = + mService.getCurrentInputMethodSubtypeLocked(); + if (currentSubtype != null) { + final String curMethodId = mService.getSelectedMethodIdLocked(); + final InputMethodInfo currentImi = + mService.queryInputMethodForCurrentUserLocked(curMethodId); + preferredInputMethodSubtypeId = SubtypeUtils.getSubtypeIdFromHashCode( + currentImi, currentSubtype.hashCode()); } + } - final int size = imList.size(); - mIms = new InputMethodInfo[size]; - mSubtypeIds = new int[size]; - int checkedItem = 0; - for (int i = 0; i < size; ++i) { - final ImeSubtypeListItem item = imList.get(i); - mIms[i] = item.mImi; - mSubtypeIds[i] = item.mSubtypeId; - if (mIms[i].getId().equals(lastInputMethodId)) { - int subtypeId = mSubtypeIds[i]; - if ((subtypeId == NOT_A_SUBTYPE_ID) - || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0) - || (subtypeId == lastInputMethodSubtypeId)) { - checkedItem = i; - } + // Find out which item should be checked by default. + final int size = imList.size(); + mIms = new InputMethodInfo[size]; + mSubtypeIds = new int[size]; + int checkedItem = 0; + for (int i = 0; i < size; ++i) { + final ImeSubtypeListItem item = imList.get(i); + mIms[i] = item.mImi; + mSubtypeIds[i] = item.mSubtypeId; + if (mIms[i].getId().equals(preferredInputMethodId)) { + int subtypeId = mSubtypeIds[i]; + if ((subtypeId == NOT_A_SUBTYPE_ID) + || (preferredInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0) + || (subtypeId == preferredInputMethodSubtypeId)) { + checkedItem = i; } } + } - if (mDialogWindowContext == null) { - mDialogWindowContext = new InputMethodDialogWindowContext(); - } - final Context dialogWindowContext = mDialogWindowContext.get(displayId); - mDialogBuilder = new AlertDialog.Builder(dialogWindowContext); - mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu()); - - final Context dialogContext = mDialogBuilder.getContext(); - final TypedArray a = dialogContext.obtainStyledAttributes(null, - com.android.internal.R.styleable.DialogPreference, - com.android.internal.R.attr.alertDialogStyle, 0); - final Drawable dialogIcon = a.getDrawable( - com.android.internal.R.styleable.DialogPreference_dialogIcon); - a.recycle(); - - mDialogBuilder.setIcon(dialogIcon); - - final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class); - final View tv = inflater.inflate( - com.android.internal.R.layout.input_method_switch_dialog_title, null); - mDialogBuilder.setCustomTitle(tv); - - // Setup layout for a toggle switch of the hardware keyboard - mSwitchingDialogTitleView = tv; - mSwitchingDialogTitleView - .findViewById(com.android.internal.R.id.hard_keyboard_section) - .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable() - ? View.VISIBLE : View.GONE); - final Switch hardKeySwitch = mSwitchingDialogTitleView.findViewById( - com.android.internal.R.id.hard_keyboard_switch); - hardKeySwitch.setChecked(mShowImeWithHardKeyboard); - hardKeySwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { - mSettings.setShowImeWithHardKeyboard(isChecked); - // Ensure that the input method dialog is dismissed when changing - // the hardware keyboard state. - hideInputMethodMenu(); - }); - - final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext, - com.android.internal.R.layout.input_method_switch_item, imList, checkedItem); - final DialogInterface.OnClickListener choiceListener = (dialog, which) -> { - synchronized (ImfLock.class) { - if (mIms == null || mIms.length <= which || mSubtypeIds == null - || mSubtypeIds.length <= which) { - return; - } - final InputMethodInfo im = mIms[which]; - int subtypeId = mSubtypeIds[which]; - adapter.mCheckedItem = which; - adapter.notifyDataSetChanged(); - if (im != null) { - if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) { - subtypeId = NOT_A_SUBTYPE_ID; - } - mService.setInputMethodLocked(im.getId(), subtypeId); + if (mDialogWindowContext == null) { + mDialogWindowContext = new InputMethodDialogWindowContext(); + } + final Context dialogWindowContext = mDialogWindowContext.get(displayId); + mDialogBuilder = new AlertDialog.Builder(dialogWindowContext); + mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu()); + + final Context dialogContext = mDialogBuilder.getContext(); + final TypedArray a = dialogContext.obtainStyledAttributes(null, + com.android.internal.R.styleable.DialogPreference, + com.android.internal.R.attr.alertDialogStyle, 0); + final Drawable dialogIcon = a.getDrawable( + com.android.internal.R.styleable.DialogPreference_dialogIcon); + a.recycle(); + + mDialogBuilder.setIcon(dialogIcon); + + final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class); + final View tv = inflater.inflate( + com.android.internal.R.layout.input_method_switch_dialog_title, null); + mDialogBuilder.setCustomTitle(tv); + + // Setup layout for a toggle switch of the hardware keyboard + mSwitchingDialogTitleView = tv; + mSwitchingDialogTitleView + .findViewById(com.android.internal.R.id.hard_keyboard_section) + .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable() + ? View.VISIBLE : View.GONE); + final Switch hardKeySwitch = mSwitchingDialogTitleView.findViewById( + com.android.internal.R.id.hard_keyboard_switch); + hardKeySwitch.setChecked(mShowImeWithHardKeyboard); + hardKeySwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { + SecureSettingsWrapper.putBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, + isChecked, userId); + // Ensure that the input method dialog is dismissed when changing + // the hardware keyboard state. + hideInputMethodMenu(); + }); + + // Fill the list items with onClick listener, which takes care of IME (and subtype) + // switching when clicked. + final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext, + com.android.internal.R.layout.input_method_switch_item, imList, checkedItem); + final DialogInterface.OnClickListener choiceListener = (dialog, which) -> { + synchronized (ImfLock.class) { + if (mIms == null || mIms.length <= which || mSubtypeIds == null + || mSubtypeIds.length <= which) { + return; + } + final InputMethodInfo im = mIms[which]; + int subtypeId = mSubtypeIds[which]; + adapter.mCheckedItem = which; + adapter.notifyDataSetChanged(); + if (im != null) { + if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) { + subtypeId = NOT_A_SUBTYPE_ID; } - hideInputMethodMenuLocked(); + mService.setInputMethodLocked(im.getId(), subtypeId); } - }; - mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener); - - mSwitchingDialog = mDialogBuilder.create(); - mSwitchingDialog.setCanceledOnTouchOutside(true); - final Window w = mSwitchingDialog.getWindow(); - final WindowManager.LayoutParams attrs = w.getAttributes(); - w.setType(WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); - w.setHideOverlayWindows(true); - // Use an alternate token for the dialog for that window manager can group the token - // with other IME windows based on type vs. grouping based on whichever token happens - // to get selected by the system later on. - attrs.token = dialogWindowContext.getWindowContextToken(); - attrs.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; - attrs.setTitle("Select input method"); - w.setAttributes(attrs); - mService.updateSystemUiLocked(); - mService.sendOnNavButtonFlagsChangedLocked(); - mSwitchingDialog.show(); - - } + hideInputMethodMenuLocked(); + } + }; + mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener); + + // Final steps to instantiate a dialog to show it up. + mSwitchingDialog = mDialogBuilder.create(); + mSwitchingDialog.setCanceledOnTouchOutside(true); + final Window w = mSwitchingDialog.getWindow(); + final WindowManager.LayoutParams attrs = w.getAttributes(); + w.setType(WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); + w.setHideOverlayWindows(true); + // Use an alternate token for the dialog for that window manager can group the token + // with other IME windows based on type vs. grouping based on whichever token happens + // to get selected by the system later on. + attrs.token = dialogWindowContext.getWindowContextToken(); + attrs.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + attrs.setTitle("Select input method"); + w.setAttributes(attrs); + mService.updateSystemUiLocked(); + mService.sendOnNavButtonFlagsChangedLocked(); + mSwitchingDialog.show(); } void updateKeyboardFromSettingsLocked() { - mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled(); + mShowImeWithHardKeyboard = + SecureSettingsWrapper.getBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, + false, mService.getCurrentImeUserIdLocked()); if (mSwitchingDialog != null && mSwitchingDialogTitleView != null && mSwitchingDialog.isShowing()) { final Switch hardKeySwitch = mSwitchingDialogTitleView.findViewById( diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java index a88d85e07100..a0b55edddec7 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java @@ -213,9 +213,6 @@ final class InputMethodUtils { public static class InputMethodSettings { private final ArrayMap<String, InputMethodInfo> mMethodMap; - private boolean mCopyOnWrite = false; - @NonNull - private String mEnabledInputMethodsStrCache = ""; @UserIdInt private int mCurrentUserId; @@ -229,29 +226,21 @@ final class InputMethodUtils { } } - InputMethodSettings(ArrayMap<String, InputMethodInfo> methodMap, @UserIdInt int userId, - boolean copyOnWrite) { + InputMethodSettings(ArrayMap<String, InputMethodInfo> methodMap, @UserIdInt int userId) { mMethodMap = methodMap; - switchCurrentUser(userId, copyOnWrite); + switchCurrentUser(userId); } /** * Must be called when the current user is changed. * * @param userId The user ID. - * @param copyOnWrite If {@code true}, for each settings key - * (e.g. {@link Settings.Secure#ACTION_INPUT_METHOD_SUBTYPE_SETTINGS}) we use the actual - * settings on the {@link Settings.Secure} until we do the first write operation. */ - void switchCurrentUser(@UserIdInt int userId, boolean copyOnWrite) { + void switchCurrentUser(@UserIdInt int userId) { if (DEBUG) { Slog.d(TAG, "--- Switch the current user from " + mCurrentUserId + " to " + userId); } - if (mCurrentUserId != userId || mCopyOnWrite != copyOnWrite) { - mEnabledInputMethodsStrCache = ""; - } mCurrentUserId = userId; - mCopyOnWrite = copyOnWrite; } private void putString(@NonNull String key, @Nullable String str) { @@ -352,16 +341,6 @@ final class InputMethodUtils { return imsList; } - void appendAndPutEnabledInputMethodLocked(String id) { - if (TextUtils.isEmpty(mEnabledInputMethodsStrCache)) { - // Add in the newly enabled input method. - putEnabledInputMethodsStr(id); - } else { - putEnabledInputMethodsStr( - mEnabledInputMethodsStrCache + INPUT_METHOD_SEPARATOR + id); - } - } - /** * Build and put a string of EnabledInputMethods with removing specified Id. * @return the specified id was removed or not. @@ -418,18 +397,11 @@ final class InputMethodUtils { } else { putString(Settings.Secure.ENABLED_INPUT_METHODS, str); } - // TODO: Update callers of putEnabledInputMethodsStr to make str @NonNull. - mEnabledInputMethodsStrCache = (str != null ? str : ""); } @NonNull String getEnabledInputMethodsStr() { - mEnabledInputMethodsStrCache = getString(Settings.Secure.ENABLED_INPUT_METHODS, ""); - if (DEBUG) { - Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache - + ", " + mCurrentUserId); - } - return mEnabledInputMethodsStrCache; + return getString(Settings.Secure.ENABLED_INPUT_METHODS, ""); } private void saveSubtypeHistory( @@ -688,14 +660,6 @@ final class InputMethodUtils { return getInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, NOT_A_SUBTYPE_ID); } - boolean isShowImeWithHardKeyboardEnabled() { - return getBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, false); - } - - void setShowImeWithHardKeyboard(boolean show) { - putBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, show); - } - @UserIdInt public int getCurrentUserId() { return mCurrentUserId; @@ -862,8 +826,6 @@ final class InputMethodUtils { public void dumpLocked(final Printer pw, final String prefix) { pw.println(prefix + "mCurrentUserId=" + mCurrentUserId); - pw.println(prefix + "mCopyOnWrite=" + mCopyOnWrite); - pw.println(prefix + "mEnabledInputMethodsStrCache=" + mEnabledInputMethodsStrCache); } } diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java index 5ef89ad4269a..a5939e924adb 100644 --- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java @@ -17,6 +17,7 @@ package com.android.server.location.gnss; import android.content.Context; +import android.location.flags.Flags; import android.os.PersistableBundle; import android.os.SystemProperties; import android.telephony.CarrierConfigManager; @@ -36,6 +37,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; @@ -275,6 +277,11 @@ public class GnssConfiguration { } loadPropertiesFromCarrierConfig(inEmergency, activeSubId); + if (Flags.gnssConfigurationFromResource()) { + // Overlay carrier properties from resources. + loadPropertiesFromResource(mContext, mProperties); + } + if (isSimAbsent(mContext)) { // Use the default SIM's LPP profile when SIM is absent. String lpp_prof = SystemProperties.get(LPP_PROFILE); @@ -382,7 +389,7 @@ public class GnssConfiguration { if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) { String key = configKey .substring(CarrierConfigManager.Gps.KEY_PREFIX.length()) - .toUpperCase(); + .toUpperCase(Locale.ROOT); Object value = configs.get(configKey); if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value); if (value instanceof String) { @@ -410,6 +417,24 @@ public class GnssConfiguration { } } + private void loadPropertiesFromResource(Context context, + Properties properties) { + String[] configValues = context.getResources().getStringArray( + com.android.internal.R.array.config_gnssParameters); + for (String item : configValues) { + if (DEBUG) Log.d(TAG, "GnssParamsResource: " + item); + // We need to support "KEY =", but not "=VALUE". + int index = item.indexOf("="); + if (index > 0 && index + 1 < item.length()) { + String key = item.substring(0, index); + String value = item.substring(index + 1); + properties.setProperty(key.trim().toUpperCase(Locale.ROOT), value); + } else { + Log.w(TAG, "malformed contents: " + item); + } + } + } + private int getRangeCheckedConfigEsExtensionSec() { int emergencyExtensionSeconds = getIntConfig(CONFIG_ES_EXTENSION_SEC, 0); if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) { diff --git a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioManagerRouteController.java index 0eb9166371dc..087f5a65a222 100644 --- a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java +++ b/services/core/java/com/android/server/media/AudioManagerRouteController.java @@ -57,12 +57,10 @@ import java.util.Objects; * * <p>This implementation obtains and manages all routes via {@link AudioManager}, with the * exception of {@link AudioManager#handleBluetoothActiveDeviceChanged inactive bluetooth} routes - * which are managed by {@link AudioPoliciesBluetoothRouteController}, which depends on the - * bluetooth stack (for example {@link BluetoothAdapter}. + * which are managed by {@link BluetoothDeviceRoutesManager}, which depends on the + * bluetooth stack ({@link BluetoothAdapter} and related classes). */ -// TODO: b/305199571 - Rename this class to avoid the AudioPolicies prefix, which has been flagged -// by the audio team as a confusing name. -/* package */ final class AudioPoliciesDeviceRouteController implements DeviceRouteController { +/* package */ final class AudioManagerRouteController implements DeviceRouteController { private static final String TAG = SystemMediaRoute2Provider.TAG; @NonNull @@ -77,7 +75,7 @@ import java.util.Objects; @NonNull private final AudioManager mAudioManager; @NonNull private final Handler mHandler; @NonNull private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; - @NonNull private final AudioPoliciesBluetoothRouteController mBluetoothRouteController; + @NonNull private final BluetoothDeviceRoutesManager mBluetoothRouteController; @NonNull private final Map<String, MediaRoute2InfoHolder> mRouteIdToAvailableDeviceRoutes = @@ -103,7 +101,7 @@ import java.util.Objects; Manifest.permission.MODIFY_AUDIO_ROUTING, Manifest.permission.QUERY_AUDIO_STATE }) - /* package */ AudioPoliciesDeviceRouteController( + /* package */ AudioManagerRouteController( @NonNull Context context, @NonNull AudioManager audioManager, @NonNull Looper looper, @@ -120,7 +118,7 @@ import java.util.Objects; DeviceRouteController.getBuiltInSpeakerSuitabilityStatus(mContext); mBluetoothRouteController = - new AudioPoliciesBluetoothRouteController( + new BluetoothDeviceRoutesManager( mContext, btAdapter, this::rebuildAvailableRoutesAndNotify); // Just build routes but don't notify. The caller may not expect the listener to be invoked // before this constructor has finished executing. diff --git a/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java b/services/core/java/com/android/server/media/BluetoothDeviceRoutesManager.java index 7cf3983e57f6..8119628aed7a 100644 --- a/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java +++ b/services/core/java/com/android/server/media/BluetoothDeviceRoutesManager.java @@ -58,9 +58,7 @@ import java.util.stream.Collectors; * <p>This class also serves as ground truth for assigning {@link MediaRoute2Info#getId() route ids} * for bluetooth routes via {@link #getRouteIdForBluetoothAddress}. */ -// TODO: b/305199571 - Rename this class to remove the RouteController suffix, which causes -// confusion with the BluetoothRouteController interface. -/* package */ class AudioPoliciesBluetoothRouteController { +/* package */ class BluetoothDeviceRoutesManager { private static final String TAG = SystemMediaRoute2Provider.TAG; private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_"; @@ -86,7 +84,7 @@ import java.util.stream.Collectors; @NonNull private final BluetoothProfileMonitor mBluetoothProfileMonitor; - AudioPoliciesBluetoothRouteController(@NonNull Context context, + BluetoothDeviceRoutesManager(@NonNull Context context, @NonNull BluetoothAdapter bluetoothAdapter, @NonNull BluetoothRouteController.BluetoothRoutesUpdatedListener listener) { this(context, bluetoothAdapter, @@ -94,7 +92,7 @@ import java.util.stream.Collectors; } @VisibleForTesting - AudioPoliciesBluetoothRouteController(@NonNull Context context, + BluetoothDeviceRoutesManager(@NonNull Context context, @NonNull BluetoothAdapter bluetoothAdapter, @NonNull BluetoothProfileMonitor bluetoothProfileMonitor, @NonNull BluetoothRouteController.BluetoothRoutesUpdatedListener listener) { @@ -276,7 +274,7 @@ import java.util.stream.Collectors; int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); if (state == BluetoothAdapter.STATE_OFF || state == BluetoothAdapter.STATE_TURNING_OFF) { - synchronized (AudioPoliciesBluetoothRouteController.this) { + synchronized (BluetoothDeviceRoutesManager.this) { mBluetoothRoutes.clear(); } notifyBluetoothRoutesUpdated(); @@ -284,7 +282,7 @@ import java.util.stream.Collectors; updateBluetoothRoutes(); boolean shouldCallListener; - synchronized (AudioPoliciesBluetoothRouteController.this) { + synchronized (BluetoothDeviceRoutesManager.this) { shouldCallListener = !mBluetoothRoutes.isEmpty(); } diff --git a/services/core/java/com/android/server/media/DeviceRouteController.java b/services/core/java/com/android/server/media/DeviceRouteController.java index 8b62cc974862..dff0adfca370 100644 --- a/services/core/java/com/android/server/media/DeviceRouteController.java +++ b/services/core/java/com/android/server/media/DeviceRouteController.java @@ -65,7 +65,7 @@ import java.util.List; if (strategyForMedia != null && btAdapter != null && Flags.enableAudioPoliciesDeviceAndBluetoothController()) { - return new AudioPoliciesDeviceRouteController( + return new AudioManagerRouteController( context, audioManager, looper, diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index ae889d8255c6..21e7befc1b89 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -231,18 +231,21 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } private boolean shouldBind() { - if (mRunning) { - boolean shouldBind = - mLastDiscoveryPreference != null - && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty(); - if (mIsSelfScanOnlyProvider) { - shouldBind &= mLastDiscoveryPreferenceIncludesThisPackage; - } - shouldBind |= mIsManagerScanning; - shouldBind |= !getSessionInfos().isEmpty(); - return shouldBind; + if (!mRunning) { + return false; } - return false; + if (!getSessionInfos().isEmpty() || mIsManagerScanning) { + // We bind if any manager is scanning (regardless of whether an app is scanning) to give + // the opportunity for providers to publish routing sessions that were established + // directly between the app and the provider (typically via AndroidX MediaRouter). See + // b/176774510#comment20 for more information. + return true; + } + boolean anAppIsScanning = + mLastDiscoveryPreference != null + && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty(); + return anAppIsScanning + && (mLastDiscoveryPreferenceIncludesThisPackage || !mIsSelfScanOnlyProvider); } private void bind() { diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 9088cb96a29d..06a8d989b930 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -2051,6 +2051,7 @@ class MediaRouter2ServiceImpl { String indent = prefix + " "; pw.println(indent + "mOwnerPackageName=" + mOwnerPackageName); + pw.println(indent + "mTargetPackageName=" + mTargetPackageName); pw.println(indent + "mManagerId=" + mManagerId); pw.println(indent + "mOwnerUid=" + mOwnerUid); pw.println(indent + "mOwnerPid=" + mOwnerPid); @@ -2264,7 +2265,6 @@ class MediaRouter2ServiceImpl { indexOfRouteProviderInfoByUniqueId(provider.getUniqueId(), mLastProviderInfos); MediaRoute2ProviderInfo oldInfo = providerInfoIndex == -1 ? null : mLastProviderInfos.get(providerInfoIndex); - MediaRouter2ServiceImpl mediaRouter2Service = mServiceRef.get(); if (oldInfo == newInfo) { // Nothing to do. diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index db39b5e24bbb..2affdfcf5c7e 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -89,12 +89,10 @@ import android.view.ViewConfiguration; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.media.flags.Flags; -import com.android.server.LocalManagerRegistry; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.Watchdog; import com.android.server.Watchdog.Monitor; -import com.android.server.am.ActivityManagerLocal; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -146,7 +144,6 @@ public class MediaSessionService extends SystemService implements Monitor { private KeyguardManager mKeyguardManager; private AudioManager mAudioManager; private boolean mHasFeatureLeanback; - private ActivityManagerLocal mActivityManagerLocal; private ActivityManagerInternal mActivityManagerInternal; // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile) @@ -232,7 +229,6 @@ public class MediaSessionService extends SystemService implements Monitor { NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED); mContext.registerReceiver(mNotificationListenerEnabledChangedReceiver, filter); - mActivityManagerLocal = LocalManagerRegistry.getManager(ActivityManagerLocal.class); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); } @@ -585,18 +581,21 @@ public class MediaSessionService extends SystemService implements Monitor { try { MediaServerUtils.enforcePackageName(mContext, callingPackage, callingUid); if (targetUid != callingUid) { - boolean canAllowWhileInUse = mActivityManagerLocal - .canAllowWhileInUsePermissionInFgs(callingPid, callingUid, callingPackage); - boolean canStartFgs = canAllowWhileInUse - || mActivityManagerLocal.canStartForegroundService(callingPid, callingUid, - callingPackage); + boolean canAllowWhileInUse = + mActivityManagerInternal.canAllowWhileInUsePermissionInFgs( + callingPid, callingUid, callingPackage); + boolean canStartFgs = + canAllowWhileInUse + || mActivityManagerInternal.canStartForegroundService( + callingPid, callingUid, callingPackage); Log.i(TAG, "tempAllowlistTargetPkgIfPossible callingPackage:" + callingPackage + " targetPackage:" + targetPackage + " reason:" + reason + (canAllowWhileInUse ? " [WIU]" : "") + (canStartFgs ? " [FGS]" : "")); if (canAllowWhileInUse) { - mActivityManagerLocal.tempAllowWhileInUsePermissionInFgs(targetUid, + mActivityManagerInternal.tempAllowWhileInUsePermissionInFgs( + targetUid, MediaSessionDeviceConfig .getMediaSessionCallbackFgsWhileInUseTempAllowDurationMs()); } diff --git a/services/core/java/com/android/server/media/TEST_MAPPING b/services/core/java/com/android/server/media/TEST_MAPPING index 1b49093a66d8..b3e5b9e96889 100644 --- a/services/core/java/com/android/server/media/TEST_MAPPING +++ b/services/core/java/com/android/server/media/TEST_MAPPING @@ -3,5 +3,10 @@ { "name": "CtsMediaBetterTogetherTestCases" } + ], + "postsubmit": [ + { + "name": "MediaRouterServiceTests" + } ] } diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index 85731651dd59..4d19eade5a05 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -42,6 +42,7 @@ import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import com.android.internal.annotations.Keep; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.RingBuffer; import com.android.server.am.ProcessList; @@ -693,6 +694,7 @@ public class NetworkPolicyLogger { * Note: This class needs to be public for RingBuffer class to be able to create * new instances of this. */ + @Keep public static final class Data { public int type; public long timeStamp; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ff415c155b35..7fbc0852c746 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -16,7 +16,9 @@ package com.android.server.notification; +import static android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS; import static android.Manifest.permission.RECEIVE_SENSITIVE_NOTIFICATIONS; +import static android.Manifest.permission.STATUS_BAR_SERVICE; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE; import static android.app.AppOpsManager.MODE_ALLOWED; @@ -67,6 +69,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OF import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; import static android.app.Flags.lifetimeExtensionRefactor; +import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; +import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_FOREGROUND_SERVICE; @@ -210,6 +214,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; @@ -3369,9 +3374,7 @@ public class NotificationManagerService extends SystemService { .setChannelName(r.getChannel().getName().toString()) .setPostedTimeMs(System.currentTimeMillis()) .setTitle(getHistoryTitle(r.getNotification())) - .setText(getHistoryText( - r.getSbn().getPackageContext(getContext()), - r.getNotification())) + .setText(getHistoryText(r.getNotification())) .setIcon(r.getNotification().getSmallIcon()) .build()); } @@ -3414,12 +3417,11 @@ public class NotificationManagerService extends SystemService { /** * Returns the appropriate substring for this notification based on the style of notification. */ - private String getHistoryText(Context appContext, Notification n) { + private String getHistoryText(Notification n) { CharSequence text = null; if (n.extras != null) { text = n.extras.getCharSequence(EXTRA_TEXT); - - Notification.Builder nb = Notification.Builder.recoverBuilder(appContext, n); + Notification.Builder nb = Notification.Builder.recoverBuilder(getContext(), n); if (nb.getStyle() instanceof Notification.BigTextStyle) { text = ((Notification.BigTextStyle) nb.getStyle()).getBigText(); @@ -5126,8 +5128,10 @@ public class NotificationManagerService extends SystemService { for (int userId : mUm.getProfileIds(info.userid, false)) { try { int uid = getUidForPackageAndUser(pkg, UserHandle.of(userId)); - VersionedPackage vp = new VersionedPackage(pkg, uid); - nlf.addPackage(vp); + if (uid != INVALID_UID) { + VersionedPackage vp = new VersionedPackage(pkg, uid); + nlf.addPackage(vp); + } } catch (Exception e) { // pkg doesn't exist on that user; skip } @@ -5383,7 +5387,7 @@ public class NotificationManagerService extends SystemService { @Override public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg, boolean fromUser) { - validateAutomaticZenRule(automaticZenRule); + validateAutomaticZenRule(/* updateId= */ null, automaticZenRule); checkCallerIsSameApp(pkg); if (automaticZenRule.getZenPolicy() != null && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { @@ -5409,7 +5413,7 @@ public class NotificationManagerService extends SystemService { @Override public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule, boolean fromUser) throws RemoteException { - validateAutomaticZenRule(automaticZenRule); + validateAutomaticZenRule(id, automaticZenRule); enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); enforceUserOriginOnlyFromSystem(fromUser, "updateAutomaticZenRule"); @@ -5417,26 +5421,58 @@ public class NotificationManagerService extends SystemService { computeZenOrigin(fromUser), "updateAutomaticZenRule", Binder.getCallingUid()); } - private void validateAutomaticZenRule(AutomaticZenRule rule) { + private void validateAutomaticZenRule(@Nullable String updateId, AutomaticZenRule rule) { Objects.requireNonNull(rule, "automaticZenRule is null"); Objects.requireNonNull(rule.getName(), "Name is null"); rule.validate(); - if (rule.getOwner() == null - && rule.getConfigurationActivity() == null) { - throw new NullPointerException( - "Rule must have a conditionproviderservice and/or configuration activity"); + + // Implicit rules have no ConditionProvider or Activity. We allow the user to customize + // them (via Settings), but not the owner app. Should the app want to start using it as + // a "normal" rule, it must provide a CP/ConfigActivity too. + if (android.app.Flags.modesApi()) { + boolean isImplicitRuleUpdateFromSystem = updateId != null + && ZenModeHelper.isImplicitRuleId(updateId) + && isCallerSystemOrSystemUi(); + if (!isImplicitRuleUpdateFromSystem + && rule.getOwner() == null + && rule.getConfigurationActivity() == null) { + throw new NullPointerException( + "Rule must have a ConditionProviderService and/or configuration " + + "activity"); + } + } else { + if (rule.getOwner() == null && rule.getConfigurationActivity() == null) { + throw new NullPointerException( + "Rule must have a ConditionProviderService and/or configuration " + + "activity"); + } } Objects.requireNonNull(rule.getConditionId(), "ConditionId is null"); if (android.app.Flags.modesApi()) { + if (isCallerSystemOrSystemUi()) { + return; // System callers can use any type. + } + int uid = Binder.getCallingUid(); + int userId = UserHandle.getUserId(uid); + if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) { - int uid = Binder.getCallingUid(); boolean isDeviceOwner = Binder.withCleanCallingIdentity( () -> mDpm.isActiveDeviceOwner(uid)); if (!isDeviceOwner) { throw new IllegalArgumentException( "Only Device Owners can use AutomaticZenRules with TYPE_MANAGED"); } + } else if (rule.getType() == AutomaticZenRule.TYPE_BEDTIME) { + String wellbeingPackage = getContext().getResources().getString( + com.android.internal.R.string.config_systemWellbeing); + boolean isCallerWellbeing = !TextUtils.isEmpty(wellbeingPackage) + && mPackageManagerInternal.isSameApp(wellbeingPackage, uid, userId); + if (!isCallerWellbeing) { + throw new IllegalArgumentException( + "Only the 'Wellbeing' package can use AutomaticZenRules with " + + "TYPE_BEDTIME"); + } } } } @@ -5569,7 +5605,7 @@ public class NotificationManagerService extends SystemService { private void enforceSystemOrSystemUI(String message) { if (isCallerSystemOrPhone()) return; - getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, + getContext().enforceCallingPermission(STATUS_BAR_SERVICE, message); } @@ -5578,7 +5614,7 @@ public class NotificationManagerService extends SystemService { checkCallerIsSystemOrSameApp(pkg); } catch (SecurityException e) { getContext().enforceCallingPermission( - android.Manifest.permission.STATUS_BAR_SERVICE, + STATUS_BAR_SERVICE, message); } } @@ -6183,13 +6219,20 @@ public class NotificationManagerService extends SystemService { @Override public void setPrivateNotificationsAllowed(boolean allow) { if (PackageManager.PERMISSION_GRANTED - != getContext().checkCallingPermission( - permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { + != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { throw new SecurityException( "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); } if (allow != mLockScreenAllowSecureNotifications) { mLockScreenAllowSecureNotifications = allow; + if (android.app.Flags.keyguardPrivateNotifications()) { + getContext().sendBroadcast( + new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) + .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, + mLockScreenAllowSecureNotifications), + STATUS_BAR_SERVICE); + } + handleSavePolicyFile(); } } @@ -6197,8 +6240,7 @@ public class NotificationManagerService extends SystemService { @Override public boolean getPrivateNotificationsAllowed() { if (PackageManager.PERMISSION_GRANTED - != getContext().checkCallingPermission( - permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { + != getContext().checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) { throw new SecurityException( "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission"); } @@ -8369,6 +8411,8 @@ public class NotificationManagerService extends SystemService { boolean posted = false; try { posted = postNotification(); + } catch (Exception e) { + Slog.e(TAG, "Error posting", e); } finally { if (!posted) { mTracker.cancel(); @@ -9557,12 +9601,16 @@ public class NotificationManagerService extends SystemService { } private void scheduleListenerHintsChanged(int state) { - mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); + if (!Flags.notificationReduceMessagequeueUsage()) { + mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); + } mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); } private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { - mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); + if (!Flags.notificationReduceMessagequeueUsage()) { + mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); + } mHandler.obtainMessage( MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, listenerInterruptionFilter, @@ -9642,15 +9690,24 @@ public class NotificationManagerService extends SystemService { } protected void scheduleSendRankingUpdate() { - if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { + if (Flags.notificationReduceMessagequeueUsage()) { Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE); sendMessage(m); + } else { + if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { + Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE); + sendMessage(m); + } } } protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) { - if (!hasCallbacks(cancelRunnable)) { + if (Flags.notificationReduceMessagequeueUsage()) { sendMessage(Message.obtain(this, cancelRunnable)); + } else { + if (!hasCallbacks(cancelRunnable)) { + sendMessage(Message.obtain(this, cancelRunnable)); + } } } @@ -9684,7 +9741,9 @@ public class NotificationManagerService extends SystemService { } public void requestSort() { - removeMessages(MESSAGE_RANKING_SORT); + if (!Flags.notificationReduceMessagequeueUsage()) { + removeMessages(MESSAGE_RANKING_SORT); + } Message msg = Message.obtain(); msg.what = MESSAGE_RANKING_SORT; sendMessage(msg); @@ -10589,7 +10648,7 @@ public class NotificationManagerService extends SystemService { if (isCallerSystemOrPhone()) { return true; } - return getContext().checkCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE) + return getContext().checkCallingPermission(STATUS_BAR_SERVICE) == PERMISSION_GRANTED; } @@ -10628,7 +10687,7 @@ public class NotificationManagerService extends SystemService { if (isCallerSystemOrPhone()) { return; } - getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, + getContext().enforceCallingPermission(STATUS_BAR_SERVICE, message); } diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java index df570a02eba5..0145577fb945 100644 --- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java +++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java @@ -23,6 +23,7 @@ import static android.service.notification.NotificationServiceProto.RULE_TYPE_MA import static android.service.notification.NotificationServiceProto.RULE_TYPE_UNKNOWN; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Flags; import android.app.NotificationManager; import android.content.pm.PackageManager; @@ -256,13 +257,21 @@ class ZenModeEventLogger { return true; } + if (Flags.modesApi() && hasActiveRuleCountDiff()) { + // Rules with INTERRUPTION_FILTER_ALL were always possible but before MODES_API + // they were completely useless; now they can apply effects, so we want to log + // when they become active/inactive, even though DND itself (as in "notification + // blocking") is off. + return true; + } + // If zen mode didn't change, did the policy or number of active rules change? We only // care about changes that take effect while zen mode is on, so make sure the current // zen mode is not "OFF" if (mNewZenMode == ZEN_MODE_OFF) { return false; } - return hasPolicyDiff() || hasRuleCountDiff(); + return hasPolicyDiff() || hasActiveRuleCountDiff(); } // Does the difference in zen mode go from off to on or vice versa? @@ -294,6 +303,16 @@ class ZenModeEventLogger { } } + if (Flags.modesApi() && mNewZenMode == ZEN_MODE_OFF) { + // If the mode is OFF -> OFF then there cannot be any *effective* change to policy. + // (Note that, in theory, a policy diff is impossible since we don't merge the + // policies of INTERRUPTION_FILTER_ALL rules; this is a "just in case" check). + if (hasPolicyDiff() || hasChannelsBypassingDiff()) { + Log.wtf(TAG, "Detected policy diff even though DND is OFF and not toggled"); + } + return ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED; + } + // zen mode didn't change; we must be here because of a policy change or rule change if (hasPolicyDiff() || hasChannelsBypassingDiff()) { return ZenStateChangedEvent.DND_POLICY_CHANGED; @@ -345,7 +364,7 @@ class ZenModeEventLogger { * Returns whether the previous config and new config have a different number of active * automatic or manual rules. */ - private boolean hasRuleCountDiff() { + private boolean hasActiveRuleCountDiff() { return numActiveRulesInConfig(mPrevConfig) != numActiveRulesInConfig(mNewConfig); } @@ -381,9 +400,11 @@ class ZenModeEventLogger { // Determine the number of (automatic & manual) rules active after the change takes place. int getNumRulesActive() { - // If the zen mode has turned off, that means nothing can be active. - if (mNewZenMode == ZEN_MODE_OFF) { - return 0; + if (!Flags.modesApi()) { + // If the zen mode has turned off, that means nothing can be active. + if (mNewZenMode == ZEN_MODE_OFF) { + return 0; + } } return numActiveRulesInConfig(mNewConfig); } @@ -478,8 +499,19 @@ class ZenModeEventLogger { /** * Convert the new policy to a DNDPolicyProto format for output in logs. + * + * <p>If {@code mNewZenMode} is {@code ZEN_MODE_OFF} (which can mean either no rules + * active, or only rules with {@code INTERRUPTION_FILTER_ALL} active) then this returns + * {@code null} (which will be mapped to a missing submessage in the proto). Although this + * is not the value of {@code NotificationManager#getConsolidatedNotificationPolicy()}, it + * makes sense for logging since that policy is not actually influencing anything. */ + @Nullable byte[] getDNDPolicyProto() { + if (Flags.modesApi() && mNewZenMode == ZEN_MODE_OFF) { + return null; + } + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); ProtoOutputStream proto = new ProtoOutputStream(bytes); diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 0a46901a93d1..3244aff2a4dc 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -134,6 +134,8 @@ public class ZenModeHelper { private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72; static final int RULE_LIMIT_PER_PACKAGE = 100; + private static final String IMPLICIT_RULE_ID_PREFIX = "implicit_"; // + pkg_name + /** * Send new activation AutomaticZenRule statuses to apps with a min target SDK version */ @@ -653,7 +655,11 @@ public class ZenModeHelper { } private static String implicitRuleId(String forPackage) { - return "implicit_" + forPackage; + return IMPLICIT_RULE_ID_PREFIX + forPackage; + } + + static boolean isImplicitRuleId(@NonNull String ruleId) { + return ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX); } boolean removeAutomaticZenRule(String id, @ConfigChangeOrigin int origin, String reason, @@ -1490,7 +1496,12 @@ public class ZenModeHelper { for (ZenRule automaticRule : mConfig.automaticRules.values()) { if (automaticRule.isAutomaticActive()) { - applyCustomPolicy(policy, automaticRule); + // Active rules with INTERRUPTION_FILTER_ALL are not included in consolidated + // policy. This is relevant in case some other active rule has a more + // restrictive INTERRUPTION_FILTER but a more lenient ZenPolicy! + if (!Flags.modesApi() || automaticRule.zenMode != Global.ZEN_MODE_OFF) { + applyCustomPolicy(policy, automaticRule); + } if (Flags.modesApi()) { deviceEffectsBuilder.add(automaticRule.zenDeviceEffects); } diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig index 8e79922a996a..49db7fc280d9 100644 --- a/services/core/java/com/android/server/notification/flags.aconfig +++ b/services/core/java/com/android/server/notification/flags.aconfig @@ -50,3 +50,10 @@ flag { # Referenced in WM where WM starts before DeviceConfig is_fixed_read_only: true } + +flag { + name: "notification_reduce_messagequeue_usage" + namespace: "systemui" + description: "When this flag is on, NMS will no longer call removeMessage() and hasCallbacks() on Handler" + bug: "311051285" +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/pdb/TEST_MAPPING b/services/core/java/com/android/server/pdb/TEST_MAPPING index 1aa8601bdcf9..9e9802354a4d 100644 --- a/services/core/java/com/android/server/pdb/TEST_MAPPING +++ b/services/core/java/com/android/server/pdb/TEST_MAPPING @@ -1,5 +1,5 @@ { - "postsubmit": [ + "presubmit": [ { "name": "FrameworksServicesTests", "options": [ diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 3cb2420cd223..0555d90779e9 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -78,6 +78,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.ComponentInfo; +import android.content.pm.Flags; import android.content.pm.InstallSourceInfo; import android.content.pm.InstantAppRequest; import android.content.pm.InstantAppResolveInfo; @@ -1511,6 +1512,13 @@ public class ComputerEngine implements Computer { packageInfo.packageName = packageInfo.applicationInfo.packageName = resolveExternalPackageName(p); + if (Flags.provideInfoOfApkInApex()) { + final String apexModuleName = ps.getApexModuleName(); + if (apexModuleName != null) { + packageInfo.setApexPackageName( + mApexManager.getActivePackageNameForApexModuleName(apexModuleName)); + } + } return packageInfo; } else if ((flags & (MATCH_UNINSTALLED_PACKAGES | MATCH_ARCHIVED_PACKAGES)) != 0 && PackageUserStateUtils.isAvailable(state, flags)) { diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java index 230f5558b37d..6561d462e716 100644 --- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java +++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java @@ -18,6 +18,7 @@ package com.android.server.pm; import android.annotation.NonNull; import android.content.Context; +import android.content.pm.Flags; import android.content.pm.IPackageManager; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; @@ -165,6 +166,10 @@ public class ModuleInfoProvider { mi.setApexModuleName( mApexManager.getApexModuleNameForPackageName(modulePackageName)); + if (Flags.provideInfoOfApkInApex()) { + mi.setApkInApexPackageNames(mApexManager.getApksInApex(modulePackageName)); + } + mModuleInfo.put(modulePackageName, mi); } } catch (XmlPullParserException | IOException e) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 2305d6c9fba9..75b453184db8 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2285,6 +2285,11 @@ public class UserManagerService extends IUserManager.Stub { throw new SecurityException("You need MANAGE_USERS permission to query if u=" + userId + " is a demo user"); } + + if (SystemProperties.getBoolean("ro.boot.arc_demo_mode", false)) { + return true; + } + synchronized (mUsersLock) { UserInfo userInfo = getUserInfoLU(userId); return userInfo != null && userInfo.isDemo(); 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 10e6edc2941f..d683855cc5d9 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1229,11 +1229,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { sPlatformPermissions.put(permission, permissionInfo); } } catch (PackageManager.NameNotFoundException ignored) { - // TODO(b/302609140): Remove extra logging after this issue is diagnosed. - if (permission.equals(Manifest.permission.BLUETOOTH_CONNECT)) { - Slog.e(LOG_TAG, "BLUETOOTH_CONNECT permission hard denied as package" - + " not found when retrieving permission info"); - } return PermissionChecker.PERMISSION_HARD_DENIED; } } @@ -1353,34 +1348,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { // way we can avoid the datasource creating an attribution context for every call. if (!(fromDatasource && current.equals(attributionSource)) && next != null && !current.isTrusted(context)) { - // TODO(b/302609140): Remove extra logging after this issue is diagnosed. - if (permission.equals(Manifest.permission.BLUETOOTH_CONNECT)) { - Slog.e(LOG_TAG, "BLUETOOTH_CONNECT permission hard denied as " - + current + " attribution source isn't a data source and " - + current + " isn't trusted"); - } return PermissionChecker.PERMISSION_HARD_DENIED; } // If we already checked the permission for this one, skip the work if (!skipCurrentChecks && !checkPermission(context, permissionManagerServiceInt, permission, current)) { - // TODO(b/302609140): Remove extra logging after this issue is diagnosed. - if (permission.equals(Manifest.permission.BLUETOOTH_CONNECT)) { - Slog.e(LOG_TAG, "BLUETOOTH_CONNECT permission hard denied as we" - + " aren't skipping permission checks and permission check returns" - + " false for " + current); - } return PermissionChecker.PERMISSION_HARD_DENIED; } if (next != null && !checkPermission(context, permissionManagerServiceInt, permission, next)) { - // TODO(b/302609140): Remove extra logging after this issue is diagnosed. - if (permission.equals(Manifest.permission.BLUETOOTH_CONNECT)) { - Slog.e(LOG_TAG, "BLUETOOTH_CONNECT permission hard denied as" - + " permission check returns false for next source " + next); - } return PermissionChecker.PERMISSION_HARD_DENIED; } @@ -1697,12 +1675,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { final AttributionSource resolvedAttributionSource = resolveAttributionSource( context, accessorSource); if (resolvedAttributionSource.getPackageName() == null) { - // TODO(b/302609140): Remove extra logging after this issue is diagnosed. - if (op == OP_BLUETOOTH_CONNECT) { - Slog.e(LOG_TAG, "BLUETOOTH_CONNECT permission hard denied as resolved" - + "package name for " + resolvedAttributionSource + " returned" - + " null"); - } return AppOpsManager.MODE_ERRORED; } int notedOp = op; @@ -1716,13 +1688,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (attributedOp != AppOpsManager.OP_NONE && attributedOp != op) { checkedOpResult = appOpsManager.checkOpNoThrow(op, resolvedAttributionSource); if (checkedOpResult == MODE_ERRORED) { - // TODO(b/302609140): Remove extra logging after this issue is diagnosed. - if (op == OP_BLUETOOTH_CONNECT) { - Slog.e(LOG_TAG, "BLUETOOTH_CONNECT permission hard denied as" - + " checkOp for resolvedAttributionSource " - + resolvedAttributionSource + " and op " + op - + " returned MODE_ERRORED"); - } return checkedOpResult; } notedOp = attributedOp; diff --git a/services/core/java/com/android/server/utils/AnrTimer.java b/services/core/java/com/android/server/utils/AnrTimer.java index 7b5192c4bd6b..e3aba0f6bc6f 100644 --- a/services/core/java/com/android/server/utils/AnrTimer.java +++ b/services/core/java/com/android/server/utils/AnrTimer.java @@ -16,21 +16,30 @@ package com.android.server.utils; +import static android.text.TextUtils.formatSimple; + import android.annotation.NonNull; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.os.Trace; +import android.text.TextUtils; import android.text.format.TimeMigrationUtils; +import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.Log; +import android.util.LongSparseArray; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.Keep; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.RingBuffer; +import java.lang.ref.WeakReference; import java.io.PrintWriter; import java.util.Arrays; +import java.util.ArrayList; import java.util.Objects; /** @@ -60,9 +69,14 @@ import java.util.Objects; * is restarted with the extension timeout. If extensions are disabled or if the extension is zero, * the client process is notified of the expiration. * + * <p>Instances use native resources but not system resources when the feature is enabled. + * Instances should be explicitly closed unless they are being closed as part of process + * exit. (So, instances in system server generally need not be explicitly closed since they are + * created during process start and will last until process exit.) + * * @hide */ -public class AnrTimer<V> { +public class AnrTimer<V> implements AutoCloseable { /** * The log tag. @@ -87,6 +101,12 @@ public class AnrTimer<V> { private static final long TRACE_TAG = Trace.TRACE_TAG_ACTIVITY_MANAGER; /** + * Enable tracing from the time a timer expires until it is accepted or discarded. This is + * used to diagnose long latencies in the client. + */ + private static final boolean ENABLE_TRACING = false; + + /** * Return true if the feature is enabled. By default, the value is take from the Flags class * but it can be changed for local testing. */ @@ -103,6 +123,9 @@ public class AnrTimer<V> { } } + /** The default injector. */ + private static final Injector sDefaultInjector = new Injector(); + /** * An error is defined by its issue, the operation that detected the error, the tag of the * affected service, a short stack of the bad call, and the stringified arg associated with @@ -160,41 +183,46 @@ public class AnrTimer<V> { /** A lock for the AnrTimer instance. */ private final Object mLock = new Object(); - /** - * The total number of timers started. - */ + /** The map from client argument to the associated timer ID. */ + @GuardedBy("mLock") + private final ArrayMap<V, Integer> mTimerIdMap = new ArrayMap<>(); + + /** Reverse map from timer ID to client argument. */ + @GuardedBy("mLock") + private final SparseArray<V> mTimerArgMap = new SparseArray<>(); + + /** The highwater mark of started, but not closed, timers. */ + @GuardedBy("mLock") + private int mMaxStarted = 0; + + /** The total number of timers started. */ @GuardedBy("mLock") private int mTotalStarted = 0; - /** - * The total number of errors detected. - */ + /** The total number of errors detected. */ @GuardedBy("mLock") private int mTotalErrors = 0; - /** - * The handler for messages sent from this instance. - */ + /** The total number of timers that have expired. */ + @GuardedBy("mLock") + private int mTotalExpired = 0; + + /** The handler for messages sent from this instance. */ private final Handler mHandler; - /** - * The message type for messages sent from this interface. - */ + /** The message type for messages sent from this interface. */ private final int mWhat; - /** - * A label that identifies the AnrTimer associated with a Timer in log messages. - */ + /** A label that identifies the AnrTimer associated with a Timer in log messages. */ private final String mLabel; - /** - * Whether this timer instance supports extending timeouts. - */ + /** Whether this timer instance supports extending timeouts. */ private final boolean mExtend; - /** - * The top-level switch for the feature enabled or disabled. - */ + /** The injector used to create this instance. This is only used for testing. */ + private final Injector mInjector; + + /** The top-level switch for the feature enabled or disabled. */ private final FeatureSwitch mFeature; /** @@ -223,7 +251,27 @@ public class AnrTimer<V> { mWhat = what; mLabel = label; mExtend = extend; - mFeature = new FeatureDisabled(); + mInjector = injector; + boolean enabled = mInjector.anrTimerServiceEnabled() && nativeTimersSupported(); + mFeature = createFeatureSwitch(enabled); + } + + // Return the correct feature. FeatureEnabled is returned if and only if the feature is + // flag-enabled and if the native shadow was successfully created. Otherwise, FeatureDisabled + // is returned. + private FeatureSwitch createFeatureSwitch(boolean enabled) { + if (!enabled) { + return new FeatureDisabled(); + } else { + try { + return new FeatureEnabled(); + } catch (RuntimeException e) { + // Something went wrong in the native layer. Log the error and fall back on the + // feature-disabled logic. + Log.e(TAG, e.toString()); + return new FeatureDisabled(); + } + } } /** @@ -245,7 +293,7 @@ public class AnrTimer<V> { * @param extend A flag to indicate if expired timers can be granted extensions. */ public AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) { - this(handler, what, label, extend, new Injector()); + this(handler, what, label, extend, sDefaultInjector); } /** @@ -272,19 +320,44 @@ public class AnrTimer<V> { } /** + * Start a trace on the timer. The trace is laid down in the AnrTimerTrack. + */ + private void traceBegin(int timerId, int pid, int uid, String what) { + if (ENABLE_TRACING) { + final String label = formatSimple("%s(%d,%d,%s)", what, pid, uid, mLabel); + final int cookie = timerId; + Trace.asyncTraceForTrackBegin(TRACE_TAG, TRACK, label, cookie); + } + } + + /** + * End a trace on the timer. + */ + private void traceEnd(int timerId) { + if (ENABLE_TRACING) { + final int cookie = timerId; + Trace.asyncTraceForTrackEnd(TRACE_TAG, TRACK, cookie); + } + } + + /** * The FeatureSwitch class provides a quick switch between feature-enabled behavior and * feature-disabled behavior. */ private abstract class FeatureSwitch { abstract void start(@NonNull V arg, int pid, int uid, long timeoutMs); - abstract void cancel(@NonNull V arg); + abstract boolean cancel(@NonNull V arg); - abstract void accept(@NonNull V arg); + abstract boolean accept(@NonNull V arg); - abstract void discard(@NonNull V arg); + abstract boolean discard(@NonNull V arg); abstract boolean enabled(); + + abstract void dump(PrintWriter pw, boolean verbose); + + abstract void close(); } /** @@ -301,18 +374,21 @@ public class AnrTimer<V> { /** Cancel a timer by removing the message from the client's handler. */ @Override - void cancel(@NonNull V arg) { + boolean cancel(@NonNull V arg) { mHandler.removeMessages(mWhat, arg); + return true; } /** accept() is a no-op when the feature is disabled. */ @Override - void accept(@NonNull V arg) { + boolean accept(@NonNull V arg) { + return true; } /** discard() is a no-op when the feature is disabled. */ @Override - void discard(@NonNull V arg) { + boolean discard(@NonNull V arg) { + return true; } /** The feature is not enabled. */ @@ -320,12 +396,179 @@ public class AnrTimer<V> { boolean enabled() { return false; } + + /** dump() is a no-op when the feature is disabled. */ + @Override + void dump(PrintWriter pw, boolean verbose) { + } + + /** close() is a no-op when the feature is disabled. */ + @Override + void close() { + } + } + + /** + * A static list of AnrTimer instances. The list is traversed by dumpsys. Only instances + * using native resources are included. + */ + @GuardedBy("sAnrTimerList") + private static final LongSparseArray<WeakReference<AnrTimer>> sAnrTimerList = + new LongSparseArray<>(); + + /** + * The FeatureEnabled class enables the AnrTimer logic. It is used when the AnrTimer service + * is enabled via Flags.anrTimerServiceEnabled. + */ + private class FeatureEnabled extends FeatureSwitch { + + /** + * The native timer that supports this instance. The value is set to non-zero when the + * native timer is created and it is set back to zero when the native timer is freed. + */ + private long mNative = 0; + + /** Fetch the native tag (an integer) for the given label. */ + FeatureEnabled() { + mNative = nativeAnrTimerCreate(mLabel); + if (mNative == 0) throw new IllegalArgumentException("unable to create native timer"); + synchronized (sAnrTimerList) { + sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this)); + } + } + + /** + * Start a timer. + */ + @Override + void start(@NonNull V arg, int pid, int uid, long timeoutMs) { + synchronized (mLock) { + if (mTimerIdMap.containsKey(arg)) { + // There is an existing timer. Cancel it. + cancel(arg); + } + int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs, mExtend); + if (timerId > 0) { + mTimerIdMap.put(arg, timerId); + mTimerArgMap.put(timerId, arg); + mTotalStarted++; + mMaxStarted = Math.max(mMaxStarted, mTimerIdMap.size()); + } else { + throw new RuntimeException("unable to start timer"); + } + } + } + + /** + * Cancel a timer. No error is reported if the timer is not found because some clients + * cancel timers from common code that runs even if a timer was never started. + */ + @Override + boolean cancel(@NonNull V arg) { + synchronized (mLock) { + Integer timer = removeLocked(arg); + if (timer == null) { + return false; + } + if (!nativeAnrTimerCancel(mNative, timer)) { + // There may be an expiration message in flight. Cancel it. + mHandler.removeMessages(mWhat, arg); + return false; + } + return true; + } + } + + /** + * Accept a timer in the framework-level handler. The timeout has been accepted and the + * timeout handler is executing. + */ + @Override + boolean accept(@NonNull V arg) { + synchronized (mLock) { + Integer timer = removeLocked(arg); + if (timer == null) { + notFoundLocked("accept", arg); + return false; + } + nativeAnrTimerAccept(mNative, timer); + traceEnd(timer); + return true; + } + } + + /** + * Discard a timer in the framework-level handler. For whatever reason, the timer is no + * longer interesting. No statistics are collected. Return false if the time was not + * found. + */ + @Override + boolean discard(@NonNull V arg) { + synchronized (mLock) { + Integer timer = removeLocked(arg); + if (timer == null) { + notFoundLocked("discard", arg); + return false; + } + nativeAnrTimerDiscard(mNative, timer); + traceEnd(timer); + return true; + } + } + + /** The feature is enabled. */ + @Override + boolean enabled() { + return true; + } + + /** Dump statistics from the native layer. */ + @Override + void dump(PrintWriter pw, boolean verbose) { + synchronized (mLock) { + if (mNative != 0) { + nativeAnrTimerDump(mNative, verbose); + } else { + pw.println("closed"); + } + } + } + + /** Free native resources. */ + @Override + void close() { + // Remove self from the list of active timers. + synchronized (sAnrTimerList) { + sAnrTimerList.remove(mNative); + } + synchronized (mLock) { + if (mNative != 0) nativeAnrTimerClose(mNative); + mNative = 0; + } + } + + /** + * Delete the entries associated with arg from the maps and return the ID of the timer, if + * any. + */ + @GuardedBy("mLock") + private Integer removeLocked(V arg) { + Integer r = mTimerIdMap.remove(arg); + if (r != null) { + synchronized (mTimerArgMap) { + mTimerArgMap.remove(r); + } + } + return r; + } } /** * Start a timer associated with arg. The same object must be used to cancel, accept, or * discard a timer later. If a timer already exists with the same arg, then the existing timer - * is canceled and a new timer is created. + * is canceled and a new timer is created. The timeout is signed but negative delays are + * nonsensical. Rather than throw an exception, timeouts less than 0ms are forced to 0ms. This + * allows a client to deliver an immediate timeout via the AnrTimer. * * @param arg The key by which the timer is known. This is never examined or modified. * @param pid The Linux process ID of the target being timed. @@ -333,25 +576,39 @@ public class AnrTimer<V> { * @param timeoutMs The timer timeout, in milliseconds. */ public void start(@NonNull V arg, int pid, int uid, long timeoutMs) { + if (timeoutMs < 0) timeoutMs = 0; mFeature.start(arg, pid, uid, timeoutMs); } /** * Cancel the running timer associated with arg. The timer is forgotten. If the timer has - * expired, the call is treated as a discard. No errors are reported if the timer does not - * exist or if the timer has expired. + * expired, the call is treated as a discard. The function returns true if a running timer was + * found, and false if an expired timer was found or if no timer was found. After this call, + * the timer does not exist. + * + * Note: the return value is always true if the feature is not enabled. + * + * @param arg The key by which the timer is known. This is never examined or modified. + * @return True if a running timer was canceled. */ - public void cancel(@NonNull V arg) { - mFeature.cancel(arg); + public boolean cancel(@NonNull V arg) { + return mFeature.cancel(arg); } /** * Accept the expired timer associated with arg. This indicates that the caller considers the - * timer expiration to be a true ANR. (See {@link #discard} for an alternate response.) It is - * an error to accept a running timer, however the running timer will be canceled. + * timer expiration to be a true ANR. (See {@link #discard} for an alternate response.) The + * function returns true if an expired timer was found and false if a running timer was found or + * if no timer was found. After this call, the timer does not exist. It is an error to accept + * a running timer, however, the running timer will be canceled. + * + * Note: the return value is always true if the feature is not enabled. + * + * @param arg The key by which the timer is known. This is never examined or modified. + * @return True if an expired timer was accepted. */ - public void accept(@NonNull V arg) { - mFeature.accept(arg); + public boolean accept(@NonNull V arg) { + return mFeature.accept(arg); } /** @@ -359,11 +616,57 @@ public class AnrTimer<V> { * timer expiration to be a false ANR. ((See {@link #accept} for an alternate response.) One * reason to discard an expired timer is if the process being timed was also being debugged: * such a process could be stopped at a breakpoint and its failure to respond would not be an - * error. It is an error to discard a running timer, however the running timer will be - * canceled. + * error. After this call thie timer does not exist. It is an error to discard a running timer, + * however the running timer will be canceled. + * + * Note: the return value is always true if the feature is not enabled. + * + * @param arg The key by which the timer is known. This is never examined or modified. + * @return True if an expired timer was discarded. + */ + public boolean discard(@NonNull V arg) { + return mFeature.discard(arg); + } + + /** + * The notifier that a timer has fired. The timerId and original pid/uid are supplied. This + * method is called from native code. This method takes mLock so that a timer cannot expire + * in the middle of another operation (like start or cancel). + */ + @Keep + private boolean expire(int timerId, int pid, int uid) { + traceBegin(timerId, pid, uid, "expired"); + V arg = null; + synchronized (mLock) { + arg = mTimerArgMap.get(timerId); + if (arg == null) { + Log.e(TAG, formatSimple("failed to expire timer %s:%d : arg not found", + mLabel, timerId)); + mTotalErrors++; + return false; + } + mTotalExpired++; + } + mHandler.sendMessage(Message.obtain(mHandler, mWhat, arg)); + return true; + } + + /** + * Close the object and free any native resources. */ - public void discard(@NonNull V arg) { - mFeature.discard(arg); + public void close() { + mFeature.close(); + } + + /** + * Ensure any native resources are freed when the object is GC'ed. Best practice is to close + * the object explicitly, but overriding finalize() avoids accidental leaks. + */ + @SuppressWarnings("Finalize") + @Override + protected void finalize() throws Throwable { + close(); + super.finalize(); } /** @@ -373,8 +676,11 @@ public class AnrTimer<V> { synchronized (mLock) { pw.format("timer: %s\n", mLabel); pw.increaseIndent(); - pw.format("started=%d errors=%d\n", mTotalStarted, mTotalErrors); + pw.format("started=%d maxStarted=%d running=%d expired=%d errors=%d\n", + mTotalStarted, mMaxStarted, mTimerIdMap.size(), + mTotalExpired, mTotalErrors); pw.decreaseIndent(); + mFeature.dump(pw, false); } } @@ -386,6 +692,13 @@ public class AnrTimer<V> { } /** + * The current time in milliseconds. + */ + private static long now() { + return SystemClock.uptimeMillis(); + } + + /** * Dump all errors to the output stream. */ private static void dumpErrors(IndentingPrintWriter ipw) { @@ -422,23 +735,89 @@ public class AnrTimer<V> { mTotalErrors++; } - /** - * Log an error about a timer not found. - */ + /** Record an error about a timer not found. */ @GuardedBy("mLock") private void notFoundLocked(String operation, Object arg) { recordErrorLocked(operation, "notFound", arg); } - /** - * Dumpsys output. - */ - public static void dump(@NonNull PrintWriter pw, boolean verbose) { + /** Dumpsys output, allowing for overrides. */ + @VisibleForTesting + static void dump(@NonNull PrintWriter pw, boolean verbose, @NonNull Injector injector) { + if (!injector.anrTimerServiceEnabled()) return; + final IndentingPrintWriter ipw = new IndentingPrintWriter(pw); ipw.println("AnrTimer statistics"); ipw.increaseIndent(); + synchronized (sAnrTimerList) { + final int size = sAnrTimerList.size(); + ipw.println("reporting " + size + " timers"); + for (int i = 0; i < size; i++) { + AnrTimer a = sAnrTimerList.valueAt(i).get(); + if (a != null) a.dump(ipw); + } + } if (verbose) dumpErrors(ipw); ipw.format("AnrTimerEnd\n"); ipw.decreaseIndent(); } + + /** Dumpsys output. There is no output if the feature is not enabled. */ + public static void dump(@NonNull PrintWriter pw, boolean verbose) { + dump(pw, verbose, sDefaultInjector); + } + + /** + * Return true if the native timers are supported. Native timers are supported if the method + * nativeAnrTimerSupported() can be executed and it returns true. + */ + private static boolean nativeTimersSupported() { + try { + return nativeAnrTimerSupported(); + } catch (java.lang.UnsatisfiedLinkError e) { + return false; + } + } + + /** + * Native methods + */ + + /** Return true if the native AnrTimer code is operational. */ + private static native boolean nativeAnrTimerSupported(); + + /** + * Create a new native timer with the given key and name. The key is not used by the native + * code but it is returned to the Java layer in the expiration handler. The name is only for + * logging. Unlike the other methods, this is an instance method: the "this" parameter is + * passed into the native layer. + */ + private native long nativeAnrTimerCreate(String name); + + /** Release the native resources. No further operations are premitted. */ + private static native int nativeAnrTimerClose(long service); + + /** Start a timer and return its ID. Zero is returned on error. */ + private static native int nativeAnrTimerStart(long service, int pid, int uid, long timeoutMs, + boolean extend); + + /** + * Cancel a timer by ID. Return true if the timer was running and canceled. Return false if + * the timer was not found or if the timer had already expired. + */ + private static native boolean nativeAnrTimerCancel(long service, int timerId); + + /** Accept an expired timer by ID. Return true if the timer was found. */ + private static native boolean nativeAnrTimerAccept(long service, int timerId); + + /** Discard an expired timer by ID. Return true if the timer was found. */ + private static native boolean nativeAnrTimerDiscard(long service, int timerId); + + /** Prod the native library to log a few statistics. */ + private static native void nativeAnrTimerDump(long service, boolean verbose); + + // This is not a native method but it is a native interface, in the sense that it is called from + // the native layer to report timer expiration. The function must return true if the expiration + // message is delivered to the upper layers and false if it could not be delivered. + // private boolean expire(int timerId, int pid, int uid); } diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java index 59b55bf74df3..0a7872f5c25f 100644 --- a/services/core/java/com/android/server/vibrator/VibrationScaler.java +++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java @@ -17,11 +17,13 @@ package com.android.server.vibrator; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.hardware.vibrator.V1_0.EffectStrength; import android.os.IExternalVibratorService; import android.os.VibrationEffect; import android.os.Vibrator; +import android.os.vibrator.Flags; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.VibrationEffectSegment; import android.util.Slog; @@ -56,6 +58,8 @@ final class VibrationScaler { private final VibrationSettings mSettingsController; private final int mDefaultVibrationAmplitude; + private SparseArray<Float> mAdaptiveHapticsScales; + VibrationScaler(Context context, VibrationSettings settingsController) { mSettingsController = settingsController; mDefaultVibrationAmplitude = context.getResources().getInteger( @@ -140,6 +144,15 @@ final class VibrationScaler { if (scaleLevel != null) { segment = segment.scale(scaleLevel.factor); } + + // If adaptive haptics scaling is available for this usage, apply it to the segment. + if (Flags.adaptiveHapticsEnabled() + && mAdaptiveHapticsScales != null && mAdaptiveHapticsScales.size() > 0 + && mAdaptiveHapticsScales.contains(usageHint)) { + float adaptiveScale = mAdaptiveHapticsScales.get(usageHint); + segment = segment.scale(adaptiveScale); + } + segments.set(i, segment); } if (segments.equals(composedEffect.getSegments())) { @@ -173,6 +186,16 @@ final class VibrationScaler { return prebaked.applyEffectStrength(newEffectStrength); } + /** + * Updates the adaptive haptics scales. + * @param scales the new vibration scales to apply. + * + * @hide + */ + public void updateAdaptiveHapticsScales(@Nullable SparseArray<Float> scales) { + mAdaptiveHapticsScales = scales; + } + /** Mapping of Vibrator.VIBRATION_INTENSITY_* values to {@link EffectStrength}. */ private static int intensityToEffectStrength(int intensity) { switch (intensity) { diff --git a/services/core/java/com/android/server/vibrator/VibratorControlService.java b/services/core/java/com/android/server/vibrator/VibratorControlService.java index 2eeb903bb551..9d75249abdd9 100644 --- a/services/core/java/com/android/server/vibrator/VibratorControlService.java +++ b/services/core/java/com/android/server/vibrator/VibratorControlService.java @@ -16,14 +16,26 @@ package com.android.server.vibrator; +import static android.os.VibrationAttributes.USAGE_ALARM; +import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST; +import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK; +import static android.os.VibrationAttributes.USAGE_MEDIA; +import static android.os.VibrationAttributes.USAGE_NOTIFICATION; +import static android.os.VibrationAttributes.USAGE_RINGTONE; +import static android.os.VibrationAttributes.USAGE_TOUCH; +import static android.os.VibrationAttributes.USAGE_UNKNOWN; + import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SuppressLint; import android.frameworks.vibrator.IVibratorControlService; import android.frameworks.vibrator.IVibratorController; +import android.frameworks.vibrator.ScaleParam; import android.frameworks.vibrator.VibrationParam; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import android.util.SparseArray; import java.util.Objects; @@ -37,10 +49,13 @@ public final class VibratorControlService extends IVibratorControlService.Stub { private static final String TAG = "VibratorControlService"; private final VibratorControllerHolder mVibratorControllerHolder; + private final VibrationScaler mVibrationScaler; private final Object mLock; - public VibratorControlService(VibratorControllerHolder vibratorControllerHolder, Object lock) { + public VibratorControlService(VibratorControllerHolder vibratorControllerHolder, + VibrationScaler vibrationScaler, Object lock) { mVibratorControllerHolder = vibratorControllerHolder; + mVibrationScaler = vibrationScaler; mLock = lock; } @@ -70,25 +85,62 @@ public final class VibratorControlService extends IVibratorControlService.Stub { + "controller doesn't match the registered one. " + this); return; } + updateAdaptiveHapticsScales(/* params= */ null); mVibratorControllerHolder.setVibratorController(null); } } @Override - public void setVibrationParams( - @SuppressLint("ArrayReturn") VibrationParam[] params, IVibratorController token) - throws RemoteException { - // TODO(b/305939964): Add set vibration implementation. + public void setVibrationParams(@SuppressLint("ArrayReturn") VibrationParam[] params, + @NonNull IVibratorController token) throws RemoteException { + Objects.requireNonNull(token); + + synchronized (mLock) { + if (mVibratorControllerHolder.getVibratorController() == null) { + Slog.w(TAG, "Received request to set VibrationParams for IVibratorController = " + + token + ", but no controller was previously registered. Request " + + "Ignored."); + return; + } + if (!Objects.equals(mVibratorControllerHolder.getVibratorController().asBinder(), + token.asBinder())) { + Slog.wtf(TAG, "Failed to set new VibrationParams. The provided " + + "controller doesn't match the registered one. " + this); + return; + } + + updateAdaptiveHapticsScales(params); + } } @Override - public void clearVibrationParams(int types, IVibratorController token) throws RemoteException { - // TODO(b/305939964): Add clear vibration implementation. + public void clearVibrationParams(int types, @NonNull IVibratorController token) + throws RemoteException { + Objects.requireNonNull(token); + + synchronized (mLock) { + if (mVibratorControllerHolder.getVibratorController() == null) { + Slog.w(TAG, "Received request to clear VibrationParams for IVibratorController = " + + token + ", but no controller was previously registered. Request " + + "Ignored."); + return; + } + if (!Objects.equals(mVibratorControllerHolder.getVibratorController().asBinder(), + token.asBinder())) { + Slog.wtf(TAG, "Failed to clear VibrationParams. The provided " + + "controller doesn't match the registered one. " + this); + return; + } + //TODO(305942827): Update this method to only clear the specified vibration types. + // Perhaps look into whether it makes more sense to have this clear all scales and + // rely on setVibrationParams for clearing the scales for specific vibrations. + updateAdaptiveHapticsScales(/* params= */ null); + } } @Override public void onRequestVibrationParamsComplete( - IBinder requestToken, @SuppressLint("ArrayReturn") VibrationParam[] result) + @NonNull IBinder requestToken, @SuppressLint("ArrayReturn") VibrationParam[] result) throws RemoteException { // TODO(305942827): Cache the vibration params in VibrationScaler } @@ -102,4 +154,52 @@ public final class VibratorControlService extends IVibratorControlService.Stub { public String getInterfaceHash() throws RemoteException { return this.HASH; } + + /** + * Extracts the vibration scales and caches them in {@link VibrationScaler}. + * + * @param params the new vibration params to cache. + */ + private void updateAdaptiveHapticsScales(@Nullable VibrationParam[] params) { + if (params == null || params.length == 0) { + mVibrationScaler.updateAdaptiveHapticsScales(null); + return; + } + + SparseArray<Float> vibrationScales = new SparseArray<>(); + for (int i = 0; i < params.length; i++) { + ScaleParam scaleParam = params[i].getScale(); + extractVibrationScales(scaleParam, vibrationScales); + } + mVibrationScaler.updateAdaptiveHapticsScales(vibrationScales); + } + + /** + * Extracts the vibration scales and map them to their corresponding + * {@link android.os.VibrationAttributes} usages. + */ + private void extractVibrationScales(ScaleParam scaleParam, SparseArray<Float> vibrationScales) { + if ((ScaleParam.TYPE_ALARM & scaleParam.typesMask) != 0) { + vibrationScales.put(USAGE_ALARM, scaleParam.scale); + } + + if ((ScaleParam.TYPE_NOTIFICATION & scaleParam.typesMask) != 0) { + vibrationScales.put(USAGE_NOTIFICATION, scaleParam.scale); + vibrationScales.put(USAGE_COMMUNICATION_REQUEST, scaleParam.scale); + } + + if ((ScaleParam.TYPE_RINGTONE & scaleParam.typesMask) != 0) { + vibrationScales.put(USAGE_RINGTONE, scaleParam.scale); + } + + if ((ScaleParam.TYPE_MEDIA & scaleParam.typesMask) != 0) { + vibrationScales.put(USAGE_MEDIA, scaleParam.scale); + vibrationScales.put(USAGE_UNKNOWN, scaleParam.scale); + } + + if ((ScaleParam.TYPE_INTERACTIVE & scaleParam.typesMask) != 0) { + vibrationScales.put(USAGE_TOUCH, scaleParam.scale); + vibrationScales.put(USAGE_HARDWARE_FEEDBACK, scaleParam.scale); + } + } } diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index fc824abd80f5..2c1ab955514e 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -273,7 +273,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService()); if (ServiceManager.isDeclared(VIBRATOR_CONTROL_SERVICE)) { injector.addService(VIBRATOR_CONTROL_SERVICE, - new VibratorControlService(new VibratorControllerHolder(), mLock)); + new VibratorControlService(new VibratorControllerHolder(), mVibrationScaler, + mLock)); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b1ae0a23d7c9..febcc052064e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -497,10 +497,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private final boolean componentSpecified; // did caller specify an explicit component? final boolean rootVoiceInteraction; // was this the root activity of a voice interaction? - private CharSequence nonLocalizedLabel; // the label information from the package mgr. - private int labelRes; // the label information from the package mgr. - private int icon; // resource identifier of activity's icon. - private int theme; // resource identifier of activity's theme. + private final int theme; // resource identifier of activity's theme. private Task task; // the task this is in. private long createTime = System.currentTimeMillis(); long lastVisibleTime; // last time this activity became visible @@ -508,7 +505,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A long launchTickTime; // base time for launch tick messages long topResumedStateLossTime; // last time we reported top resumed state loss to an activity // Last configuration reported to the activity in the client process. - private MergedConfiguration mLastReportedConfiguration; + private final MergedConfiguration mLastReportedConfiguration; private int mLastReportedDisplayId; boolean mLastReportedMultiWindowMode; boolean mLastReportedPictureInPictureMode; @@ -1060,17 +1057,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity); pw.print(prefix); pw.print("mActivityComponent="); pw.println(mActivityComponent.flattenToShortString()); - if (info != null && info.applicationInfo != null) { - final ApplicationInfo appInfo = info.applicationInfo; - pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir); - if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) { - pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir); - } - pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir); - if (appInfo.splitSourceDirs != null) { - pw.print(prefix); pw.print("splitDir="); - pw.println(Arrays.toString(appInfo.splitSourceDirs)); - } + final ApplicationInfo appInfo = info.applicationInfo; + pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir); + if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) { + pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir); + } + pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir); + if (appInfo.splitSourceDirs != null) { + pw.print(prefix); pw.print("splitDir="); + pw.println(Arrays.toString(appInfo.splitSourceDirs)); } pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded); pw.print(" componentSpecified="); pw.print(componentSpecified); @@ -1081,8 +1076,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } pw.print(prefix); pw.print("compat="); pw.print(mAtmService.compatibilityInfoForPackageLocked(info.applicationInfo)); - pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes)); - pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); pw.print(" theme=0x"); pw.println(Integer.toHexString(theme)); pw.println(prefix + "mLastReportedConfigurations:"); mLastReportedConfiguration.dump(pw, prefix + " "); @@ -2159,14 +2152,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A sConstrainDisplayApisConfig = new ConstrainDisplayApisConfig(); } stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0; - nonLocalizedLabel = aInfo.nonLocalizedLabel; - labelRes = aInfo.labelRes; - if (nonLocalizedLabel == null && labelRes == 0) { - ApplicationInfo app = aInfo.applicationInfo; - nonLocalizedLabel = app.nonLocalizedLabel; - labelRes = app.labelRes; - } - icon = aInfo.getIconResource(); theme = aInfo.getThemeResource(); if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null && (aInfo.applicationInfo.uid == SYSTEM_UID @@ -4329,7 +4314,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mTaskSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this); mTaskSupervisor.mStoppingActivities.remove(this); mLetterboxUiController.destroy(); - waitingToShow = false; // Defer removal of this activity when either a child is animating, or app transition is on // going. App transition animation might be applied on the parent task not on the activity, @@ -5403,7 +5387,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final DisplayContent displayContent = getDisplayContent(); displayContent.mOpeningApps.remove(this); displayContent.mClosingApps.remove(this); - waitingToShow = false; setVisibleRequested(visible); mLastDeferHidingClient = deferHidingClient; @@ -5428,25 +5411,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // stopped, then we need to set up to wait for its windows to be ready. if (!isVisible() || mAppStopped) { clearAllDrawn(); - - // If the app was already visible, don't reset the waitingToShow state. - if (!isVisible()) { - waitingToShow = true; - - // If the client isn't hidden, we don't need to reset the drawing state. - if (!isClientVisible()) { - // Let's reset the draw state in order to prevent the starting window to be - // immediately dismissed when the app still has the surface. - forAllWindows(w -> { - if (w.mWinAnimator.mDrawState == HAS_DRAWN) { - w.mWinAnimator.resetDrawState(); - - // Force add to mResizingWindows, so that we are guaranteed to get - // another reportDrawn callback. - w.forceReportingResized(); - } - }, true /* traverseTopToBottom */); - } + // Reset the draw state in order to prevent the starting window to be immediately + // dismissed when the app still has the surface. + if (!isVisible() && !isClientVisible()) { + forAllWindows(w -> { + if (w.mWinAnimator.mDrawState == HAS_DRAWN) { + w.mWinAnimator.resetDrawState(); + // Force add to mResizingWindows, so the window will report drawn. + w.forceReportingResized(); + } + }, true /* traverseTopToBottom */); } } @@ -8067,7 +8041,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ @Override int getOrientation(int candidate) { - if (shouldIgnoreOrientationRequests()) { + if (finishing || shouldIgnoreOrientationRequests()) { return SCREEN_ORIENTATION_UNSET; } @@ -8081,8 +8055,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // The {@link ActivityRecord} should only specify an orientation when it is not closing. // Allowing closing {@link ActivityRecord} to participate can lead to an Activity in another // task being started in the wrong orientation during the transition. - if (!getDisplayContent().mClosingApps.contains(this) - && (isVisibleRequested() || getDisplayContent().mOpeningApps.contains(this))) { + if (isVisibleRequested()) { return getOverrideOrientation(); } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index d90d017a5570..13f71521c240 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -993,17 +993,6 @@ class ActivityStarter { } } - if (Flags.archiving()) { - PackageArchiver packageArchiver = mService - .getPackageManagerInternalLocked() - .getPackageArchiver(); - if (packageArchiver.isIntentResolvedToArchivedApp(intent, mRequest.userId)) { - return packageArchiver - .requestUnarchiveOnActivityStart( - intent, callingPackage, mRequest.userId, realCallingUid); - } - } - final int launchFlags = intent.getFlags(); if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) { // Transfer the result target from the source activity to the new one being started, @@ -1045,6 +1034,17 @@ class ActivityStarter { } if (err == ActivityManager.START_SUCCESS && aInfo == null) { + if (Flags.archiving()) { + PackageArchiver packageArchiver = mService + .getPackageManagerInternalLocked() + .getPackageArchiver(); + if (packageArchiver.isIntentResolvedToArchivedApp(intent, mRequest.userId)) { + return packageArchiver + .requestUnarchiveOnActivityStart( + intent, callingPackage, mRequest.userId, realCallingUid); + } + } + // We couldn't find the specific class specified in the Intent. // Also the end of the line. err = ActivityManager.START_CLASS_NOT_FOUND; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index f43c1b01e87c..3959a5e54cbf 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3691,19 +3691,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return false; } - // If the app is using legacy-entry (not auto-enter), then we will get a client-request - // that was actually a server-request (via pause(userLeaving=true)). This happens when - // the app is PAUSING, so detect that case here. - boolean originallyFromClient = fromClient - && (!r.isState(PAUSING) || params.isAutoEnterEnabled()); - - // If PiP2 flag is on and client-request to enter PiP came via onUserLeaveHint(), - // we request a direct transition from Shell to TRANSIT_PIP_LEGACY to get the startWct - // with the right entry bounds. - if (isPip2ExperimentEnabled() && !originallyFromClient && !params.isAutoEnterEnabled()) { + // If PiP2 flag is on and client-request to enter PiP comes in, + // we request a direct transition from Shell to TRANSIT_PIP to get the startWct + // with the right entry bounds. So PiP activity isn't moved to a pinned task until after + // Shell calls back into Core with the entry bounds passed through. + if (isPip2ExperimentEnabled()) { final Transition legacyEnterPipTransition = new Transition(TRANSIT_PIP, - 0 /* flags */, getTransitionController(), - mWindowManager.mSyncEngine); + 0 /* flags */, getTransitionController(), mWindowManager.mSyncEngine); legacyEnterPipTransition.setPipActivity(r); getTransitionController().startCollectOrQueue(legacyEnterPipTransition, (deferred) -> { getTransitionController().requestStartTransition(legacyEnterPipTransition, @@ -3712,6 +3706,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return true; } + // If the app is using legacy-entry (not auto-enter), then we will get a client-request + // that was actually a server-request (via pause(userLeaving=true)). This happens when + // the app is PAUSING, so detect that case here. + boolean originallyFromClient = fromClient + && (!r.isState(PAUSING) || params.isAutoEnterEnabled()); + // Create a transition only for this pip entry if it is coming from the app without the // system requesting that the app enter-pip. If the system requested it, that means it // should be part of that transition if possible. diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 05087f8a6edf..939babc4df41 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -1176,7 +1176,6 @@ public class AppTransitionController { mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(app.token); } app.updateReportedVisibilityLocked(); - app.waitingToShow = false; app.showAllWindowsLocked(); if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) { diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index eed46fee1ae1..fc3a33883de6 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -61,6 +61,7 @@ import android.widget.Toast; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.FrameworkStatsLog; +import com.android.internal.util.Preconditions; import com.android.server.UiThread; import com.android.server.am.PendingIntentRecord; import com.android.window.flags.Flags; @@ -219,6 +220,9 @@ public class BackgroundActivityStartController { private final WindowProcessController mCallerApp; private final WindowProcessController mRealCallerApp; private final boolean mIsCallForResult; + private final ActivityOptions mCheckedOptions; + private BalVerdict mResultForCaller; + private BalVerdict mResultForRealCaller; private BalState(int callingUid, int callingPid, final String callingPackage, int realCallingUid, int realCallingPid, @@ -239,6 +243,7 @@ public class BackgroundActivityStartController { mIntent = intent; mRealCallingPackage = mService.getPackageNameIfUnique(realCallingUid, realCallingPid); mIsCallForResult = resultRecord != null; + mCheckedOptions = checkedOptions; if (balRequireOptInByPendingIntentCreator() // auto-opt in introduced with this feature && (originatingPendingIntent == null // not a PendingIntent || mIsCallForResult) // sent for result @@ -369,8 +374,19 @@ public class BackgroundActivityStartController { return mCallingUid == mRealCallingUid; } - private String dump(BalVerdict resultIfPiCreatorAllowsBal, - BalVerdict resultIfPiSenderAllowsBal) { + public void setResultForCaller(BalVerdict resultForCaller) { + Preconditions.checkState(mResultForCaller == null, + "mResultForCaller can only be set once"); + this.mResultForCaller = resultForCaller; + } + + public void setResultForRealCaller(BalVerdict resultForRealCaller) { + Preconditions.checkState(mResultForRealCaller == null, + "mResultForRealCaller can only be set once"); + this.mResultForRealCaller = resultForRealCaller; + } + + private String dump() { StringBuilder sb = new StringBuilder(2048); sb.append("[callingPackage: ") .append(getDebugPackageName(mCallingPackage, mCallingUid)); @@ -392,7 +408,7 @@ public class BackgroundActivityStartController { sb.append("; balAllowedByPiCreator: ").append(mBalAllowedByPiCreator); sb.append("; balAllowedByPiCreatorWithHardening: ") .append(mBalAllowedByPiCreatorWithHardening); - sb.append("; resultIfPiCreatorAllowsBal: ").append(resultIfPiCreatorAllowsBal); + sb.append("; resultIfPiCreatorAllowsBal: ").append(mResultForCaller); sb.append("; hasRealCaller: ").append(hasRealCaller()); sb.append("; isCallForResult: ").append(mIsCallForResult); sb.append("; isPendingIntent: ").append(isPendingIntent()); @@ -416,7 +432,7 @@ public class BackgroundActivityStartController { .append(mRealCallerApp.hasActivityInVisibleTask()); } sb.append("; balAllowedByPiSender: ").append(mBalAllowedByPiSender); - sb.append("; resultIfPiSenderAllowsBal: ").append(resultIfPiSenderAllowsBal); + sb.append("; resultIfPiSenderAllowsBal: ").append(mResultForRealCaller); } sb.append("]"); return sb.toString(); @@ -559,23 +575,25 @@ public class BackgroundActivityStartController { // realCallingSdkSandboxUidToAppUid should probably just be used instead (or in addition // to realCallingUid when calculating resultForRealCaller below. if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) { - BalVerdict balVerdict = new BalVerdict(BAL_ALLOW_SDK_SANDBOX, /*background*/ false, - "uid in SDK sandbox has visible (non-toast) window"); - return statsLog(balVerdict, state); + state.setResultForRealCaller(new BalVerdict(BAL_ALLOW_SDK_SANDBOX, + /*background*/ false, + "uid in SDK sandbox has visible (non-toast) window")); + return allowBasedOnRealCaller(state); } } BalVerdict resultForCaller = checkBackgroundActivityStartAllowedByCaller(state); + state.setResultForCaller(resultForCaller); if (!state.hasRealCaller()) { if (resultForCaller.allows()) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Background activity start allowed. " - + state.dump(resultForCaller, resultForCaller)); + + state.dump()); } - return statsLog(resultForCaller, state); + return allowBasedOnCaller(state); } - return abortLaunch(state, resultForCaller, resultForCaller); + return abortLaunch(state); } // The realCaller result is only calculated for PendingIntents (indicated by a valid @@ -589,6 +607,8 @@ public class BackgroundActivityStartController { ? resultForCaller : checkBackgroundActivityStartAllowedBySender(state, checkedOptions) .setBasedOnRealCaller(); + state.setResultForRealCaller(resultForRealCaller); + if (state.isPendingIntent()) { resultForCaller.setOnlyCreatorAllows( resultForCaller.allows() && resultForRealCaller.blocks()); @@ -600,18 +620,18 @@ public class BackgroundActivityStartController { == ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start explicitly allowed by caller. " - + state.dump(resultForCaller, resultForRealCaller)); + + state.dump()); } - return statsLog(resultForCaller, state); + return allowBasedOnCaller(state); } if (resultForRealCaller.allows() && checkedOptions.getPendingIntentBackgroundActivityStartMode() == ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start explicitly allowed by real caller. " - + state.dump(resultForCaller, resultForRealCaller)); + + state.dump()); } - return statsLog(resultForRealCaller, state); + return allowBasedOnRealCaller(state); } // Handle PendingIntent cases with default behavior next boolean callerCanAllow = resultForCaller.allows() @@ -626,26 +646,24 @@ public class BackgroundActivityStartController { // Will be allowed even with BAL hardening. if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start allowed by caller. " - + state.dump(resultForCaller, resultForRealCaller)); + + state.dump()); } - // return the realCaller result for backwards compatibility - return statsLog(resultForRealCaller, state); + return allowBasedOnCaller(state); } if (state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts()) { Slog.wtf(TAG, "With Android 15 BAL hardening this activity start may be blocked" + " if the PI creator upgrades target_sdk to 35+" + " AND the PI sender upgrades target_sdk to 34+! " - + state.dump(resultForCaller, resultForRealCaller)); + + state.dump()); showBalRiskToast(); - // return the realCaller result for backwards compatibility - return statsLog(resultForRealCaller, state); + return allowBasedOnCaller(state); } Slog.wtf(TAG, "Without Android 15 BAL hardening this activity start would be allowed" + " (missing opt in by PI creator or sender)! " - + state.dump(resultForCaller, resultForRealCaller)); - return abortLaunch(state, resultForCaller, resultForRealCaller); + + state.dump()); + return abortLaunch(state); } if (callerCanAllow) { // Allowed before V by creator @@ -653,24 +671,24 @@ public class BackgroundActivityStartController { // Will be allowed even with BAL hardening. if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start allowed by caller. " - + state.dump(resultForCaller, resultForRealCaller)); + + state.dump()); } - return statsLog(resultForCaller, state); + return allowBasedOnCaller(state); } if (state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts()) { Slog.wtf(TAG, "With Android 15 BAL hardening this activity start may be blocked" + " if the PI creator upgrades target_sdk to 35+! " + " (missing opt in by PI creator)! " - + state.dump(resultForCaller, resultForRealCaller)); + + state.dump()); showBalRiskToast(); - return statsLog(resultForCaller, state); + return allowBasedOnCaller(state); } Slog.wtf(TAG, "Without Android 15 BAL hardening this activity start would be allowed" + " (missing opt in by PI creator)! " - + state.dump(resultForCaller, resultForRealCaller)); - return abortLaunch(state, resultForCaller, resultForRealCaller); + + state.dump()); + return abortLaunch(state); } if (realCallerCanAllow) { // Allowed before U by sender @@ -679,23 +697,38 @@ public class BackgroundActivityStartController { "With Android 14 BAL hardening this activity start will be blocked" + " if the PI sender upgrades target_sdk to 34+! " + " (missing opt in by PI sender)! " - + state.dump(resultForCaller, resultForRealCaller)); + + state.dump()); showBalRiskToast(); - return statsLog(resultForRealCaller, state); + return allowBasedOnRealCaller(state); } Slog.wtf(TAG, "Without Android 14 BAL hardening this activity start would be allowed" + " (missing opt in by PI sender)! " - + state.dump(resultForCaller, resultForRealCaller)); - return abortLaunch(state, resultForCaller, resultForRealCaller); + + state.dump()); + return abortLaunch(state); } // neither the caller not the realCaller can allow or have explicitly opted out - return abortLaunch(state, resultForCaller, resultForRealCaller); + return abortLaunch(state); + } + + private BalVerdict allowBasedOnCaller(BalState state) { + if (DEBUG_ACTIVITY_STARTS) { + Slog.d(TAG, "Background activity launch allowed based on caller. " + + state.dump()); + } + return statsLog(state.mResultForCaller, state); } - private BalVerdict abortLaunch(BalState state, BalVerdict resultForCaller, - BalVerdict resultForRealCaller) { + private BalVerdict allowBasedOnRealCaller(BalState state) { + if (DEBUG_ACTIVITY_STARTS) { + Slog.d(TAG, "Background activity launch allowed based on real caller. " + + state.dump()); + } + return statsLog(state.mResultForRealCaller, state); + } + + private BalVerdict abortLaunch(BalState state) { Slog.w(TAG, "Background activity launch blocked! " - + state.dump(resultForCaller, resultForRealCaller)); + + state.dump()); showBalBlockedToast(); return statsLog(BalVerdict.BLOCK, state); } @@ -1471,24 +1504,36 @@ public class BackgroundActivityStartController { && (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) { String activityName = intent != null ? requireNonNull(intent.getComponent()).flattenToShortString() : ""; - FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - activityName, - BAL_ALLOW_PENDING_INTENT, - callingUid, - realCallingUid); + writeBalAllowedLog(activityName, BAL_ALLOW_PENDING_INTENT, + state); } if (code == BAL_ALLOW_PERMISSION || code == BAL_ALLOW_FOREGROUND - || code == BAL_ALLOW_SAW_PERMISSION) { + || code == BAL_ALLOW_SAW_PERMISSION) { // We don't need to know which activity in this case. - FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - /*activityName*/ "", - code, - callingUid, - realCallingUid); + writeBalAllowedLog("", code, state); + } return finalVerdict; } + private static void writeBalAllowedLog(String activityName, int code, BalState state) { + FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + activityName, + code, + state.mCallingUid, + state.mRealCallingUid, + state.mResultForCaller == null ? BAL_BLOCK : state.mResultForCaller.getRawCode(), + state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts(), + state.mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode() + != ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED, + state.mResultForRealCaller == null ? BAL_BLOCK + : state.mResultForRealCaller.getRawCode(), + state.mBalAllowedByPiSender.allowsBackgroundActivityStarts(), + state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode() + != ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED + ); + } + /** * Called whenever an activity finishes. Stores the record, so it can be used by ASM grace * period checks. diff --git a/services/core/java/com/android/server/wm/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java index e4eb7b3a8144..c7df83a9ccf9 100644 --- a/services/core/java/com/android/server/wm/ClientLifecycleManager.java +++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java @@ -24,6 +24,7 @@ import android.app.servertransaction.ClientTransactionItem; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.os.Trace; import android.util.ArrayMap; import android.util.Slog; @@ -146,9 +147,10 @@ class ClientLifecycleManager { /** Executes all the pending transactions. */ void dispatchPendingTransactions() { - if (!Flags.bundleClientTransactionFlag()) { + if (!Flags.bundleClientTransactionFlag() || mPendingTransactions.isEmpty()) { return; } + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "clientTransactionsDispatched"); final int size = mPendingTransactions.size(); for (int i = 0; i < size; i++) { final ClientTransaction transaction = mPendingTransactions.valueAt(i); @@ -159,6 +161,7 @@ class ClientLifecycleManager { } } mPendingTransactions.clear(); + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } /** diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index dd00b8fe3a4c..47972b37d836 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -173,7 +173,7 @@ final class LetterboxUiController { // Corresponds to OVERRIDE_ANY_ORIENTATION private final boolean mIsOverrideAnyOrientationEnabled; // Corresponds to OVERRIDE_ANY_ORIENTATION_TO_USER - private final boolean mIsOverrideToUserOrientationEnabled; + private final boolean mIsSystemOverrideToFullscreenEnabled; // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT private final boolean mIsOverrideToPortraitOrientationEnabled; // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR @@ -358,7 +358,7 @@ final class LetterboxUiController { PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE); mIsOverrideAnyOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION); - mIsOverrideToUserOrientationEnabled = + mIsSystemOverrideToFullscreenEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION_TO_USER); mIsOverrideToPortraitOrientationEnabled = isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT); @@ -670,8 +670,7 @@ final class LetterboxUiController { final DisplayContent displayContent = mActivityRecord.mDisplayContent; final boolean isIgnoreOrientationRequestEnabled = displayContent != null && displayContent.getIgnoreOrientationRequest(); - if (shouldApplyUserFullscreenOverride() - && isIgnoreOrientationRequestEnabled) { + if (shouldApplyUserFullscreenOverride() && isIgnoreOrientationRequestEnabled) { Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for " + mActivityRecord + " is overridden to " + screenOrientationToString(SCREEN_ORIENTATION_USER) @@ -706,8 +705,7 @@ final class LetterboxUiController { // mUserAspectRatio is always initialized first in shouldApplyUserFullscreenOverride(), // which will always come first before this check as user override > device // manufacturer override. - if (mUserAspectRatio == PackageManager.USER_MIN_ASPECT_RATIO_UNSET - && mIsOverrideToUserOrientationEnabled && isIgnoreOrientationRequestEnabled) { + if (isSystemOverrideToFullscreenEnabled() && isIgnoreOrientationRequestEnabled) { Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for " + mActivityRecord + " is overridden to " + screenOrientationToString(SCREEN_ORIENTATION_USER)); @@ -1201,6 +1199,13 @@ final class LetterboxUiController { return mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN; } + boolean isSystemOverrideToFullscreenEnabled() { + return mIsSystemOverrideToFullscreenEnabled + && !FALSE.equals(mBooleanPropertyAllowOrientationOverride) + && (mUserAspectRatio == USER_MIN_ASPECT_RATIO_UNSET + || mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN); + } + float getUserMinAspectRatio() { switch (mUserAspectRatio) { case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index ca66a66057a3..6033220e260d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -152,6 +152,7 @@ import com.android.server.pm.UserManagerInternal; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.policy.WindowManagerPolicy; import com.android.server.utils.Slogf; +import com.android.window.flags.Flags; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -795,6 +796,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } + if (Flags.bundleClientTransactionFlag()) { + // mWmService.mResizingWindows is populated in #applySurfaceChangesTransaction() + handleResizingWindows(); + + // Called after #handleResizingWindows to include WindowStateResizeItem if any. + mWmService.mAtmService.getLifecycleManager().dispatchPendingTransactions(); + } + // Send any pending task-info changes that were queued-up during a layout deferment mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents(); @@ -838,12 +847,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - handleResizingWindows(); + if (!Flags.bundleClientTransactionFlag()) { + handleResizingWindows(); + } clearFrameChangingWindows(); - // Called after #handleResizingWindows to include WindowStateResizeItem if any. - mWmService.mAtmService.getLifecycleManager().dispatchPendingTransactions(); - if (mWmService.mDisplayFrozen) { ProtoLog.v(WM_DEBUG_ORIENTATION, "With display frozen, orientationChangeComplete=%b", diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index c674176e766d..d556f095ae50 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3506,6 +3506,8 @@ class Task extends TaskFragment { appCompatTaskInfo.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET; appCompatTaskInfo.isUserFullscreenOverrideEnabled = top != null && top.mLetterboxUiController.shouldApplyUserFullscreenOverride(); + appCompatTaskInfo.isSystemFullscreenOverrideEnabled = top != null + && top.mLetterboxUiController.isSystemOverrideToFullscreenEnabled(); appCompatTaskInfo.isFromLetterboxDoubleTap = top != null && top.mLetterboxUiController.isFromDoubleTap(); if (appCompatTaskInfo.isLetterboxDoubleTapEnabled) { diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index d425bdf5613f..f51bd1be158c 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; @@ -57,6 +58,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITC import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService.checkPermission; import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; @@ -80,7 +82,9 @@ import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.ResumeActivityItem; +import android.content.PermissionChecker; import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; @@ -744,7 +748,17 @@ class TaskFragment extends WindowContainer<WindowContainer> { // The system is trusted to embed other apps securely and for all users. return UserHandle.getAppId(uid) == SYSTEM_UID // Activities from the same UID can be embedded freely by the host. - || a.isUid(uid); + || a.isUid(uid) + // Apps which have the signature MANAGE_ACTIVITY_TASK permission are trusted. + || hasManageTaskPermission(uid); + } + + /** + * Checks if a particular app uid has the {@link MANAGE_ACTIVITY_TASKS} permission. + */ + private static boolean hasManageTaskPermission(int uid) { + return checkPermission(MANAGE_ACTIVITY_TASKS, PermissionChecker.PID_UNKNOWN, uid) + == PackageManager.PERMISSION_GRANTED; } /** @@ -926,10 +940,14 @@ class TaskFragment extends WindowContainer<WindowContainer> { boolean sleepIfPossible(boolean shuttingDown) { boolean shouldSleep = true; if (mResumedActivity != null) { - // Still have something resumed; can't sleep until it is paused. - ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity); - startPausing(false /* userLeaving */, true /* uiSleeping */, null /* resuming */, - "sleep"); + if (!shuttingDown && mResumedActivity.canTurnScreenOn()) { + ProtoLog.v(WM_DEBUG_STATES, "Waiting for screen on due to %s", mResumedActivity); + } else { + // Still have something resumed; can't sleep until it is paused. + ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity); + startPausing(false /* userLeaving */, true /* uiSleeping */, null /* resuming */, + "sleep"); + } shouldSleep = false; } else if (mPausingActivity != null) { // Still waiting for something to pause; can't sleep yet. @@ -2980,7 +2998,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Override Dimmer getDimmer() { // If this is in an embedded TaskFragment and we want the dim applies on the TaskFragment. - if (mIsEmbedded && mEmbeddedDimArea == EMBEDDED_DIM_AREA_TASK_FRAGMENT) { + if (mIsEmbedded && !isDimmingOnParentTask()) { return mDimmer; } @@ -2989,7 +3007,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { /** Bounds to be used for dimming, as well as touch related tests. */ void getDimBounds(@NonNull Rect out) { - if (mIsEmbedded && mEmbeddedDimArea == EMBEDDED_DIM_AREA_PARENT_TASK) { + if (mIsEmbedded && isDimmingOnParentTask() && getDimmer().getDimBounds() != null) { + // Return the task bounds if the dimmer is showing and should cover on the Task (not + // just on this embedded TaskFragment). out.set(getTask().getBounds()); } else { out.set(getBounds()); @@ -3000,6 +3020,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { mEmbeddedDimArea = embeddedDimArea; } + @VisibleForTesting + boolean isDimmingOnParentTask() { + return mEmbeddedDimArea == EMBEDDED_DIM_AREA_PARENT_TASK; + } + @Override void prepareSurfaces() { if (asTask() != null) { diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 707f9fc9ea5f..81fe453cc692 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.IApplicationThread; import android.content.Intent; import android.content.res.Configuration; import android.os.Binder; @@ -106,6 +107,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr */ private class TaskFragmentOrganizerState implements IBinder.DeathRecipient { private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>(); + private final IApplicationThread mAppThread; private final ITaskFragmentOrganizer mOrganizer; private final int mOrganizerPid; private final int mOrganizerUid; @@ -169,6 +171,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr TaskFragmentOrganizerState(@NonNull ITaskFragmentOrganizer organizer, int pid, int uid, boolean isSystemOrganizer) { + if (Flags.bundleClientTransactionFlag()) { + mAppThread = getAppThread(pid, uid); + } else { + mAppThread = null; + } mOrganizer = organizer; mOrganizerPid = pid; mOrganizerUid = uid; @@ -407,7 +414,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return; } try { - mOrganizer.onTransactionReady(transaction); + if (Flags.bundleClientTransactionFlag()) { + // Dispatch through IApplicationThread to ensure the binder call is in order + // with ClientTransaction. + mAppThread.scheduleTaskFragmentTransaction(mOrganizer, transaction); + } else { + mOrganizer.onTransactionReady(transaction); + } } catch (RemoteException e) { Slog.d(TAG, "Exception sending TaskFragmentTransaction", e); return; @@ -464,11 +477,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr : null; } - @VisibleForTesting - void registerOrganizer(@NonNull ITaskFragmentOrganizer organizer) { - registerOrganizerInternal(organizer, false /* isSystemOrganizer */); - } - @Override public void registerOrganizer( @NonNull ITaskFragmentOrganizer organizer, boolean isSystemOrganizer) { @@ -477,8 +485,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr Flags.taskFragmentSystemOrganizerFlag() && isSystemOrganizer); } - @VisibleForTesting - void registerOrganizerInternal( + private void registerOrganizerInternal( @NonNull ITaskFragmentOrganizer organizer, boolean isSystemOrganizer) { if (isSystemOrganizer) { enforceTaskPermission("registerSystemOrganizer()"); @@ -1198,6 +1205,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } + @VisibleForTesting + @NonNull + IApplicationThread getAppThread(int pid, int uid) { + final WindowProcessController wpc = mAtmService.mProcessMap.getProcess(pid); + final IApplicationThread appThread = wpc != null && wpc.mUid == uid + ? wpc.getThread() + : null; + if (appThread == null) { + throw new IllegalArgumentException("Cannot find process for pid=" + pid + + " uid=" + uid); + } + return appThread; + } + /** * Trims the given Intent to only those that are needed to for embedding rules. This helps to * make it safer for cross-uid embedding even if we only send the Intent for trusted embedding. diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index b12855e2bb49..56bef3335b8b 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1906,7 +1906,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { for (int i = mParticipants.size() - 1; i >= 0; --i) { final WallpaperWindowToken wallpaper = mParticipants.valueAt(i).asWallpaperToken(); if (wallpaper != null) { - wallpaper.waitingToShow = false; if (!wallpaper.isVisible() && wallpaper.isVisibleRequested()) { wallpaper.commitVisibility(showWallpaper); } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 9e4a31c3773a..59d0210251d1 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -34,6 +34,7 @@ import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS; import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_DIM_ON_TASK; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ISOLATED_NAVIGATION; import static android.window.TaskFragmentOperation.OP_TYPE_SET_RELATIVE_BOUNDS; import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; @@ -68,6 +69,8 @@ import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermis import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; +import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_PARENT_TASK; +import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_TASK_FRAGMENT; import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED; import static com.android.server.wm.TaskFragment.FLAG_FORCE_HIDDEN_FOR_TASK_FRAGMENT_ORG; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; @@ -1493,6 +1496,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub task.removeDecorSurface(); break; } + case OP_TYPE_SET_DIM_ON_TASK: { + final boolean dimOnTask = operation.isDimOnTask(); + taskFragment.setEmbeddedDimArea(dimOnTask ? EMBEDDED_DIM_AREA_PARENT_TASK + : EMBEDDED_DIM_AREA_TASK_FRAGMENT); + break; + } } return effects; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 949025c45287..0b43be700b0d 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1929,9 +1929,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * of a transition that has not yet been started. */ boolean isReadyForDisplay() { - if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()) { - return false; - } final boolean parentAndClientVisible = !isParentWindowHidden() && mViewVisibility == View.VISIBLE && mToken.isVisible(); return mHasSurface && isVisibleByPolicy() && !mDestroying @@ -5641,12 +5638,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Skip sync for invisible app windows which are not managed by activity lifecycle. return false; } - if (mActivityRecord != null && mViewVisibility != View.VISIBLE - && mWinAnimator.mAttrType != TYPE_BASE_APPLICATION - && mWinAnimator.mAttrType != TYPE_APPLICATION_STARTING) { - // Skip sync for invisible app windows which are not managed by activity lifecycle. - return false; - } // In the WindowContainer implementation we immediately mark ready // since a generic WindowContainer only needs to wait for its // children to finish and is immediately ready from its own diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 7d21dbf85a66..5048cef3da1b 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -28,7 +28,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowTokenProto.HASH_CODE; import static com.android.server.wm.WindowTokenProto.PAUSED; -import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW; import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER; import android.annotation.CallSuper; @@ -91,10 +90,6 @@ class WindowToken extends WindowContainer<WindowState> { // Is key dispatching paused for this token? boolean paused = false; - // Set to true when this token is in a pending transaction where it - // will be shown. - boolean waitingToShow; - /** The owner has {@link android.Manifest.permission#MANAGE_APP_TOKENS} */ final boolean mOwnerCanManageAppTokens; @@ -702,7 +697,6 @@ class WindowToken extends WindowContainer<WindowState> { final long token = proto.start(fieldId); super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); proto.write(HASH_CODE, System.identityHashCode(this)); - proto.write(WAITING_TO_SHOW, waitingToShow); proto.write(PAUSED, paused); proto.end(token); } @@ -716,9 +710,6 @@ class WindowToken extends WindowContainer<WindowState> { super.dump(pw, prefix, dumpAll); pw.print(prefix); pw.print("windows="); pw.println(mChildren); pw.print(prefix); pw.print("windowType="); pw.print(windowType); - if (waitingToShow) { - pw.print(" waitingToShow=true"); - } pw.println(); if (hasFixedRotationTransform()) { pw.print(prefix); diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index b19f3d813985..dfa9dcecfbb5 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -79,6 +79,7 @@ cc_library_static { ":lib_cachedAppOptimizer_native", ":lib_gameManagerService_native", ":lib_oomConnection_native", + ":lib_anrTimer_native", ], include_dirs: [ @@ -246,3 +247,10 @@ filegroup { name: "lib_oomConnection_native", srcs: ["com_android_server_am_OomConnection.cpp"], } + +filegroup { + name: "lib_anrTimer_native", + srcs: [ + "com_android_server_utils_AnrTimer.cpp", + ], +} diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 9ba0a2aae02c..afb0b20650f8 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -114,6 +114,7 @@ static struct { jmethodID notifyFocusChanged; jmethodID notifySensorEvent; jmethodID notifySensorAccuracy; + jmethodID notifyStickyModifierStateChanged; jmethodID notifyStylusGestureStarted; jmethodID isInputMethodConnectionActive; jmethodID notifyVibratorState; @@ -270,7 +271,8 @@ static std::string getStringElementFromJavaArray(JNIEnv* env, jobjectArray array class NativeInputManager : public virtual InputReaderPolicyInterface, public virtual InputDispatcherPolicyInterface, public virtual PointerControllerPolicyInterface, - public virtual PointerChoreographerPolicyInterface { + public virtual PointerChoreographerPolicyInterface, + public virtual InputFilterPolicyInterface { protected: virtual ~NativeInputManager(); @@ -388,6 +390,10 @@ public: PointerControllerInterface::ControllerType type) override; void notifyPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position) override; + /* --- InputFilterPolicyInterface implementation --- */ + void notifyStickyModifierStateChanged(uint32_t modifierState, + uint32_t lockedModifierState) override; + private: sp<InputManagerInterface> mInputManager; @@ -477,7 +483,7 @@ NativeInputManager::NativeInputManager(jobject serviceObj, const sp<Looper>& loo mServiceObj = env->NewGlobalRef(serviceObj); - InputManager* im = new InputManager(this, *this, *this); + InputManager* im = new InputManager(this, *this, *this, *this); mInputManager = im; defaultServiceManager()->addService(String16("inputflinger"), im); } @@ -806,6 +812,14 @@ void NativeInputManager::notifyPointerDisplayIdChanged(int32_t pointerDisplayId, checkAndClearExceptionFromCallback(env, "onPointerDisplayIdChanged"); } +void NativeInputManager::notifyStickyModifierStateChanged(uint32_t modifierState, + uint32_t lockedModifierState) { + JNIEnv* env = jniEnv(); + env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyStickyModifierStateChanged, + modifierState, lockedModifierState); + checkAndClearExceptionFromCallback(env, "notifyStickyModifierStateChanged"); +} + sp<SurfaceControl> NativeInputManager::getParentSurfaceForPointers(int displayId) { JNIEnv* env = jniEnv(); jlong nativeSurfaceControlPtr = @@ -2957,6 +2971,9 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.onPointerDisplayIdChanged, clazz, "onPointerDisplayIdChanged", "(IFF)V"); + GET_METHOD_ID(gServiceClassInfo.notifyStickyModifierStateChanged, clazz, + "notifyStickyModifierStateChanged", "(II)V"); + GET_METHOD_ID(gServiceClassInfo.onPointerDownOutsideFocus, clazz, "onPointerDownOutsideFocus", "(Landroid/os/IBinder;)V"); diff --git a/services/core/jni/com_android_server_utils_AnrTimer.cpp b/services/core/jni/com_android_server_utils_AnrTimer.cpp new file mode 100644 index 000000000000..97b18fac91f4 --- /dev/null +++ b/services/core/jni/com_android_server_utils_AnrTimer.cpp @@ -0,0 +1,918 @@ +/* + * 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. + */ + +#include <time.h> +#include <pthread.h> +#include <sys/timerfd.h> +#include <inttypes.h> + +#include <algorithm> +#include <list> +#include <memory> +#include <set> +#include <string> +#include <vector> + +#define LOG_TAG "AnrTimerService" + +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include "android_runtime/AndroidRuntime.h" +#include "core_jni_helpers.h" + +#include <utils/Mutex.h> +#include <utils/Timers.h> + +#include <utils/Log.h> +#include <utils/Timers.h> +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include <android-base/unique_fd.h> + +using ::android::base::StringPrintf; + + +// Native support is unavailable on WIN32 platforms. This macro preemptively disables it. +#ifdef _WIN32 +#define NATIVE_SUPPORT 0 +#else +#define NATIVE_SUPPORT 1 +#endif + +namespace android { + +// using namespace android; + +// Almost nothing in this module needs to be in the android namespace. +namespace { + +// If not on a Posix system, create stub timerfd methods. These are defined to allow +// compilation. They are not functional. Also, they do not leak outside this compilation unit. +#ifdef _WIN32 +int timer_create() { + return -1; +} +int timer_settime(int, int, void const *, void *) { + return -1; +} +#else +int timer_create() { + return timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); +} +int timer_settime(int fd, int flags, const struct itimerspec *new_value, + struct itimerspec *_Nullable old_value) { + return timerfd_settime(fd, flags, new_value, old_value); +} +#endif + +// A local debug flag that gates a set of log messages for debug only. This is normally const +// false so the debug statements are not included in the image. The flag can be set true in a +// unit test image to debug test failures. +const bool DEBUG = false; + +// Return the current time in nanoseconds. This time is relative to system boot. +nsecs_t now() { + return systemTime(SYSTEM_TIME_MONOTONIC); +} + +/** + * This class encapsulates the anr timer service. The service manages a list of individual + * timers. A timer is either Running or Expired. Once started, a timer may be canceled or + * accepted. Both actions collect statistics about the timer and then delete it. An expired + * timer may also be discarded, which deletes the timer without collecting any statistics. + * + * All public methods in this class are thread-safe. + */ +class AnrTimerService { + private: + class ProcessStats; + class Timer; + + public: + + // The class that actually runs the clock. + class Ticker; + + // A timer is identified by a timer_id_t. Timer IDs are unique in the moment. + using timer_id_t = uint32_t; + + // A manifest constant. No timer is ever created with this ID. + static const timer_id_t NOTIMER = 0; + + // A notifier is called with a timer ID, the timer's tag, and the client's cookie. The pid + // and uid that were originally assigned to the timer are passed as well. + using notifier_t = bool (*)(timer_id_t, int pid, int uid, void* cookie, jweak object); + + enum Status { + Invalid, + Running, + Expired, + Canceled + }; + + /** + * Create a timer service. The service is initialized with a name used for logging. The + * constructor is also given the notifier callback, and two cookies for the callback: the + * traditional void* and an int. + */ + AnrTimerService(char const* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker*); + + // Delete the service and clean up memory. + ~AnrTimerService(); + + // Start a timer and return the associated timer ID. It does not matter if the same pid/uid + // are already in the running list. Once start() is called, one of cancel(), accept(), or + // discard() must be called to clean up the internal data structures. + timer_id_t start(int pid, int uid, nsecs_t timeout, bool extend); + + // Cancel a timer and remove it from all lists. This is called when the event being timed + // has occurred. If the timer was Running, the function returns true. The other + // possibilities are that the timer was Expired or non-existent; in both cases, the function + // returns false. + bool cancel(timer_id_t timerId); + + // Accept a timer and remove it from all lists. This is called when the upper layers accept + // that a timer has expired. If the timer was Expired, the function returns true. The + // other possibilities are tha the timer was Running or non-existing; in both cases, the + // function returns false. + bool accept(timer_id_t timerId); + + // Discard a timer without collecting any statistics. This is called when the upper layers + // recognize that a timer expired but decide the expiration is not significant. If the + // timer was Expired, the function returns true. The other possibilities are tha the timer + // was Running or non-existing; in both cases, the function returns false. + bool discard(timer_id_t timerId); + + // A timer has expired. + void expire(timer_id_t); + + // Dump a small amount of state to the log file. + void dump(bool verbose) const; + + // Return the Java object associated with this instance. + jweak jtimer() const { + return notifierObject_; + } + + private: + // The service cannot be copied. + AnrTimerService(AnrTimerService const &) = delete; + + // Insert a timer into the running list. The lock must be held by the caller. + void insert(const Timer&); + + // Remove a timer from the lists and return it. The lock must be held by the caller. + Timer remove(timer_id_t timerId); + + // Return a string representation of a status value. + static char const *statusString(Status); + + // The name of this service, for logging. + std::string const label_; + + // The callback that is invoked when a timer expires. + notifier_t const notifier_; + + // The two cookies passed to the notifier. + void* notifierCookie_; + jweak notifierObject_; + + // The global lock + mutable Mutex lock_; + + // The list of all timers that are still running. This is sorted by ID for fast lookup. + std::set<Timer> running_; + + // The maximum number of active timers. + size_t maxActive_; + + // Simple counters + struct Counters { + // The number of timers started, canceled, accepted, discarded, and expired. + size_t started; + size_t canceled; + size_t accepted; + size_t discarded; + size_t expired; + + // The number of times there were zero active timers. + size_t drained; + + // The number of times a protocol error was seen. + size_t error; + }; + + Counters counters_; + + // The clock used by this AnrTimerService. + Ticker *ticker_; +}; + +class AnrTimerService::ProcessStats { + public: + nsecs_t cpu_time; + nsecs_t cpu_delay; + + ProcessStats() : + cpu_time(0), + cpu_delay(0) { + } + + // Collect all statistics for a process. Return true if the fill succeeded and false if it + // did not. If there is any problem, the statistics are zeroed. + bool fill(int pid) { + cpu_time = 0; + cpu_delay = 0; + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/proc/%u/schedstat", pid); + ::android::base::unique_fd fd(open(path, O_RDONLY | O_CLOEXEC)); + if (!fd.ok()) { + return false; + } + char buffer[128]; + ssize_t len = read(fd, buffer, sizeof(buffer)); + if (len <= 0) { + return false; + } + if (len >= sizeof(buffer)) { + ALOGE("proc file too big: %s", path); + return false; + } + buffer[len] = 0; + unsigned long t1; + unsigned long t2; + if (sscanf(buffer, "%lu %lu", &t1, &t2) != 2) { + return false; + } + cpu_time = t1; + cpu_delay = t2; + return true; + } +}; + +class AnrTimerService::Timer { + public: + // A unique ID assigned when the Timer is created. + timer_id_t const id; + + // The creation parameters. The timeout is the original, relative timeout. + int const pid; + int const uid; + nsecs_t const timeout; + bool const extend; + + // The state of this timer. + Status status; + + // The scheduled timeout. This is an absolute time. It may be extended. + nsecs_t scheduled; + + // True if this timer has been extended. + bool extended; + + // Bookkeeping for extensions. The initial state of the process. This is collected only if + // the timer is extensible. + ProcessStats initial; + + // The default constructor is used to create timers that are Invalid, representing the "not + // found" condition when a collection is searched. + Timer() : + id(NOTIMER), + pid(0), + uid(0), + timeout(0), + extend(false), + status(Invalid), + scheduled(0), + extended(false) { + } + + // This constructor creates a timer with the specified id. This can be used as the argument + // to find(). + Timer(timer_id_t id) : + id(id), + pid(0), + uid(0), + timeout(0), + extend(false), + status(Invalid), + scheduled(0), + extended(false) { + } + + // Create a new timer. This starts the timer. + Timer(int pid, int uid, nsecs_t timeout, bool extend) : + id(nextId()), + pid(pid), + uid(uid), + timeout(timeout), + extend(extend), + status(Running), + scheduled(now() + timeout), + extended(false) { + if (extend && pid != 0) { + initial.fill(pid); + } + } + + // Cancel a timer. Return the headroom (which may be negative). This does not, as yet, + // account for extensions. + void cancel() { + ALOGW_IF(DEBUG && status != Running, "cancel %s", toString().c_str()); + status = Canceled; + } + + // Expire a timer. Return true if the timer is expired and false otherwise. The function + // returns false if the timer is eligible for extension. If the function returns false, the + // scheduled time is updated. + bool expire() { + ALOGI_IF(DEBUG, "expire %s", toString().c_str()); + nsecs_t extension = 0; + if (extend && !extended) { + // Only one extension is permitted. + extended = true; + ProcessStats current; + current.fill(pid); + extension = current.cpu_delay - initial.cpu_delay; + if (extension < 0) extension = 0; + if (extension > timeout) extension = timeout; + } + if (extension == 0) { + status = Expired; + } else { + scheduled += extension; + } + return status == Expired; + } + + // Accept a timeout. + void accept() { + } + + // Discard a timeout. + void discard() { + } + + // Timers are sorted by id, which is unique. This provides fast lookups. + bool operator<(Timer const &r) const { + return id < r.id; + } + + bool operator==(timer_id_t r) const { + return id == r; + } + + std::string toString() const { + return StringPrintf("timer id=%d pid=%d status=%s", id, pid, statusString(status)); + } + + std::string toString(nsecs_t now) const { + uint32_t ms = nanoseconds_to_milliseconds(now - scheduled); + return StringPrintf("timer id=%d pid=%d status=%s scheduled=%ums", + id, pid, statusString(status), -ms); + } + + static int maxId() { + return idGen; + } + + private: + // Get the next free ID. NOTIMER is never returned. + static timer_id_t nextId() { + timer_id_t id = idGen.fetch_add(1); + while (id == NOTIMER) { + id = idGen.fetch_add(1); + } + return id; + } + + // IDs start at 1. A zero ID is invalid. + static std::atomic<timer_id_t> idGen; +}; + +// IDs start at 1. +std::atomic<AnrTimerService::timer_id_t> AnrTimerService::Timer::idGen(1); + +/** + * Manage a set of timers and notify clients when there is a timeout. + */ +class AnrTimerService::Ticker { + private: + struct Entry { + const nsecs_t scheduled; + const timer_id_t id; + AnrTimerService* const service; + + Entry(nsecs_t scheduled, timer_id_t id, AnrTimerService* service) : + scheduled(scheduled), id(id), service(service) {}; + + bool operator<(const Entry &r) const { + return scheduled == r.scheduled ? id < r.id : scheduled < r.scheduled; + } + }; + + public: + + // Construct the ticker. This creates the timerfd file descriptor and starts the monitor + // thread. The monitor thread is given a unique name. + Ticker() { + timerFd_ = timer_create(); + if (timerFd_ < 0) { + ALOGE("failed to create timerFd: %s", strerror(errno)); + return; + } + + if (pthread_create(&watcher_, 0, run, this) != 0) { + ALOGE("failed to start thread: %s", strerror(errno)); + watcher_ = 0; + ::close(timerFd_); + return; + } + + // 16 is a magic number from the kernel. Thread names may not be longer than this many + // bytes, including the terminating null. The snprintf() method will truncate properly. + char name[16]; + snprintf(name, sizeof(name), "AnrTimerService"); + pthread_setname_np(watcher_, name); + + ready_ = true; + } + + ~Ticker() { + // Closing the file descriptor will close the monitor process, if any. + if (timerFd_ >= 0) ::close(timerFd_); + timerFd_ = -1; + watcher_ = 0; + } + + // Insert a timer. Unless canceled, the timer will expire at the scheduled time. If it + // expires, the service will be notified with the id. + void insert(nsecs_t scheduled, timer_id_t id, AnrTimerService *service) { + Entry e(scheduled, id, service); + AutoMutex _l(lock_); + timer_id_t front = headTimerId(); + running_.insert(e); + if (front != headTimerId()) restartLocked(); + maxRunning_ = std::max(maxRunning_, running_.size()); + } + + // Remove a timer. The timer is identified by its scheduled timeout and id. Technically, + // the id is sufficient (because timer IDs are unique) but using the timeout is more + // efficient. + void remove(nsecs_t scheduled, timer_id_t id) { + Entry key(scheduled, id, 0); + AutoMutex _l(lock_); + timer_id_t front = headTimerId(); + auto found = running_.find(key); + if (found != running_.end()) running_.erase(found); + if (front != headTimerId()) restartLocked(); + } + + // Remove every timer associated with the service. + void remove(AnrTimerService const* service) { + AutoMutex _l(lock_); + timer_id_t front = headTimerId(); + for (auto i = running_.begin(); i != running_.end(); i++) { + if (i->service == service) { + running_.erase(i); + } + } + if (front != headTimerId()) restartLocked(); + } + + // Return the number of timers still running. + size_t running() const { + AutoMutex _l(lock_); + return running_.size(); + } + + // Return the high-water mark of timers running. + size_t maxRunning() const { + AutoMutex _l(lock_); + return maxRunning_; + } + + private: + + // Return the head of the running list. The lock must be held by the caller. + timer_id_t headTimerId() { + return running_.empty() ? NOTIMER : running_.cbegin()->id; + } + + // A simple wrapper that meets the requirements of pthread_create. + static void* run(void* arg) { + reinterpret_cast<Ticker*>(arg)->monitor(); + ALOGI("monitor exited"); + return 0; + } + + // Loop (almost) forever. Whenever the timerfd expires, expire as many entries as + // possible. The loop terminates when the read fails; this generally indicates that the + // file descriptor has been closed and the thread can exit. + void monitor() { + uint64_t token = 0; + while (read(timerFd_, &token, sizeof(token)) == sizeof(token)) { + // Move expired timers into the local ready list. This is done inside + // the lock. Then, outside the lock, expire them. + nsecs_t current = now(); + std::vector<Entry> ready; + { + AutoMutex _l(lock_); + while (!running_.empty()) { + Entry timer = *(running_.begin()); + if (timer.scheduled <= current) { + ready.push_back(timer); + running_.erase(running_.cbegin()); + } else { + break; + } + } + restartLocked(); + } + // Call the notifiers outside the lock. Calling the notifiers with the lock held + // can lead to deadlock, if the Java-side handler also takes a lock. Note that the + // timerfd is already running. + for (auto i = ready.begin(); i != ready.end(); i++) { + Entry e = *i; + e.service->expire(e.id); + } + } + } + + // Restart the ticker. The caller must be holding the lock. This method updates the + // timerFd_ to expire at the time of the first Entry in the running list. This method does + // not check to see if the currently programmed expiration time is different from the + // scheduled expiration time of the first entry. + void restartLocked() { + if (!running_.empty()) { + Entry const x = *(running_.cbegin()); + nsecs_t delay = x.scheduled - now(); + // Force a minimum timeout of 10ns. + if (delay < 10) delay = 10; + time_t sec = nanoseconds_to_seconds(delay); + time_t ns = delay - seconds_to_nanoseconds(sec); + struct itimerspec setting = { + .it_interval = { 0, 0 }, + .it_value = { sec, ns }, + }; + timer_settime(timerFd_, 0, &setting, nullptr); + restarted_++; + ALOGI_IF(DEBUG, "restarted timerfd for %ld.%09ld", sec, ns); + } else { + const struct itimerspec setting = { + .it_interval = { 0, 0 }, + .it_value = { 0, 0 }, + }; + timer_settime(timerFd_, 0, &setting, nullptr); + drained_++; + ALOGI_IF(DEBUG, "drained timer list"); + } + } + + // The usual lock. + mutable Mutex lock_; + + // True if the object was initialized properly. Android does not support throwing C++ + // exceptions, so clients should check this flag after constructing the object. This is + // effectively const after the instance has been created. + bool ready_ = false; + + // The file descriptor of the timer. + int timerFd_ = -1; + + // The thread that monitors the timer. + pthread_t watcher_ = 0; + + // The number of times the timer was restarted. + size_t restarted_ = 0; + + // The number of times the timer list was exhausted. + size_t drained_ = 0; + + // The highwater mark of timers that are running. + size_t maxRunning_ = 0; + + // The list of timers that are scheduled. This set is sorted by timeout and then by timer + // ID. A set is sufficient (as opposed to a multiset) because timer IDs are unique. + std::set<Entry> running_; +}; + + +AnrTimerService::AnrTimerService(char const* label, + notifier_t notifier, void* cookie, jweak jtimer, Ticker* ticker) : + label_(label), + notifier_(notifier), + notifierCookie_(cookie), + notifierObject_(jtimer), + ticker_(ticker) { + + // Zero the statistics + maxActive_ = 0; + memset(&counters_, 0, sizeof(counters_)); + + ALOGI_IF(DEBUG, "initialized %s", label); +} + +AnrTimerService::~AnrTimerService() { + AutoMutex _l(lock_); + ticker_->remove(this); +} + +char const *AnrTimerService::statusString(Status s) { + switch (s) { + case Invalid: return "invalid"; + case Running: return "running"; + case Expired: return "expired"; + case Canceled: return "canceled"; + } + return "unknown"; +} + +AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, + nsecs_t timeout, bool extend) { + ALOGI_IF(DEBUG, "starting"); + AutoMutex _l(lock_); + Timer t(pid, uid, timeout, extend); + insert(t); + counters_.started++; + + ALOGI_IF(DEBUG, "started timer %u timeout=%zu", t.id, static_cast<size_t>(timeout)); + return t.id; +} + +bool AnrTimerService::cancel(timer_id_t timerId) { + ALOGI_IF(DEBUG, "canceling %u", timerId); + if (timerId == NOTIMER) return false; + AutoMutex _l(lock_); + Timer timer = remove(timerId); + + bool result = timer.status == Running; + if (timer.status != Invalid) { + timer.cancel(); + } else { + counters_.error++; + } + counters_.canceled++; + ALOGI_IF(DEBUG, "canceled timer %u", timerId); + return result; +} + +bool AnrTimerService::accept(timer_id_t timerId) { + ALOGI_IF(DEBUG, "accepting %u", timerId); + if (timerId == NOTIMER) return false; + AutoMutex _l(lock_); + Timer timer = remove(timerId); + + bool result = timer.status == Expired; + if (timer.status == Expired) { + timer.accept(); + } else { + counters_.error++; + } + counters_.accepted++; + ALOGI_IF(DEBUG, "accepted timer %u", timerId); + return result; +} + +bool AnrTimerService::discard(timer_id_t timerId) { + ALOGI_IF(DEBUG, "discarding %u", timerId); + if (timerId == NOTIMER) return false; + AutoMutex _l(lock_); + Timer timer = remove(timerId); + + bool result = timer.status == Expired; + if (timer.status == Expired) { + timer.discard(); + } else { + counters_.error++; + } + counters_.discarded++; + ALOGI_IF(DEBUG, "discarded timer %u", timerId); + return result; +} + +// Hold the lock in order to manage the running list. +// the listener. +void AnrTimerService::expire(timer_id_t timerId) { + ALOGI_IF(DEBUG, "expiring %u", timerId); + // Save the timer attributes for the notification + int pid = 0; + int uid = 0; + bool expired = false; + { + AutoMutex _l(lock_); + Timer t = remove(timerId); + expired = t.expire(); + if (t.status == Invalid) { + ALOGW_IF(DEBUG, "error: expired invalid timer %u", timerId); + return; + } else { + // The timer is either Running (because it was extended) or expired (and is awaiting an + // accept or discard). + insert(t); + } + } + + // Deliver the notification outside of the lock. + if (expired) { + if (!notifier_(timerId, pid, uid, notifierCookie_, notifierObject_)) { + AutoMutex _l(lock_); + // Notification failed, which means the listener will never call accept() or + // discard(). Do not reinsert the timer. + remove(timerId); + } + } + ALOGI_IF(DEBUG, "expired timer %u", timerId); +} + +void AnrTimerService::insert(const Timer& t) { + running_.insert(t); + if (t.status == Running) { + // Only forward running timers to the ticker. Expired timers are handled separately. + ticker_->insert(t.scheduled, t.id, this); + maxActive_ = std::max(maxActive_, running_.size()); + } +} + +AnrTimerService::Timer AnrTimerService::remove(timer_id_t timerId) { + Timer key(timerId); + auto found = running_.find(key); + if (found != running_.end()) { + Timer result = *found; + running_.erase(found); + ticker_->remove(result.scheduled, result.id); + return result; + } + return Timer(); +} + +void AnrTimerService::dump(bool verbose) const { + AutoMutex _l(lock_); + ALOGI("timer %s ops started=%zu canceled=%zu accepted=%zu discarded=%zu expired=%zu", + label_.c_str(), + counters_.started, counters_.canceled, counters_.accepted, + counters_.discarded, counters_.expired); + ALOGI("timer %s stats max-active=%zu/%zu running=%zu/%zu errors=%zu", + label_.c_str(), + maxActive_, ticker_->maxRunning(), running_.size(), ticker_->running(), + counters_.error); + + if (verbose) { + nsecs_t time = now(); + for (auto i = running_.begin(); i != running_.end(); i++) { + Timer t = *i; + ALOGI(" running %s", t.toString(time).c_str()); + } + } +} + +/** + * True if the native methods are supported in this process. Native methods are supported only + * if the initialization succeeds. + */ +bool nativeSupportEnabled = false; + +/** + * Singleton/globals for the anr timer. Among other things, this includes a Ticker* and a use + * count. The JNI layer creates a single Ticker for all operational AnrTimers. The Ticker is + * created when the first AnrTimer is created, and is deleted when the last AnrTimer is closed. + */ +static Mutex gAnrLock; +struct AnrArgs { + jclass clazz = NULL; + jmethodID func = NULL; + JavaVM* vm = NULL; + AnrTimerService::Ticker* ticker = nullptr; + int tickerUseCount = 0;; +}; +static AnrArgs gAnrArgs; + +// The cookie is the address of the AnrArgs object to which the notification should be sent. +static bool anrNotify(AnrTimerService::timer_id_t timerId, int pid, int uid, + void* cookie, jweak jtimer) { + AutoMutex _l(gAnrLock); + AnrArgs* target = reinterpret_cast<AnrArgs* >(cookie); + JNIEnv *env; + if (target->vm->AttachCurrentThread(&env, 0) != JNI_OK) { + ALOGE("failed to attach thread to JavaVM"); + return false; + } + jboolean r = false; + jobject timer = env->NewGlobalRef(jtimer); + if (timer != nullptr) { + r = env->CallBooleanMethod(timer, target->func, timerId, pid, uid); + env->DeleteGlobalRef(timer); + } + target->vm->DetachCurrentThread(); + return r; +} + +jboolean anrTimerSupported(JNIEnv* env, jclass) { + return nativeSupportEnabled; +} + +jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname) { + if (!nativeSupportEnabled) return 0; + AutoMutex _l(gAnrLock); + if (!gAnrArgs.ticker) { + gAnrArgs.ticker = new AnrTimerService::Ticker(); + } + gAnrArgs.tickerUseCount++; + + ScopedUtfChars name(env, jname); + jobject timer = env->NewWeakGlobalRef(jtimer); + AnrTimerService* service = + new AnrTimerService(name.c_str(), anrNotify, &gAnrArgs, timer, gAnrArgs.ticker); + return reinterpret_cast<jlong>(service); +} + +AnrTimerService *toService(jlong pointer) { + return reinterpret_cast<AnrTimerService*>(pointer); +} + +jint anrTimerClose(JNIEnv* env, jclass, jlong ptr) { + if (!nativeSupportEnabled) return -1; + if (ptr == 0) return -1; + AutoMutex _l(gAnrLock); + AnrTimerService *s = toService(ptr); + env->DeleteWeakGlobalRef(s->jtimer()); + delete s; + if (--gAnrArgs.tickerUseCount <= 0) { + delete gAnrArgs.ticker; + gAnrArgs.ticker = nullptr; + } + return 0; +} + +jint anrTimerStart(JNIEnv* env, jclass, jlong ptr, + jint pid, jint uid, jlong timeout, jboolean extend) { + if (!nativeSupportEnabled) return 0; + // On the Java side, timeouts are expressed in milliseconds and must be converted to + // nanoseconds before being passed to the library code. + return toService(ptr)->start(pid, uid, milliseconds_to_nanoseconds(timeout), extend); +} + +jboolean anrTimerCancel(JNIEnv* env, jclass, jlong ptr, jint timerId) { + if (!nativeSupportEnabled) return false; + return toService(ptr)->cancel(timerId); +} + +jboolean anrTimerAccept(JNIEnv* env, jclass, jlong ptr, jint timerId) { + if (!nativeSupportEnabled) return false; + return toService(ptr)->accept(timerId); +} + +jboolean anrTimerDiscard(JNIEnv* env, jclass, jlong ptr, jint timerId) { + if (!nativeSupportEnabled) return false; + return toService(ptr)->discard(timerId); +} + +jint anrTimerDump(JNIEnv *env, jclass, jlong ptr, jboolean verbose) { + if (!nativeSupportEnabled) return -1; + toService(ptr)->dump(verbose); + return 0; +} + +static const JNINativeMethod methods[] = { + {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, + {"nativeAnrTimerCreate", "(Ljava/lang/String;)J", (void*) anrTimerCreate}, + {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, + {"nativeAnrTimerStart", "(JIIJZ)I", (void*) anrTimerStart}, + {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, + {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, + {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, + {"nativeAnrTimerDump", "(JZ)V", (void*) anrTimerDump}, +}; + +} // anonymous namespace + +int register_android_server_utils_AnrTimer(JNIEnv* env) +{ + static const char *className = "com/android/server/utils/AnrTimer"; + jniRegisterNativeMethods(env, className, methods, NELEM(methods)); + + jclass service = FindClassOrDie(env, className); + gAnrArgs.clazz = MakeGlobalRefOrDie(env, service); + gAnrArgs.func = env->GetMethodID(gAnrArgs.clazz, "expire", "(III)Z"); + env->GetJavaVM(&gAnrArgs.vm); + + nativeSupportEnabled = NATIVE_SUPPORT; + + return 0; +} + +} // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 11734da5b1ac..f3158d11b9a4 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -52,6 +52,7 @@ int register_android_server_Watchdog(JNIEnv* env); int register_android_server_HardwarePropertiesManagerService(JNIEnv* env); int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); +int register_android_server_utils_AnrTimer(JNIEnv *env); int register_android_server_am_OomConnection(JNIEnv* env); int register_android_server_am_CachedAppOptimizer(JNIEnv* env); int register_android_server_am_LowMemDetector(JNIEnv* env); @@ -113,6 +114,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_storage_AppFuse(env); register_android_server_SyntheticPasswordManager(env); register_android_hardware_display_DisplayViewport(env); + register_android_server_utils_AnrTimer(env); register_android_server_am_OomConnection(env); register_android_server_am_CachedAppOptimizer(env); register_android_server_am_LowMemDetector(env); diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 6899ad48b813..31409ab1de4b 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -109,7 +109,7 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(), Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS), /*defaultProviderId=*/flattenedPrimaryProviders), - providerDataList); + providerDataList, /*isRequestForAllOptions=*/ false); mClientCallback.onPendingIntent(mPendingIntent); } catch (RemoteException e) { mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 686b2a813bd3..dfb5a5758448 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -63,6 +63,7 @@ import android.text.TextUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.view.autofill.IAutoFillManagerClient; import com.android.internal.annotations.GuardedBy; import com.android.server.credentials.metrics.ApiName; @@ -483,6 +484,7 @@ public final class CredentialManagerService public ICancellationSignal getCandidateCredentials( GetCredentialRequest request, IGetCandidateCredentialsCallback callback, + IAutoFillManagerClient clientCallback, final String callingPackage) { Slog.i(TAG, "starting getCandidateCredentials with callingPackage: " + callingPackage); @@ -503,7 +505,8 @@ public final class CredentialManagerService request, constructCallingAppInfo(callingPackage, userId, request.getOrigin()), getEnabledProvidersForUser(userId), - CancellationSignal.fromTransport(cancelTransport) + CancellationSignal.fromTransport(cancelTransport), + clientCallback ); 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 3c190bf7ad11..f092dccbcfd1 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java @@ -150,9 +150,12 @@ public class CredentialManagerUi { * * @param requestInfo the information about the request * @param providerDataList the list of provider data from remote providers + * @param isRequestForAllOptions whether the bottom sheet should directly navigate to the + * all options page */ public PendingIntent createPendingIntent( - RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) { + RequestInfo requestInfo, ArrayList<ProviderData> providerDataList, + boolean isRequestForAllOptions) { List<CredentialProviderInfo> allProviders = CredentialProviderInfoFactory.getCredentialProviderServices( mContext, @@ -168,7 +171,8 @@ public class CredentialManagerUi { disabledProvider.getComponentName().flattenToString())).toList(); Intent intent = IntentFactory.createCredentialSelectorIntent(requestInfo, providerDataList, - new ArrayList<>(disabledProviderDataList), mResultReceiver) + new ArrayList<>(disabledProviderDataList), mResultReceiver, + isRequestForAllOptions) .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/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java index 6d9b7e824e28..d1651713fe03 100644 --- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java @@ -16,6 +16,7 @@ package com.android.server.credentials; +import android.Manifest; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; @@ -23,6 +24,7 @@ import android.credentials.CredentialProviderInfo; import android.credentials.GetCandidateCredentialsException; import android.credentials.GetCandidateCredentialsResponse; import android.credentials.GetCredentialRequest; +import android.credentials.GetCredentialResponse; import android.credentials.IGetCandidateCredentialsCallback; import android.credentials.ui.GetCredentialProviderData; import android.credentials.ui.ProviderData; @@ -30,7 +32,9 @@ import android.credentials.ui.RequestInfo; import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; +import android.service.credentials.PermissionUtils; import android.util.Slog; +import android.view.autofill.IAutoFillManagerClient; import java.util.ArrayList; import java.util.List; @@ -42,18 +46,22 @@ import java.util.Set; */ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequest, IGetCandidateCredentialsCallback, GetCandidateCredentialsResponse> - implements ProviderSession.ProviderInternalCallback<GetCandidateCredentialsResponse> { + implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> { private static final String TAG = "GetCandidateRequestSession"; + private final IAutoFillManagerClient mAutoFillCallback; + public GetCandidateRequestSession( Context context, SessionLifetime sessionCallback, Object lock, int userId, int callingUid, IGetCandidateCredentialsCallback callback, GetCredentialRequest request, CallingAppInfo callingAppInfo, Set<ComponentName> enabledProviders, - CancellationSignal cancellationSignal) { + CancellationSignal cancellationSignal, + IAutoFillManagerClient autoFillCallback) { super(context, sessionCallback, lock, userId, callingUid, request, callback, RequestInfo.TYPE_GET, callingAppInfo, enabledProviders, cancellationSignal, 0L); + mAutoFillCallback = autoFillCallback; } /** @@ -92,12 +100,26 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ return; } + cancelExistingPendingIntent(); + mPendingIntent = mCredentialManagerUi.createPendingIntent( + RequestInfo.newGetRequestInfo( + mRequestId, mClientRequest, mClientAppInfo.getPackageName(), + PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(), + Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS)), + providerDataList, + /*isRequestForAllOptions=*/ true); + List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); for (ProviderData providerData : providerDataList) { candidateProviderDataList.add((GetCredentialProviderData) (providerData)); } - respondToClientWithResponseAndFinish(new GetCandidateCredentialsResponse( - candidateProviderDataList)); + + try { + invokeClientCallbackSuccess(new GetCandidateCredentialsResponse( + candidateProviderDataList, mPendingIntent)); + } catch (RemoteException e) { + Slog.e(TAG, "Issue while responding to client with error : " + e); + } } @Override @@ -151,7 +173,8 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ @Override public void onFinalResponseReceived(ComponentName componentName, - GetCandidateCredentialsResponse response) { - // Not applicable for session without UI + GetCredentialResponse response) { + Slog.d(TAG, "onFinalResponseReceived"); + respondToClientWithResponseAndFinish(new GetCandidateCredentialsResponse(response)); } } diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index c9e691e199c7..3f57c804cba0 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -99,21 +99,24 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) { mRequestSessionMetric.collectUiCallStartTime(System.nanoTime()); mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION); - Binder.withCleanCallingIdentity(()-> { - try { + Binder.withCleanCallingIdentity(() -> { + try { cancelExistingPendingIntent(); - mPendingIntent = mCredentialManagerUi.createPendingIntent( - RequestInfo.newGetRequestInfo( - mRequestId, mClientRequest, mClientAppInfo.getPackageName(), - PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(), - Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS)), - providerDataList); - mClientCallback.onPendingIntent(mPendingIntent); - } catch (RemoteException e) { - mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); - mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED); - String exception = GetCredentialException.TYPE_UNKNOWN; - mRequestSessionMetric.collectFrameworkException(exception); + mPendingIntent = mCredentialManagerUi.createPendingIntent( + RequestInfo.newGetRequestInfo( + mRequestId, mClientRequest, mClientAppInfo.getPackageName(), + PermissionUtils.hasPermission(mContext, + mClientAppInfo.getPackageName(), + Manifest.permission + .CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS)), + providerDataList, + /*isRequestForAllOptions=*/ false); + mClientCallback.onPendingIntent(mPendingIntent); + } catch (RemoteException e) { + mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); + mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED); + String exception = GetCredentialException.TYPE_UNKNOWN; + mRequestSessionMetric.collectFrameworkException(exception); respondToClientWithErrorAndFinish(exception, "Unable to instantiate selector"); } }); diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java index f447c1fd277e..fbfc9caf0205 100644 --- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java @@ -192,7 +192,7 @@ public class PrepareGetRequestSession extends GetRequestSession { mRequestId, mClientRequest, mClientAppInfo.getPackageName(), PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(), Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS)), - providerDataList); + providerDataList, /*isRequestForAllOptions=*/ false); } else { 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 a490013303e9..f288103bd954 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -6243,9 +6243,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final long id = mInjector.binderClearCallingIdentity(); try { - final KeyChainConnection keyChainConnection = - KeyChain.bindAsUser(mContext, caller.getUserHandle()); - try { + try (KeyChainConnection keyChainConnection = + KeyChain.bindAsUser(mContext, caller.getUserHandle())) { IKeyChainService keyChain = keyChainConnection.getService(); if (!keyChain.installKeyPair(privKey, cert, chain, alias, KeyStore.UID_SELF)) { logInstallKeyPairFailure(caller, isCredentialManagementApp); @@ -6263,10 +6262,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ? CREDENTIAL_MANAGEMENT_APP : NOT_CREDENTIAL_MANAGEMENT_APP) .write(); return true; - } catch (RemoteException e) { + } catch (RemoteException | AssertionError e) { Slogf.e(LOG_TAG, "Installing certificate", e); - } finally { - keyChainConnection.close(); } } catch (InterruptedException e) { Slogf.w(LOG_TAG, "Interrupted while installing certificate", e); @@ -6313,9 +6310,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final long id = Binder.clearCallingIdentity(); try { - final KeyChainConnection keyChainConnection = - KeyChain.bindAsUser(mContext, caller.getUserHandle()); - try { + try (KeyChainConnection keyChainConnection = + KeyChain.bindAsUser(mContext, caller.getUserHandle())) { IKeyChainService keyChain = keyChainConnection.getService(); DevicePolicyEventLogger .createEvent(DevicePolicyEnums.REMOVE_KEY_PAIR) @@ -6325,10 +6321,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ? CREDENTIAL_MANAGEMENT_APP : NOT_CREDENTIAL_MANAGEMENT_APP) .write(); return keyChain.removeKeyPair(alias); - } catch (RemoteException e) { + } catch (RemoteException | AssertionError e) { Slogf.e(LOG_TAG, "Removing keypair", e); - } finally { - keyChainConnection.close(); } } catch (InterruptedException e) { Slogf.w(LOG_TAG, "Interrupted while removing keypair", e); @@ -6355,7 +6349,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try (KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, caller.getUserHandle())) { return keyChainConnection.getService().containsKeyPair(alias); - } catch (RemoteException e) { + } catch (RemoteException | AssertionError e) { Slogf.e(LOG_TAG, "Querying keypair", e); } catch (InterruptedException e) { Slogf.w(LOG_TAG, "Interrupted while querying keypair", e); @@ -6417,7 +6411,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } return false; - } catch (RemoteException e) { + } catch (RemoteException | AssertionError e) { Slogf.e(LOG_TAG, "Querying grant to wifi auth.", e); return false; } @@ -6497,7 +6491,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } result.put(uid, new ArraySet<String>(packages)); } - } catch (RemoteException e) { + } catch (RemoteException | AssertionError e) { Slogf.e(LOG_TAG, "Querying keypair grants", e); } catch (InterruptedException e) { Slogf.w(LOG_TAG, "Interrupted while querying keypair grants", e); @@ -6667,7 +6661,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { .write(); return true; } - } catch (RemoteException e) { + } catch (RemoteException | AssertionError e) { Slogf.e(LOG_TAG, "KeyChain error while generating a keypair", e); } catch (InterruptedException e) { Slogf.w(LOG_TAG, "Interrupted while generating keypair", e); @@ -6742,7 +6736,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (InterruptedException e) { Slogf.w(LOG_TAG, "Interrupted while setting keypair certificate", e); Thread.currentThread().interrupt(); - } catch (RemoteException e) { + } catch (RemoteException | AssertionError e) { Slogf.e(LOG_TAG, "Failed setting keypair certificate", e); } finally { mInjector.binderRestoreCallingIdentity(id); @@ -7227,7 +7221,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { connection.getService().getCredentialManagementAppPolicy(); return policy != null && !policy.getAppAndUriMappings().isEmpty() && containsAlias(policy, alias); - } catch (RemoteException | InterruptedException e) { + } catch (RemoteException | InterruptedException | AssertionError e) { return false; } }); diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java index 7a84406f1b08..e370f5501865 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -759,6 +759,15 @@ public final class DisplayDeviceConfigTest { AUTO_BRIGHTNESS_MODE_DEFAULT, Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_DIM), SMALL_DELTA); + assertArrayEquals(new float[]{0.0f, 80}, + mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux( + AUTO_BRIGHTNESS_MODE_DEFAULT, + Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT), ZERO_DELTA); + assertArrayEquals(new float[]{0.6f, 0.7f}, + mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels( + AUTO_BRIGHTNESS_MODE_DEFAULT, + Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_BRIGHT), SMALL_DELTA); + assertArrayEquals(new float[]{0.0f, 95}, mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux( AUTO_BRIGHTNESS_MODE_DOZE, @@ -1197,6 +1206,20 @@ public final class DisplayDeviceConfigTest { + "</map>\n" + "</luxToBrightnessMapping>\n" + "<luxToBrightnessMapping>\n" + + "<mode>default</mode>\n" + + "<setting>bright</setting>\n" + + "<map>\n" + + "<point>\n" + + "<first>0</first>\n" + + "<second>0.6</second>\n" + + "</point>\n" + + "<point>\n" + + "<first>80</first>\n" + + "<second>0.7</second>\n" + + "</point>\n" + + "</map>\n" + + "</luxToBrightnessMapping>\n" + + "<luxToBrightnessMapping>\n" + "<mode>doze</mode>\n" + "<map>\n" + "<point>\n" diff --git a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java index 6f9b6faa0bb0..8f5d1253406e 100644 --- a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java +++ b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java @@ -62,7 +62,7 @@ import java.util.List; import java.util.Set; @RunWith(JUnit4.class) -public class AudioPoliciesDeviceRouteControllerTest { +public class AudioManagerRouteControllerTest { private static final String FAKE_ROUTE_NAME = "fake name"; private static final AudioDeviceInfo FAKE_AUDIO_DEVICE_INFO_BUILTIN_SPEAKER = @@ -89,7 +89,7 @@ public class AudioPoliciesDeviceRouteControllerTest { private Set<AudioDeviceInfo> mAvailableAudioDeviceInfos; @Mock private AudioManager mMockAudioManager; @Mock private DeviceRouteController.OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; - private AudioPoliciesDeviceRouteController mControllerUnderTest; + private AudioManagerRouteController mControllerUnderTest; private AudioDeviceCallback mAudioDeviceCallback; private AudioProductStrategy mMediaAudioProductStrategy; @@ -116,7 +116,7 @@ public class AudioPoliciesDeviceRouteControllerTest { BluetoothAdapter btAdapter = realContext.getSystemService(BluetoothManager.class).getAdapter(); mControllerUnderTest = - new AudioPoliciesDeviceRouteController( + new AudioManagerRouteController( mockContext, mMockAudioManager, Looper.getMainLooper(), diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 2f909f818bfe..fcb3caa19b85 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -824,24 +824,24 @@ public class ActivityManagerServiceTest { final BroadcastOptions options = BroadcastOptions.makeWithDeferUntilActive(true); broadcastIntent(intent1, null, true); - assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER), + assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, TEST_USER), StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN)); - assertNull(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER)); - assertNull(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER)); + assertNull(mAms.getStickyBroadcastsForTest(TEST_ACTION2, TEST_USER)); + assertNull(mAms.getStickyBroadcastsForTest(TEST_ACTION3, TEST_USER)); broadcastIntent(intent2, options.toBundle(), true); - assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER), + assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, TEST_USER), StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN)); - assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER), + assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION2, TEST_USER), StickyBroadcast.create(intent2, true, Process.myUid(), PROCESS_STATE_UNKNOWN)); - assertNull(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER)); + assertNull(mAms.getStickyBroadcastsForTest(TEST_ACTION3, TEST_USER)); broadcastIntent(intent3, null, true); - assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION1, TEST_USER), + assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION1, TEST_USER), StickyBroadcast.create(intent1, false, Process.myUid(), PROCESS_STATE_UNKNOWN)); - assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION2, TEST_USER), + assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION2, TEST_USER), StickyBroadcast.create(intent2, true, Process.myUid(), PROCESS_STATE_UNKNOWN)); - assertStickyBroadcasts(mAms.getStickyBroadcasts(TEST_ACTION3, TEST_USER), + assertStickyBroadcasts(mAms.getStickyBroadcastsForTest(TEST_ACTION3, TEST_USER), StickyBroadcast.create(intent3, false, Process.myUid(), PROCESS_STATE_UNKNOWN)); } 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 115a5b0d53f2..e7aaed4edbff 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -67,6 +67,7 @@ import android.content.IIntentReceiver; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.os.Binder; import android.os.Bundle; import android.os.DeadObjectException; @@ -1878,6 +1879,32 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { } @Test + public void testReplacePending_withSingletonReceiver() throws Exception { + final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_PHONE); + final ProcessRecord systemApp = makeActiveProcessRecord(PACKAGE_ANDROID, PROCESS_SYSTEM); + + final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED) + .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + + final ResolveInfo systemReceiverA = makeManifestReceiver(PACKAGE_ANDROID, PROCESS_SYSTEM, + CLASS_BLUE, USER_SYSTEM); + final ResolveInfo systemReceiverB = makeManifestReceiver(PACKAGE_ANDROID, PROCESS_SYSTEM, + CLASS_BLUE, USER_GUEST); + + enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of( + systemReceiverA, systemReceiverB))); + + assertEquals("Unexpected userId for receiverA", USER_SYSTEM, + UserHandle.getUserId(systemReceiverA.activityInfo.applicationInfo.uid)); + assertEquals("Unexpected userId for receiverB", USER_SYSTEM, + UserHandle.getUserId(systemReceiverB.activityInfo.applicationInfo.uid)); + + waitForIdle(); + + verifyScheduleReceiver(times(2), systemApp, airplane); + } + + @Test public void testIdleAndBarrier() throws Exception { final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED); final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceDemoModeTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceDemoModeTest.kt new file mode 100644 index 000000000000..dfdb0c7241c4 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceDemoModeTest.kt @@ -0,0 +1,80 @@ +/* + * 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.pm + +import android.content.res.Configuration +import android.os.Looper +import android.os.SystemProperties +import android.os.UserHandle +import android.util.ArrayMap +import com.android.server.LockGuard +import com.android.server.extendedtestutils.wheneverStatic +import com.android.server.testutils.whenever +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.MockitoAnnotations + +@RunWith(JUnit4::class) +class UserManagerServiceDemoModeTest { + private lateinit var ums: UserManagerService + + @Rule + @JvmField + val rule = MockSystemRule() + + @Before + @Throws(Exception::class) + fun setUp() { + MockitoAnnotations.initMocks(this) + rule.system().stageNominalSystemState() + + if (Looper.myLooper() == null) { + Looper.prepare() + } + + wheneverStatic { LockGuard.installNewLock(LockGuard.INDEX_USER) }.thenReturn(Object()) + whenever(rule.mocks().systemConfig.getAndClearPackageToUserTypeWhitelist()).thenReturn(ArrayMap<String, Set<String>>()) + whenever(rule.mocks().systemConfig.getAndClearPackageToUserTypeBlacklist()).thenReturn(ArrayMap<String, Set<String>>()) + whenever(rule.mocks().resources.getStringArray(com.android.internal.R.array.config_defaultFirstUserRestrictions)).thenReturn(arrayOf<String>()) + whenever(rule.mocks().resources.configuration).thenReturn(Configuration()) + + ums = UserManagerService(rule.mocks().context) + } + + @Test + fun isDemoUser_returnsTrue_whenSystemPropertyIsSet() { + wheneverStatic { SystemProperties.getBoolean("ro.boot.arc_demo_mode", false) }.thenReturn(true) + + assertThat(ums.isDemoUser(0)).isTrue() + } + + @Test + fun isDemoUser_returnsFalse_whenSystemPropertyIsSet() { + wheneverStatic { SystemProperties.getBoolean("ro.boot.arc_demo_mode", false) }.thenReturn(false) + + assertThat(ums.isDemoUser(0)).isFalse() + } + + @Test + fun isDemoUser_returnsFalse_whenSystemPropertyIsNotSet() { + assertThat(ums.isDemoUser(0)).isFalse() + } +}
\ No newline at end of file diff --git a/services/tests/servicestests/jni/Android.bp b/services/tests/servicestests/jni/Android.bp index 174beb81d3eb..c30e4eb666b4 100644 --- a/services/tests/servicestests/jni/Android.bp +++ b/services/tests/servicestests/jni/Android.bp @@ -23,6 +23,7 @@ cc_library_shared { ":lib_cachedAppOptimizer_native", ":lib_gameManagerService_native", ":lib_oomConnection_native", + ":lib_anrTimer_native", "onload.cpp", ], @@ -55,4 +56,4 @@ cc_library_shared { "android.hardware.graphics.mapper@4.0", "android.hidl.token@1.0-utils", ], -}
\ No newline at end of file +} diff --git a/services/tests/servicestests/jni/onload.cpp b/services/tests/servicestests/jni/onload.cpp index f160b3d97367..25487c5aabbe 100644 --- a/services/tests/servicestests/jni/onload.cpp +++ b/services/tests/servicestests/jni/onload.cpp @@ -27,6 +27,7 @@ namespace android { int register_android_server_am_CachedAppOptimizer(JNIEnv* env); int register_android_server_app_GameManagerService(JNIEnv* env); int register_android_server_am_OomConnection(JNIEnv* env); +int register_android_server_utils_AnrTimer(JNIEnv *env); }; using namespace android; @@ -44,5 +45,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_am_CachedAppOptimizer(env); register_android_server_app_GameManagerService(env); register_android_server_am_OomConnection(env); + register_android_server_utils_AnrTimer(env); return JNI_VERSION_1_4; } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index efcdbd488a39..1cd61e90126e 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -44,10 +44,6 @@ import android.content.Context; import android.graphics.PointF; import android.os.Looper; import android.os.SystemClock; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.testing.DexmakerShareClassLoaderRule; import android.view.InputDevice; import android.view.MotionEvent; @@ -60,7 +56,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.AccessibilityTraceManager; import com.android.server.accessibility.EventStreamTransformation; -import com.android.server.accessibility.Flags; import com.android.server.accessibility.utils.GestureLogParser; import com.android.server.testutils.OffsettableClock; @@ -81,7 +76,6 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; - @RunWith(AndroidJUnit4.class) public class TouchExplorerTest { @@ -125,9 +119,6 @@ public class TouchExplorerTest { public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - /** * {@link TouchExplorer#sendDownForAllNotInjectedPointers} injecting events with the same object * is resulting {@link ArgumentCaptor} to capture events with last state. Before implementation @@ -170,42 +161,11 @@ public class TouchExplorerTest { goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER); // Wait for transiting to touch exploring state. mHandler.fastForward(2 * USER_INTENT_TIMEOUT); - assertState(STATE_TOUCH_EXPLORING); - // Manually construct the next move event. Using moveEachPointers() will batch the move - // event which produces zero movement for some reason. - float[] x = new float[1]; - float[] y = new float[1]; - x[0] = mLastEvent.getX(0) + mTouchSlop; - y[0] = mLastEvent.getY(0) + mTouchSlop; - send(manyPointerEvent(ACTION_MOVE, x, y)); - goToStateClearFrom(STATE_TOUCH_EXPLORING_1FINGER); - assertCapturedEvents(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT); - } - - /** - * Test the case where ACTION_DOWN is followed by a number of ACTION_MOVE events that do not - * change the coordinates. - */ - @Test - @RequiresFlagsEnabled(Flags.FLAG_REDUCE_TOUCH_EXPLORATION_SENSITIVITY) - public void testOneFingerMoveWithExtraMoveEvents_generatesOneMoveEvent() { - goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER); - // Inject a set of move events that have the same coordinates as the down event. - moveEachPointers(mLastEvent, p(0, 0)); - send(mLastEvent); - // Wait for transition to touch exploring state. - mHandler.fastForward(2 * USER_INTENT_TIMEOUT); - // Now move for real. - moveAtLeastTouchSlop(mLastEvent); - send(mLastEvent); - // One more move event with no change. - moveEachPointers(mLastEvent, p(0, 0)); + moveEachPointers(mLastEvent, p(10, 10)); send(mLastEvent); goToStateClearFrom(STATE_TOUCH_EXPLORING_1FINGER); - assertCapturedEvents( - ACTION_HOVER_ENTER, - ACTION_HOVER_MOVE, - ACTION_HOVER_EXIT); + assertCapturedEvents(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT); + assertState(STATE_TOUCH_EXPLORING); } /** @@ -213,8 +173,7 @@ public class TouchExplorerTest { * change the coordinates. */ @Test - @RequiresFlagsDisabled(Flags.FLAG_REDUCE_TOUCH_EXPLORATION_SENSITIVITY) - public void testOneFingerMoveWithExtraMoveEvents_generatesThreeMoveEvent() { + public void testOneFingerMoveWithExtraMoveEvents() { goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER); // Inject a set of move events that have the same coordinates as the down event. moveEachPointers(mLastEvent, p(0, 0)); @@ -222,7 +181,7 @@ public class TouchExplorerTest { // Wait for transition to touch exploring state. mHandler.fastForward(2 * USER_INTENT_TIMEOUT); // Now move for real. - moveAtLeastTouchSlop(mLastEvent); + moveEachPointers(mLastEvent, p(10, 10)); send(mLastEvent); // One more move event with no change. moveEachPointers(mLastEvent, p(0, 0)); @@ -283,7 +242,7 @@ public class TouchExplorerTest { moveEachPointers(mLastEvent, p(0, 0), p(0, 0)); send(mLastEvent); // Now move for real. - moveEachPointers(mLastEvent, p(mTouchSlop, mTouchSlop), p(mTouchSlop, mTouchSlop)); + moveEachPointers(mLastEvent, p(10, 10), p(10, 10)); send(mLastEvent); goToStateClearFrom(STATE_DRAGGING_2FINGERS); assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_MOVE, ACTION_UP); @@ -292,7 +251,7 @@ public class TouchExplorerTest { @Test public void testUpEvent_OneFingerMove_clearStateAndInjectHoverEvents() { goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER); - moveAtLeastTouchSlop(mLastEvent); + moveEachPointers(mLastEvent, p(10, 10)); send(mLastEvent); // Wait 10 ms to make sure that hover enter and exit are not scheduled for the same moment. mHandler.fastForward(10); @@ -318,7 +277,7 @@ public class TouchExplorerTest { // Wait for the finger moving to the second view. mHandler.fastForward(oneThirdUserIntentTimeout); - moveAtLeastTouchSlop(mLastEvent); + moveEachPointers(mLastEvent, p(10, 10)); send(mLastEvent); // Wait for the finger lifting from the second view. @@ -443,6 +402,7 @@ public class TouchExplorerTest { // Manually construct the next move event. Using moveEachPointers() will batch the move // event onto the pointer up event which will mean that the move event still has a pointer // count of 3. + // Todo: refactor to avoid using batching as there is no special reason to do it that way. float[] x = new float[2]; float[] y = new float[2]; x[0] = mLastEvent.getX(0) + 100; @@ -774,9 +734,6 @@ public class TouchExplorerTest { } } - private void moveAtLeastTouchSlop(MotionEvent event) { - moveEachPointers(event, p(2 * mTouchSlop, 0)); - } /** * A {@link android.os.Handler} that doesn't process messages until {@link #fastForward(int)} is * invoked. diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java index 18e6f0a2cc57..132b6219977a 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java @@ -164,6 +164,19 @@ public class GenericWindowPolicyControllerTest { } @Test + public void userNotAllowlisted_systemUserCanLaunchBlockedAppStreamingActivity() { + GenericWindowPolicyController gwpc = createGwpcWithNoAllowedUsers(); + gwpc.setDisplayId(DISPLAY_ID, /* isMirrorDisplay= */ false); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_APP_STREAMING_COMPONENT.getPackageName(), + BLOCKED_APP_STREAMING_COMPONENT.getClassName(), + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test public void openNonBlockedAppOnVirtualDisplay_isNotBlocked() { GenericWindowPolicyController gwpc = createGwpc(); gwpc.setDisplayId(DISPLAY_ID, /* isMirrorDisplay= */ false); diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java index 0d25faf2bcf1..a2f8c8bbe13e 100644 --- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java @@ -1236,24 +1236,17 @@ public class InputMethodUtilsTest { // Init InputMethodSettings for the owner user (userId=0), verify calls can get the // corresponding user's context, contentResolver and the resources configuration. InputMethodUtils.InputMethodSettings settings = new InputMethodUtils.InputMethodSettings( - methodMap, 0 /* userId */, true); + methodMap, 0 /* userId */); assertEquals(0, settings.getCurrentUserId()); - settings.isShowImeWithHardKeyboardEnabled(); - verify(ownerUserContext.getContentResolver(), atLeastOnce()).getAttributionSource(); - settings.getEnabledInputMethodSubtypeListLocked(nonSystemIme, true); verify(ownerUserContext.getResources(), atLeastOnce()).getConfiguration(); // Calling switchCurrentUser to the secondary user (userId=10), verify calls can get the // corresponding user's context, contentResolver and the resources configuration. - settings.switchCurrentUser(10 /* userId */, true); + settings.switchCurrentUser(10 /* userId */); assertEquals(10, settings.getCurrentUserId()); - settings.isShowImeWithHardKeyboardEnabled(); - verify(TestContext.getSecondaryUserContext().getContentResolver(), - atLeastOnce()).getAttributionSource(); - settings.getEnabledInputMethodSubtypeListLocked(nonSystemIme, true); verify(TestContext.getSecondaryUserContext().getResources(), atLeastOnce()).getConfiguration(); diff --git a/services/tests/servicestests/src/com/android/server/media/BluetoothRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/BluetoothRouteControllerTest.java deleted file mode 100644 index 06f117bdbd65..000000000000 --- a/services/tests/servicestests/src/com/android/server/media/BluetoothRouteControllerTest.java +++ /dev/null @@ -1,74 +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.server.media; - -import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER; - -import android.content.Context; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; - -import androidx.test.platform.app.InstrumentationRegistry; - -import com.google.common.truth.Truth; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class BluetoothRouteControllerTest { - - private final BluetoothRouteController.BluetoothRoutesUpdatedListener - mBluetoothRoutesUpdatedListener = - () -> { - // Empty on purpose. - }; - - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - - private Context mContext; - - @Before - public void setUp() { - mContext = InstrumentationRegistry.getInstrumentation().getContext(); - } - - @Test - @RequiresFlagsDisabled(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER) - public void createInstance_audioPoliciesFlagIsDisabled_createsLegacyController() { - BluetoothRouteController deviceRouteController = - BluetoothRouteController.createInstance(mContext, mBluetoothRoutesUpdatedListener); - - Truth.assertThat(deviceRouteController).isInstanceOf(LegacyBluetoothRouteController.class); - } - - @Test - @RequiresFlagsEnabled(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER) - public void createInstance_audioPoliciesFlagIsEnabled_createsAudioPoliciesController() { - BluetoothRouteController deviceRouteController = - BluetoothRouteController.createInstance(mContext, mBluetoothRoutesUpdatedListener); - - Truth.assertThat(deviceRouteController) - .isInstanceOf(AudioPoliciesBluetoothRouteController.class); - } -} diff --git a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java index 0961b7d97177..eb789615b978 100644 --- a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java @@ -70,7 +70,6 @@ public class DeviceRouteControllerTest { DeviceRouteController.createInstance( mContext, Looper.getMainLooper(), mOnDeviceRouteChangedListener); - Truth.assertThat(deviceRouteController) - .isInstanceOf(AudioPoliciesDeviceRouteController.class); + Truth.assertThat(deviceRouteController).isInstanceOf(AudioManagerRouteController.class); } } diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java index 835ccf0b19f6..6fffd7533df8 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java @@ -112,7 +112,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { testServiceDefaultValue_On(ServiceType.NULL); } - @Suppress + @Suppress // TODO: b/317823111 - Remove once test fixed. @SmallTest public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() { testDefaultValue( @@ -219,7 +219,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { ServiceType.QUICK_DOZE); } - @Suppress + @Suppress // TODO: b/317823111 - Remove once test fixed. @SmallTest public void testUpdateConstants_getCorrectData() { mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_CONSTANTS, ""); @@ -327,6 +327,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { } } + @Suppress // TODO: b/317823111 - Remove once test fixed. public void testSetPolicyLevel_Adaptive() { mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_ADAPTIVE); diff --git a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java index 861d14a2cf66..6c085e085f4e 100644 --- a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java +++ b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java @@ -23,17 +23,21 @@ import static org.junit.Assert.assertTrue; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.util.Log; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import com.android.internal.annotations.GuardedBy; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -45,6 +49,9 @@ import java.util.concurrent.TimeUnit; @RunWith(Parameterized.class) public class AnrTimerTest { + // A log tag. + private static final String TAG = "AnrTimerTest"; + // The commonly used message timeout key. private static final int MSG_TIMEOUT = 1; @@ -63,9 +70,7 @@ public class AnrTimerTest { } } - /** - * The test handler is a self-contained object for a single test. - */ + /** The test helper is a self-contained object for a single test. */ private static class Helper { final Object mLock = new Object(); @@ -114,7 +119,7 @@ public class AnrTimerTest { /** * Force AnrTimer to use the test parameter for the feature flag. */ - class TestInjector extends AnrTimer.Injector { + private class TestInjector extends AnrTimer.Injector { @Override boolean anrTimerServiceEnabled() { return mEnabled; @@ -124,9 +129,9 @@ public class AnrTimerTest { /** * An instrumented AnrTimer. */ - private static class TestAnrTimer extends AnrTimer<TestArg> { + private class TestAnrTimer extends AnrTimer<TestArg> { private TestAnrTimer(Handler h, int key, String tag) { - super(h, key, tag); + super(h, key, tag, false, new TestInjector()); } TestAnrTimer(Helper helper) { @@ -173,35 +178,103 @@ public class AnrTimerTest { @Test public void testSimpleTimeout() throws Exception { Helper helper = new Helper(1); - TestAnrTimer timer = new TestAnrTimer(helper); - TestArg t = new TestArg(1, 1); - timer.start(t, 10); - // Delivery is immediate but occurs on a different thread. - assertTrue(helper.await(5000)); - TestArg[] result = helper.messages(1); - validate(t, result[0]); + try (TestAnrTimer timer = new TestAnrTimer(helper)) { + // One-time check that the injector is working as expected. + assertEquals(mEnabled, timer.serviceEnabled()); + TestArg t = new TestArg(1, 1); + timer.start(t, 10); + // Delivery is immediate but occurs on a different thread. + assertTrue(helper.await(5000)); + TestArg[] result = helper.messages(1); + validate(t, result[0]); + } } /** - * Verify that if three timers are scheduled, they are delivered in time order. + * Verify that a restarted timer is delivered exactly once. The initial timer value is very + * large, to ensure it does not expire before the timer can be restarted. + */ + @Test + public void testTimerRestart() throws Exception { + Helper helper = new Helper(1); + try (TestAnrTimer timer = new TestAnrTimer(helper)) { + TestArg t = new TestArg(1, 1); + timer.start(t, 10000); + // Briefly pause. + assertFalse(helper.await(10)); + timer.start(t, 10); + // Delivery is immediate but occurs on a different thread. + assertTrue(helper.await(5000)); + TestArg[] result = helper.messages(1); + validate(t, result[0]); + } + } + + /** + * Verify that a restarted timer is delivered exactly once. The initial timer value is very + * large, to ensure it does not expire before the timer can be restarted. + */ + @Test + public void testTimerZero() throws Exception { + Helper helper = new Helper(1); + try (TestAnrTimer timer = new TestAnrTimer(helper)) { + TestArg t = new TestArg(1, 1); + timer.start(t, 0); + // Delivery is immediate but occurs on a different thread. + assertTrue(helper.await(5000)); + TestArg[] result = helper.messages(1); + validate(t, result[0]); + } + } + + /** + * Verify that if three timers are scheduled on a single AnrTimer, they are delivered in time + * order. */ @Test public void testMultipleTimers() throws Exception { // Expect three messages. Helper helper = new Helper(3); - TestAnrTimer timer = new TestAnrTimer(helper); TestArg t1 = new TestArg(1, 1); TestArg t2 = new TestArg(1, 2); TestArg t3 = new TestArg(1, 3); - timer.start(t1, 50); - timer.start(t2, 60); - timer.start(t3, 40); - // Delivery is immediate but occurs on a different thread. - assertTrue(helper.await(5000)); - TestArg[] result = helper.messages(3); - validate(t3, result[0]); - validate(t1, result[1]); - validate(t2, result[2]); + try (TestAnrTimer timer = new TestAnrTimer(helper)) { + timer.start(t1, 50); + timer.start(t2, 60); + timer.start(t3, 40); + // Delivery is immediate but occurs on a different thread. + assertTrue(helper.await(5000)); + TestArg[] result = helper.messages(3); + validate(t3, result[0]); + validate(t1, result[1]); + validate(t2, result[2]); + } + } + + /** + * Verify that if three timers are scheduled on three separate AnrTimers, they are delivered + * in time order. + */ + @Test + public void testMultipleServices() throws Exception { + // Expect three messages. + Helper helper = new Helper(3); + TestArg t1 = new TestArg(1, 1); + TestArg t2 = new TestArg(1, 2); + TestArg t3 = new TestArg(1, 3); + try (TestAnrTimer x1 = new TestAnrTimer(helper); + TestAnrTimer x2 = new TestAnrTimer(helper); + TestAnrTimer x3 = new TestAnrTimer(helper)) { + x1.start(t1, 50); + x2.start(t2, 60); + x3.start(t3, 40); + // Delivery is immediate but occurs on a different thread. + assertTrue(helper.await(5000)); + TestArg[] result = helper.messages(3); + validate(t3, result[0]); + validate(t1, result[1]); + validate(t2, result[2]); + } } /** @@ -211,20 +284,109 @@ public class AnrTimerTest { public void testCancelTimer() throws Exception { // Expect two messages. Helper helper = new Helper(2); - TestAnrTimer timer = new TestAnrTimer(helper); TestArg t1 = new TestArg(1, 1); TestArg t2 = new TestArg(1, 2); TestArg t3 = new TestArg(1, 3); - timer.start(t1, 50); - timer.start(t2, 60); - timer.start(t3, 40); - // Briefly pause. - assertFalse(helper.await(10)); - timer.cancel(t1); - // Delivery is immediate but occurs on a different thread. - assertTrue(helper.await(5000)); - TestArg[] result = helper.messages(2); - validate(t3, result[0]); - validate(t2, result[1]); + try (TestAnrTimer timer = new TestAnrTimer(helper)) { + timer.start(t1, 50); + timer.start(t2, 60); + timer.start(t3, 40); + // Briefly pause. + assertFalse(helper.await(10)); + timer.cancel(t1); + // Delivery is immediate but occurs on a different thread. + assertTrue(helper.await(5000)); + TestArg[] result = helper.messages(2); + validate(t3, result[0]); + validate(t2, result[1]); + } + } + + /** + * Return the dump string. + */ + private String getDumpOutput() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + AnrTimer.dump(pw, true, new TestInjector()); + pw.close(); + return sw.getBuffer().toString(); + } + + /** + * Verify the dump output. + */ + @Test + public void testDumpOutput() throws Exception { + String r1 = getDumpOutput(); + assertEquals(false, r1.contains("timer:")); + + Helper helper = new Helper(2); + TestArg t1 = new TestArg(1, 1); + TestArg t2 = new TestArg(1, 2); + TestArg t3 = new TestArg(1, 3); + try (TestAnrTimer timer = new TestAnrTimer(helper)) { + timer.start(t1, 5000); + timer.start(t2, 5000); + timer.start(t3, 5000); + + String r2 = getDumpOutput(); + // There are timers in the list if and only if the feature is enabled. + final boolean expected = mEnabled; + assertEquals(expected, r2.contains("timer:")); + } + + String r3 = getDumpOutput(); + assertEquals(false, r3.contains("timer:")); + } + + /** + * Verify that GC works as expected. This test will almost certainly be flaky, since it + * relies on the finalizers running, which is a best-effort on the part of the JVM. + * Therefore, the test is marked @Ignore. Remove that annotation to run the test locally. + */ + @Ignore + @Test + public void testGarbageCollection() throws Exception { + if (!mEnabled) return; + + String r1 = getDumpOutput(); + assertEquals(false, r1.contains("timer:")); + + Helper helper = new Helper(2); + TestArg t1 = new TestArg(1, 1); + TestArg t2 = new TestArg(1, 2); + TestArg t3 = new TestArg(1, 3); + // The timer is explicitly not closed. It is, however, scoped to the next block. + { + TestAnrTimer timer = new TestAnrTimer(helper); + timer.start(t1, 5000); + timer.start(t2, 5000); + timer.start(t3, 5000); + + String r2 = getDumpOutput(); + // There are timers in the list if and only if the feature is enabled. + final boolean expected = mEnabled; + assertEquals(expected, r2.contains("timer:")); + } + + // Try to make finalizers run. The timer object above should be a candidate. Finalizers + // are run on their own thread, so pause this thread to give that thread some time. + String r3 = getDumpOutput(); + for (int i = 0; i < 10 && r3.contains("timer:"); i++) { + Log.i(TAG, "requesting finalization " + i); + System.gc(); + System.runFinalization(); + Thread.sleep(4 * 1000); + r3 = getDumpOutput(); + } + + // The timer was not explicitly closed but it should have been implicitly closed by GC. + assertEquals(false, r3.contains("timer:")); + } + + // TODO: [b/302724778] Remove manual JNI load + static { + System.loadLibrary("servicestestjni"); } } 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 3ab7496eff84..f1edd9a59b99 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -16,11 +16,14 @@ package com.android.server.notification; +import static android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS; +import static android.Manifest.permission.STATUS_BAR_SERVICE; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE; import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS; import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP; import static android.app.Notification.EXTRA_PICTURE; import static android.app.Notification.EXTRA_PICTURE_ICON; @@ -60,6 +63,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BA import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_MUTABLE; import static android.app.PendingIntent.FLAG_ONE_SHOT; +import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; +import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.PackageManager.FEATURE_TELECOM; import static android.content.pm.PackageManager.FEATURE_WATCH; @@ -106,6 +111,7 @@ import static com.android.server.notification.NotificationRecordLogger.Notificat import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED; import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED; +import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -118,6 +124,7 @@ import static junit.framework.Assert.assertSame; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Matchers.anyBoolean; @@ -296,7 +303,6 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; @@ -547,6 +553,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager); mContext.addMockSystemService(NotificationManager.class, mMockNm); + doNothing().when(mContext).sendBroadcast(any(), anyString()); doNothing().when(mContext).sendBroadcastAsUser(any(), any()); doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); @@ -570,6 +577,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid); when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer( (Answer<Boolean>) invocation -> { + // TODO: b/317957802 - This is overly broad and basically makes ANY + // isSameApp() check pass, requiring Mockito.reset() for meaningful + // tests! Make it more precise. Object[] args = invocation.getArguments(); return (int) args[1] == mUid; }); @@ -909,7 +919,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } private ApplicationInfo getApplicationInfo(String pkg, int uid) { final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = pkg; applicationInfo.uid = uid; + applicationInfo.sourceDir = mContext.getApplicationInfo().sourceDir; switch (pkg) { case PKG_N_MR1: applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; @@ -5535,15 +5547,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testBumpFGImportance_channelChangePreOApp() throws Exception { - String preOPkg = PKG_N_MR1; - final ApplicationInfo legacy = new ApplicationInfo(); - legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; - when(mPackageManagerClient.getApplicationInfoAsUser(eq(preOPkg), anyInt(), anyInt())) - .thenReturn(legacy); - when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt())) - .thenReturn(Binder.getCallingUid()); - getContext().setMockPackageManager(mPackageManagerClient); - Notification.Builder nb = new Notification.Builder(mContext, NotificationChannel.DEFAULT_CHANNEL_ID) .setContentTitle("foo") @@ -5551,7 +5554,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setFlag(FLAG_FOREGROUND_SERVICE, true) .setPriority(Notification.PRIORITY_MIN); - StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, + StatusBarNotification sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9, "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(), 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0); @@ -5571,11 +5574,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setFlag(FLAG_FOREGROUND_SERVICE, true) .setPriority(Notification.PRIORITY_MIN); - sbn = new StatusBarNotification(preOPkg, preOPkg, 9, + sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9, "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(), 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0); - mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, + mBinderService.enqueueNotificationWithTag(PKG_N_MR1, PKG_N_MR1, "testBumpFGImportance_channelChangePreOApp", sbn.getId(), sbn.getNotification(), sbn.getUserId()); waitForIdle(); @@ -5583,7 +5586,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.getNotificationRecord(sbn.getKey()).getImportance()); NotificationChannel defaultChannel = mBinderService.getNotificationChannel( - preOPkg, mContext.getUserId(), preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID); + PKG_N_MR1, mContext.getUserId(), PKG_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID); assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance()); } @@ -9139,31 +9142,98 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) .setType(AutomaticZenRule.TYPE_MANAGED) - .setOwner(new ComponentName("pkg", "cls")) + .setOwner(new ComponentName(PKG, "cls")) .build(); when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true); - mBinderService.addAutomaticZenRule(rule, "pkg", /* fromUser= */ false); + mBinderService.addAutomaticZenRule(rule, PKG, /* fromUser= */ false); + + verify(zenModeHelper).addAutomaticZenRule(eq(PKG), eq(rule), anyInt(), any(), anyInt()); + } - verify(zenModeHelper).addAutomaticZenRule(eq("pkg"), eq(rule), anyInt(), any(), anyInt()); + @Test + @EnableFlags(android.app.Flags.FLAG_MODES_API) + public void testAddAutomaticZenRule_typeManagedCanBeUsedBySystem() throws Exception { + addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_MANAGED); } @Test @EnableFlags(android.app.Flags.FLAG_MODES_API) public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception { + addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( + AutomaticZenRule.TYPE_MANAGED); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_MODES_API) + public void testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing() throws Exception { + ZenModeHelper zenModeHelper = setUpMockZenTest(); + mService.setCallerIsNormalPackage(); + reset(mPackageManagerInternal); + when(mPackageManagerInternal.isSameApp(eq(PKG), eq(mUid), anyInt())).thenReturn(true); + when(mResources + .getString(com.android.internal.R.string.config_systemWellbeing)) + .thenReturn(PKG); + when(mContext.getResources()).thenReturn(mResources); + + AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setOwner(new ComponentName(PKG, "cls")) + .build(); + + mBinderService.addAutomaticZenRule(rule, PKG, /* fromUser= */ false); + + verify(zenModeHelper).addAutomaticZenRule(eq(PKG), eq(rule), anyInt(), any(), anyInt()); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_MODES_API) + public void testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem() throws Exception { + reset(mPackageManagerInternal); + when(mPackageManagerInternal.isSameApp(eq(PKG), eq(mUid), anyInt())).thenReturn(true); + addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_BEDTIME); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_MODES_API) + public void testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps() throws Exception { + reset(mPackageManagerInternal); + when(mPackageManagerInternal.isSameApp(eq(PKG), eq(mUid), anyInt())).thenReturn(true); + addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( + AutomaticZenRule.TYPE_BEDTIME); + } + + private void addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( + @AutomaticZenRule.Type int ruleType) throws Exception { + ZenModeHelper zenModeHelper = setUpMockZenTest(); + mService.isSystemUid = true; + + AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) + .setType(ruleType) + .setOwner(new ComponentName(PKG, "cls")) + .build(); + when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true); + + mBinderService.addAutomaticZenRule(rule, PKG, /* fromUser= */ false); + + verify(zenModeHelper).addAutomaticZenRule(eq(PKG), eq(rule), anyInt(), any(), anyInt()); + } + + private void addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( + @AutomaticZenRule.Type int ruleType) { mService.setCallerIsNormalPackage(); mService.setZenHelper(mock(ZenModeHelper.class)); when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) .thenReturn(true); AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) - .setType(AutomaticZenRule.TYPE_MANAGED) - .setOwner(new ComponentName("pkg", "cls")) + .setType(ruleType) + .setOwner(new ComponentName(PKG, "cls")) .build(); when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(false); assertThrows(IllegalArgumentException.class, - () -> mBinderService.addAutomaticZenRule(rule, "pkg", /* fromUser= */ false)); + () -> mBinderService.addAutomaticZenRule(rule, PKG, /* fromUser= */ false)); } @Test @@ -9300,6 +9370,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyInt()); } + /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */ private ZenModeHelper setUpMockZenTest() { ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); mService.setZenHelper(zenModeHelper); @@ -11266,6 +11337,40 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testMigrateNotificationFilter_invalidPackage() throws Exception { + int[] userIds = new int[] {mUserId, 1000}; + when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); + List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries"); + for (int userId : userIds) { + when(mPackageManager.getPackageUid("apples", 0, userId)).thenThrow( + new RemoteException("")); + when(mPackageManager.getPackageUid("bananas", 0, userId)).thenReturn(9000); + when(mPackageManager.getPackageUid("cherries", 0, userId)).thenReturn(9001); + } + + when(mListeners.getNotificationListenerFilter(any())).thenReturn( + new NotificationListenerFilter()); + + mBinderService.migrateNotificationFilter(null, + FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, + disallowedApps); + + ArgumentCaptor<NotificationListenerFilter> captor = + ArgumentCaptor.forClass(NotificationListenerFilter.class); + verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); + + assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, + captor.getValue().getTypes()); + // valid values stay + assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("bananas", 9000))); + assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9001))); + // don't store invalid values + for (VersionedPackage vp : captor.getValue().getDisallowedPackages()) { + assertNotEquals("apples", vp.getPackageName()); + } + } + + @Test public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception { int[] userIds = new int[] {mUserId}; when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); @@ -13871,6 +13976,76 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + @EnableFlags(android.app.Flags.FLAG_MODES_API) + @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) + public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception { + setUpRealZenTest(); + mService.setCallerIsNormalPackage(); + assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); + + // Create an implicit zen rule by calling setNotificationPolicy from an app. + mBinderService.setNotificationPolicy(PKG, new NotificationManager.Policy(0, 0, 0), false); + assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); + Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( + mBinderService.getAutomaticZenRules().entrySet()); + assertThat(rule.getValue().getOwner()).isNull(); + assertThat(rule.getValue().getConfigurationActivity()).isNull(); + + // Now try to update said rule (e.g. disable it). Should fail. + // We also validate the exception message because NPE could be thrown by all sorts of test + // issues (e.g. misconfigured mocks). + rule.getValue().setEnabled(false); + NullPointerException e = assertThrows(NullPointerException.class, + () -> mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false)); + assertThat(e.getMessage()).isEqualTo( + "Rule must have a ConditionProviderService and/or configuration activity"); + } + + @Test + @EnableFlags(android.app.Flags.FLAG_MODES_API) + @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) + public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception { + setUpRealZenTest(); + mService.setCallerIsNormalPackage(); + assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); + + // Create an implicit zen rule by calling setNotificationPolicy from an app. + mBinderService.setNotificationPolicy(PKG, new NotificationManager.Policy(0, 0, 0), false); + assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); + Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( + mBinderService.getAutomaticZenRules().entrySet()); + assertThat(rule.getValue().getOwner()).isNull(); + assertThat(rule.getValue().getConfigurationActivity()).isNull(); + + // Now update said rule from Settings (e.g. disable it). Should work! + mService.isSystemUid = true; + rule.getValue().setEnabled(false); + mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false); + + Map.Entry<String, AutomaticZenRule> updatedRule = getOnlyElement( + mBinderService.getAutomaticZenRules().entrySet()); + assertThat(updatedRule.getValue().isEnabled()).isFalse(); + } + + /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */ + private void setUpRealZenTest() throws Exception { + when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) + .thenReturn(true); + + int iconResId = 79; + String iconResName = "icon_79"; + String pkg = mContext.getPackageName(); + ApplicationInfo appInfoSpy = spy(new ApplicationInfo()); + appInfoSpy.icon = iconResId; + when(appInfoSpy.loadLabel(any())).thenReturn("Test App"); + when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy); + + when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName); + when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId); + when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources); + } + + @Test public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception { mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR); Notification n = new Notification.Builder(mContext, "test") @@ -13885,7 +14060,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - @Ignore("b/316989461") public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne() throws RemoteException { mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags @@ -13897,7 +14071,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addNotification(nr1); // Create old notification. - final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0); + final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, + System.currentTimeMillis() - 60000); mService.addNotification(nr2); // Cancel specific notifications via listener. @@ -13915,16 +14090,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - @Ignore("b/316989461") public void cancelNotificationsFromListener_rapidClear_old_cancelOne() throws RemoteException { mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); // Create old notifications. - final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 0); + final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, + System.currentTimeMillis() - 60000); mService.addNotification(nr1); - final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0); + final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, + System.currentTimeMillis() - 60000); mService.addNotification(nr2); // Cancel specific notifications via listener. @@ -13943,7 +14119,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - @Ignore("b/316989461") public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne_flagDisabled() throws RemoteException { mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags @@ -13955,7 +14130,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addNotification(nr1); // Create old notification. - final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0); + final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, + System.currentTimeMillis() - 60000); mService.addNotification(nr2); // Cancel specific notifications via listener. @@ -13974,7 +14150,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - @Ignore("b/316989461") public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll() throws RemoteException { mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags @@ -13986,7 +14161,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addNotification(nr1); // Create old notification. - final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0); + final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, + System.currentTimeMillis() - 60000); mService.addNotification(nr2); // Cancel all notifications via listener. @@ -14003,16 +14179,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - @Ignore("b/316989461") public void cancelNotificationsFromListener_rapidClear_old_cancelAll() throws RemoteException { mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); // Create old notifications. - final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 0); + final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, + System.currentTimeMillis() - 60000); mService.addNotification(nr1); - final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0); + final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, + System.currentTimeMillis() - 60000); mService.addNotification(nr2); // Cancel all notifications via listener. @@ -14030,7 +14207,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - @Ignore("b/316989461") public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll_flagDisabled() throws RemoteException { mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags @@ -14042,7 +14218,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addNotification(nr1); // Create old notification. - final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 0); + final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, + System.currentTimeMillis() - 60000); mService.addNotification(nr2); // Cancel all notifications via listener. @@ -14059,6 +14236,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { any(), any()); } + @Test + @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) + public void testSetPrivateNotificationsAllowed() throws Exception { + when(mContext.checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) + .thenReturn(PERMISSION_GRANTED); + mBinderService.setPrivateNotificationsAllowed(false); + Intent expected = new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) + .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false); + ArgumentCaptor<Intent> actual = ArgumentCaptor.forClass(Intent.class); + verify(mContext).sendBroadcast(actual.capture(), eq(STATUS_BAR_SERVICE)); + + assertEquals(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED, actual.getValue().getAction()); + assertFalse(actual.getValue().getBooleanExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true)); + assertFalse(mBinderService.getPrivateNotificationsAllowed()); + } + private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName) throws RemoteException { StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, testName, mUid, 0, diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java index 1fcee0658afc..5b35e345e46b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java @@ -118,10 +118,13 @@ public class ZenModeEventLoggerFake extends ZenModeEventLogger { public DNDPolicyProto getPolicyProto(int i) throws IllegalArgumentException { checkInRange(i); byte[] policyBytes = mChanges.get(i).getDNDPolicyProto(); + if (policyBytes == null) { + return null; + } try { return DNDPolicyProto.parseFrom(policyBytes); } catch (InvalidProtocolBufferException e) { - return null; // couldn't turn it into proto + throw new RuntimeException("Couldn't parse DNDPolicyProto!", e); } } 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 44f0894f76d7..25c0cd9fae25 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -2429,7 +2429,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertEquals(0, mZenModeEventLogger.getNumRulesActive(1)); assertFalse(mZenModeEventLogger.getIsUserAction(1)); assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1)); - checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + if (Flags.modesApi()) { + assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull(); + } else { + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + } } @Test @@ -2511,7 +2515,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertEquals(0, mZenModeEventLogger.getNumRulesActive(1)); assertTrue(mZenModeEventLogger.getIsUserAction(1)); assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(1)); - checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + if (Flags.modesApi()) { + assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull(); + } else { + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + } // When the system rule is enabled, this counts as an automatic action that comes from the // system and turns on DND @@ -3016,6 +3024,48 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + @EnableFlags(Flags.FLAG_MODES_API) + public void testZenModeEventLog_ruleWithInterruptionFilterAll_notLoggedAsDndChange() { + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + // An app adds an automatic zen rule + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(CUSTOM_PKG_NAME, "cls"), + Uri.parse("condition"), + null, + NotificationManager.INTERRUPTION_FILTER_ALL, true); + String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, + UPDATE_ORIGIN_APP, "test", CUSTOM_PKG_UID); + + // Event 1: App activates the rule automatically. + mZenModeHelper.setAutomaticZenRuleState(id, + new Condition(zenRule.getConditionId(), "", STATE_TRUE, SOURCE_SCHEDULE), + UPDATE_ORIGIN_APP, CUSTOM_PKG_UID); + + // Event 2: App deactivates the rule automatically. + mZenModeHelper.setAutomaticZenRuleState(id, + new Condition(zenRule.getConditionId(), "", STATE_FALSE, SOURCE_SCHEDULE), + UPDATE_ORIGIN_APP, CUSTOM_PKG_UID); + + // In total, this represents 2 events. + assertEquals(2, mZenModeEventLogger.numLoggedChanges()); + + // However, they are not DND_TURNED_ON/_OFF (no notification filtering is taking place). + // Also, no consolidated ZenPolicy is logged (because of the same reason). + assertThat(mZenModeEventLogger.getEventId(0)).isEqualTo( + ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId()); + assertThat(mZenModeEventLogger.getNumRulesActive(0)).isEqualTo(1); + assertThat(mZenModeEventLogger.getPolicyProto(0)).isNull(); + + assertThat(mZenModeEventLogger.getEventId(1)).isEqualTo( + ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId()); + assertThat(mZenModeEventLogger.getNumRulesActive(1)).isEqualTo(0); + assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull(); + } + + @Test public void testUpdateConsolidatedPolicy_defaultRulesOnly() { setupZenConfig(); @@ -3203,6 +3253,52 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + @EnableFlags(Flags.FLAG_MODES_API) + public void testUpdateConsolidatedPolicy_ignoresActiveRulesWithInterruptionFilterAll() { + setupZenConfig(); + + // Rules with INTERRUPTION_FILTER_ALL are skipped when calculating consolidated policy. + // Note: rules with filter != PRIORITY should not have a custom policy. However, as of V + // this is only validated on rule addition, but not on rule update. :/ + + // Rule 1: PRIORITY, custom policy but not very strict (in fact, less strict than default). + AutomaticZenRule zenRuleWithPriority = new AutomaticZenRule("Priority", + null, + new ComponentName(CUSTOM_PKG_NAME, "cls"), + Uri.parse("priority"), + new ZenPolicy.Builder().allowMedia(true).build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String rule1Id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), + zenRuleWithPriority, UPDATE_ORIGIN_APP, "test", CUSTOM_PKG_UID); + mZenModeHelper.setAutomaticZenRuleState(rule1Id, + new Condition(zenRuleWithPriority.getConditionId(), "", STATE_TRUE), + UPDATE_ORIGIN_APP, CUSTOM_PKG_UID); + + // Rule 2: ALL, but somehow with a super strict ZenPolicy. + AutomaticZenRule zenRuleWithAll = new AutomaticZenRule("All", + null, + new ComponentName(CUSTOM_PKG_NAME, "cls"), + Uri.parse("priority"), + new ZenPolicy.Builder().disallowAllSounds().build(), + NotificationManager.INTERRUPTION_FILTER_ALL, true); + String rule2Id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), + zenRuleWithAll, UPDATE_ORIGIN_APP, "test", CUSTOM_PKG_UID); + mZenModeHelper.setAutomaticZenRuleState(rule2Id, + new Condition(zenRuleWithPriority.getConditionId(), "", STATE_TRUE), + UPDATE_ORIGIN_APP, CUSTOM_PKG_UID); + + // Consolidated Policy should be default + rule1. + assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isFalse(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // priority rule + assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isFalse(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isTrue(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isTrue(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowConversations()).isTrue(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers()).isTrue(); // default + } + + @Test public void zenRuleToAutomaticZenRule_allFields() { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); when(mPackageManager.getPackagesForUid(anyInt())).thenReturn( diff --git a/services/tests/vibrator/Android.bp b/services/tests/vibrator/Android.bp index 6f37967bf7f0..66dcaff687c8 100644 --- a/services/tests/vibrator/Android.bp +++ b/services/tests/vibrator/Android.bp @@ -31,13 +31,13 @@ android_test { "frameworks-base-testutils", "frameworks-services-vibrator-testutils", "junit", - "mockito-target-minus-junit4", + "mockito-target-inline-minus-junit4", "platform-test-annotations", "service-permission.stubs.system_server", "services.core", "flag-junit", ], - + jni_libs: ["libdexmakerjvmtiagent"], platform_apis: true, certificate: "platform", dxflags: ["--multi-dex"], diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java index bbca704e58c8..f9fe6a9ac313 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java @@ -43,12 +43,17 @@ import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; import android.os.test.TestLooper; +import android.os.vibrator.Flags; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.StepSegment; import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibrationEffectSegment; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; +import android.util.SparseArray; import androidx.test.InstrumentationRegistry; @@ -68,6 +73,9 @@ public class VibrationScalerTest { @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); @Mock private PowerManagerInternal mPowerManagerInternalMock; @Mock private PackageManagerInternal mPackageManagerInternalMock; @@ -256,6 +264,29 @@ public class VibrationScalerTest { assertEquals(0.5, scaled.getScale(), 1e-5); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED) + public void scale_withAdaptiveHaptics_scalesVibrationsCorrectly() { + setDefaultIntensity(USAGE_RINGTONE, VIBRATION_INTENSITY_HIGH); + setDefaultIntensity(USAGE_NOTIFICATION, VIBRATION_INTENSITY_HIGH); + + SparseArray<Float> adaptiveHapticsScales = new SparseArray<>(); + adaptiveHapticsScales.put(USAGE_RINGTONE, 0.5f); + adaptiveHapticsScales.put(USAGE_NOTIFICATION, 0.5f); + mVibrationScaler.updateAdaptiveHapticsScales(adaptiveHapticsScales); + + StepSegment scaled = getFirstSegment(mVibrationScaler.scale( + VibrationEffect.createOneShot(128, 128), USAGE_RINGTONE)); + // Ringtone scales down. + assertTrue(scaled.getAmplitude() < 0.5); + + scaled = getFirstSegment(mVibrationScaler.scale( + VibrationEffect.createWaveform(new long[]{128}, new int[]{128}, -1), + USAGE_NOTIFICATION)); + // Notification scales down. + assertTrue(scaled.getAmplitude() < 0.5); + } + private void setDefaultIntensity(@VibrationAttributes.Usage int usage, @Vibrator.VibrationIntensity int intensity) { when(mVibrationConfigMock.getDefaultVibrationIntensity(eq(usage))).thenReturn(intensity); diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java index 49efd1bdd92a..1e0b1df4fc67 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java @@ -16,21 +16,49 @@ package com.android.server.vibrator; +import static android.os.VibrationAttributes.USAGE_ALARM; +import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST; +import static android.os.VibrationAttributes.USAGE_NOTIFICATION; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.frameworks.vibrator.ScaleParam; +import android.frameworks.vibrator.VibrationParam; import android.os.RemoteException; +import android.util.SparseArray; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.ArrayList; +import java.util.List; public class VibratorControlServiceTest { + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Mock + private VibrationScaler mMockVibrationScaler; + @Captor + private ArgumentCaptor<SparseArray<Float>> mVibrationScalesCaptor; + private VibratorControlService mVibratorControlService; private final Object mLock = new Object(); @Before public void setUp() throws Exception { - mVibratorControlService = new VibratorControlService(new VibratorControllerHolder(), mLock); + mVibratorControlService = new VibratorControlService(new VibratorControllerHolder(), + mMockVibrationScaler, mLock); } @Test @@ -47,6 +75,8 @@ public class VibratorControlServiceTest { FakeVibratorController fakeController = new FakeVibratorController(); mVibratorControlService.registerVibratorController(fakeController); mVibratorControlService.unregisterVibratorController(fakeController); + + verify(mMockVibrationScaler).updateAdaptiveHapticsScales(null); assertThat(fakeController.isLinkedToDeath).isFalse(); } @@ -56,8 +86,91 @@ public class VibratorControlServiceTest { FakeVibratorController fakeController1 = new FakeVibratorController(); FakeVibratorController fakeController2 = new FakeVibratorController(); mVibratorControlService.registerVibratorController(fakeController1); - mVibratorControlService.unregisterVibratorController(fakeController2); + + verifyZeroInteractions(mMockVibrationScaler); assertThat(fakeController1.isLinkedToDeath).isTrue(); } + + @Test + public void testSetVibrationParams_cachesAdaptiveHapticsScalesCorrectly() + throws RemoteException { + FakeVibratorController fakeController = new FakeVibratorController(); + mVibratorControlService.registerVibratorController(fakeController); + SparseArray<Float> vibrationScales = new SparseArray<>(); + vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f); + vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f); + + mVibratorControlService.setVibrationParams(generateVibrationParams(vibrationScales), + fakeController); + + verify(mMockVibrationScaler).updateAdaptiveHapticsScales(mVibrationScalesCaptor.capture()); + SparseArray<Float> cachedVibrationScales = mVibrationScalesCaptor.getValue(); + assertThat(cachedVibrationScales.size()).isEqualTo(3); + assertThat(cachedVibrationScales.keyAt(0)).isEqualTo(USAGE_ALARM); + assertThat(cachedVibrationScales.valueAt(0)).isEqualTo(0.7f); + assertThat(cachedVibrationScales.keyAt(1)).isEqualTo(USAGE_NOTIFICATION); + assertThat(cachedVibrationScales.valueAt(1)).isEqualTo(0.4f); + // Setting ScaleParam.TYPE_NOTIFICATION will update vibration scaling for both + // notification and communication request usages. + assertThat(cachedVibrationScales.keyAt(2)).isEqualTo(USAGE_COMMUNICATION_REQUEST); + assertThat(cachedVibrationScales.valueAt(2)).isEqualTo(0.4f); + } + + @Test + public void testSetVibrationParams_withUnregisteredController_ignoresRequest() + throws RemoteException { + FakeVibratorController fakeController = new FakeVibratorController(); + + SparseArray<Float> vibrationScales = new SparseArray<>(); + vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f); + vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f); + + mVibratorControlService.setVibrationParams(generateVibrationParams(vibrationScales), + fakeController); + + verifyZeroInteractions(mMockVibrationScaler); + } + + @Test + public void testClearVibrationParams_clearsCachedAdaptiveHapticsScales() + throws RemoteException { + FakeVibratorController fakeController = new FakeVibratorController(); + mVibratorControlService.registerVibratorController(fakeController); + mVibratorControlService.clearVibrationParams(ScaleParam.TYPE_ALARM, fakeController); + + verify(mMockVibrationScaler).updateAdaptiveHapticsScales(null); + } + + @Test + public void testClearVibrationParams_withUnregisteredController_ignoresRequest() + throws RemoteException { + FakeVibratorController fakeController = new FakeVibratorController(); + + mVibratorControlService.clearVibrationParams(ScaleParam.TYPE_ALARM, fakeController); + + verifyZeroInteractions(mMockVibrationScaler); + } + + private VibrationParam[] generateVibrationParams(SparseArray<Float> vibrationScales) { + List<VibrationParam> vibrationParamList = new ArrayList<>(); + for (int i = 0; i < vibrationScales.size(); i++) { + int type = vibrationScales.keyAt(i); + float scale = vibrationScales.valueAt(i); + + vibrationParamList.add(generateVibrationParam(type, scale)); + } + + return vibrationParamList.toArray(new VibrationParam[0]); + } + + private VibrationParam generateVibrationParam(int type, float scale) { + ScaleParam scaleParam = new ScaleParam(); + scaleParam.typesMask = type; + scaleParam.scale = scale; + VibrationParam vibrationParam = new VibrationParam(); + vibrationParam.setScale(scaleParam); + + return vibrationParam; + } } diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java index 53635835f164..29467f259ac3 100644 --- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java @@ -16,6 +16,10 @@ package com.android.server.policy; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManagerGlobal.ADD_OKAY; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -26,11 +30,16 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.filters.SmallTest; @@ -39,6 +48,7 @@ import com.android.server.wm.ActivityTaskManagerInternal; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; /** @@ -50,6 +60,9 @@ import org.junit.Test; @SmallTest public class PhoneWindowManagerTests { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + PhoneWindowManager mPhoneWindowManager; @Before @@ -85,6 +98,36 @@ public class PhoneWindowManagerTests { verify(mPhoneWindowManager).createHomeDockIntent(); } + @Test + public void testCheckAddPermission_withoutAccessibilityOverlay_noAccessibilityAppOpLogged() { + mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags + .FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); + int[] outAppOp = new int[1]; + assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_WALLPAPER, + /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp)); + assertThat(outAppOp[0]).isEqualTo(AppOpsManager.OP_NONE); + } + + @Test + public void testCheckAddPermission_withAccessibilityOverlay() { + mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags + .FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); + int[] outAppOp = new int[1]; + assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_ACCESSIBILITY_OVERLAY, + /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp)); + assertThat(outAppOp[0]).isEqualTo(AppOpsManager.OP_CREATE_ACCESSIBILITY_OVERLAY); + } + + @Test + public void testCheckAddPermission_withAccessibilityOverlay_flagDisabled() { + mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags + .FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED); + int[] outAppOp = new int[1]; + assertEquals(ADD_OKAY, mPhoneWindowManager.checkAddPermission(TYPE_ACCESSIBILITY_OVERLAY, + /* isRoundedCornerOverlay= */ false, "test.pkg", outAppOp)); + assertThat(outAppOp[0]).isEqualTo(AppOpsManager.OP_NONE); + } + private void mockStartDockOrHome() throws Exception { doNothing().when(ActivityManager.getService()).stopAppSwitches(); ActivityTaskManagerInternal mMockActivityTaskManagerInternal = 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 e88a00b93b03..f049b3398f42 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2640,6 +2640,9 @@ public class ActivityRecordTests extends WindowTestsBase { // Can specify orientation if the current orientation candidate is orientation behind. assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation(SCREEN_ORIENTATION_BEHIND)); + activity.makeFinishingLocked(); + assertEquals("Finishing activity must not report orientation", + SCREEN_ORIENTATION_UNSET, activity.getOrientation(SCREEN_ORIENTATION_BEHIND)); final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) .setActivityTheme(android.R.style.Theme_Translucent) diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 8a9c05d07b26..c82f7513e347 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -88,6 +88,7 @@ import static org.mockito.ArgumentMatchers.notNull; import android.app.ActivityOptions; import android.app.AppOpsManager; import android.app.BackgroundStartPrivileges; +import android.app.ComponentOptions.BackgroundActivityStartMode; import android.app.IApplicationThread; import android.app.PictureInPictureParams; import android.content.ComponentName; @@ -914,24 +915,78 @@ public class ActivityStarterTests extends WindowTestsBase { .mockStatic(FrameworkStatsLog.class) .strictness(Strictness.LENIENT) .startMocking(); - doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( - eq(START_ACTIVITIES_FROM_BACKGROUND), - anyInt(), anyInt())); - runAndVerifyBackgroundActivityStartsSubtest( - "allowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false); - verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - "", // activity name - BackgroundActivityStartController.BAL_ALLOW_PERMISSION, - UNIMPORTANT_UID, - UNIMPORTANT_UID2)); - mockingSession.finishMocking(); + try { + doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( + eq(START_ACTIVITIES_FROM_BACKGROUND), + anyInt(), anyInt())); + runAndVerifyBackgroundActivityStartsSubtest( + "allowed_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, + false, true, false, false, false, false, false, false); + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + "", // activity name + BackgroundActivityStartController.BAL_ALLOW_PERMISSION, + UNIMPORTANT_UID, + UNIMPORTANT_UID2, + BackgroundActivityStartController.BAL_ALLOW_PERMISSION, + true, // opt in + false, // but no explicit opt in + BackgroundActivityStartController.BAL_BLOCK, + true, // opt in + false // but no explicit opt in + )); + } finally { + mockingSession.finishMocking(); + } + } + + /** + * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT, when the PendingIntent sender + * is the only reason BAL is allowed. + */ + @Test + public void testBackgroundActivityStartsAllowed_loggingOnlyPendingIntentAllowed() { + doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); + MockitoSession mockingSession = mockitoSession() + .mockStatic(ActivityTaskManagerService.class) + .mockStatic(FrameworkStatsLog.class) + .mockStatic(PendingIntentRecord.class) + .strictness(Strictness.LENIENT) + .startMocking(); + try { + doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( + eq(START_ACTIVITIES_FROM_BACKGROUND), + anyInt(), anyInt())); + doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( + () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( + anyObject(), anyInt(), anyObject())); + runAndVerifyBackgroundActivityStartsSubtest( + "allowed_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, + false, true, false, false, false, false, false, false, + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED); + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME, + BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT, + UNIMPORTANT_UID, + Process.SYSTEM_UID, + BackgroundActivityStartController.BAL_ALLOW_PERMISSION, + false, // opt in + true, // explicit opt out + BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW, + true, // opt in + false // but no explicit opt in + )); + } finally { + mockingSession.finishMocking(); + } } /** - * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT. + * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT, when the PendingIntent sender + * is not the primary reason to allow BAL (but the creator). */ @Test public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() { @@ -942,23 +997,34 @@ public class ActivityStarterTests extends WindowTestsBase { .mockStatic(PendingIntentRecord.class) .strictness(Strictness.LENIENT) .startMocking(); - doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( - eq(START_ACTIVITIES_FROM_BACKGROUND), - anyInt(), anyInt())); - doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( - () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( - anyObject(), anyInt(), anyObject())); - runAndVerifyBackgroundActivityStartsSubtest( - "allowed_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, - Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false, false); - verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, - DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME, - BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT, - UNIMPORTANT_UID, - Process.SYSTEM_UID)); - mockingSession.finishMocking(); + try { + doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( + eq(START_ACTIVITIES_FROM_BACKGROUND), + anyInt(), anyInt())); + doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when( + () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller( + anyObject(), anyInt(), anyObject())); + runAndVerifyBackgroundActivityStartsSubtest( + "allowed_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, + false, true, false, false, false, false, false, false, + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + "", + BackgroundActivityStartController.BAL_ALLOW_PERMISSION, + UNIMPORTANT_UID, + Process.SYSTEM_UID, + BackgroundActivityStartController.BAL_ALLOW_PERMISSION, + true, // opt in + true, // explicit opt in + BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW, + true, // opt in + false // but no explicit opt in + )); + } finally { + mockingSession.finishMocking(); + } } private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, @@ -971,6 +1037,27 @@ public class ActivityStarterTests extends WindowTestsBase { boolean isCallingUidAffiliatedProfileOwner, boolean isPinnedSingleInstance, boolean hasSystemExemptAppOp) { + runAndVerifyBackgroundActivityStartsSubtest(name, shouldHaveAborted, callingUid, + callingUidHasVisibleWindow, callingUidProcState, realCallingUid, + realCallingUidHasVisibleWindow, realCallingUidProcState, hasForegroundActivities, + callerIsRecents, callerIsTempAllowed, + callerIsInstrumentingWithBackgroundActivityStartPrivileges, + isCallingUidDeviceOwner, isCallingUidAffiliatedProfileOwner, isPinnedSingleInstance, + hasSystemExemptAppOp, + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); + } + + private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, + int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, + int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, + boolean hasForegroundActivities, boolean callerIsRecents, + boolean callerIsTempAllowed, + boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, + boolean isCallingUidDeviceOwner, + boolean isCallingUidAffiliatedProfileOwner, + boolean isPinnedSingleInstance, + boolean hasSystemExemptAppOp, + @BackgroundActivityStartMode int pendingIntentCreatorBackgroundActivityStartMode) { // window visibility doReturn(callingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(callingUid); doReturn(realCallingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(realCallingUid); @@ -1022,7 +1109,10 @@ public class ActivityStarterTests extends WindowTestsBase { launchMode = LAUNCH_SINGLE_INSTANCE; } - final ActivityOptions options = spy(ActivityOptions.makeBasic()); + ActivityOptions rawOptions = ActivityOptions.makeBasic() + .setPendingIntentCreatorBackgroundActivityStartMode( + pendingIntentCreatorBackgroundActivityStartMode); + final ActivityOptions options = spy(rawOptions); ActivityRecord[] outActivity = new ActivityRecord[1]; ActivityStarter starter = prepareStarter( FLAG_ACTIVITY_NEW_TASK, true, launchMode) diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index a11079be85ab..0c1fbf3cb3d7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -1221,7 +1221,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { public void testTransitionGoodToGoForTaskFragments_detachedApp() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer); - mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); + registerTaskFragmentOrganizer(iOrganizer); final Task task = createTask(mDisplayContent); final TaskFragment changeTaskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); @@ -1265,7 +1265,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter); definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter); - mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); + registerTaskFragmentOrganizer(iOrganizer); mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index ba8c94dd9218..99505414b934 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -439,7 +439,7 @@ public class AppTransitionTests extends WindowTestsBase { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final ITaskFragmentOrganizer iOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); - mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); + registerTaskFragmentOrganizer(iOrganizer); final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(task) .setOrganizer(organizer) 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 6497ee9cb1f2..782d89cdcd29 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -115,6 +115,9 @@ import android.os.Binder; import android.os.RemoteException; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.ArraySet; import android.util.DisplayMetrics; import android.view.Display; @@ -146,6 +149,7 @@ import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.utils.WmDisplayCutout; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -172,6 +176,10 @@ import java.util.concurrent.TimeoutException; @RunWith(WindowTestRunner.class) public class DisplayContentTests extends WindowTestsBase { + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + @SetupWindows(addAllCommonWindows = true) @Test public void testForAllWindows() { @@ -508,6 +516,7 @@ public class DisplayContentTests extends WindowTestsBase { * Tests tapping on a root task in different display results in window gaining focus. */ @Test + @RequiresFlagsDisabled(com.android.input.flags.Flags.FLAG_REMOVE_POINTER_EVENT_TRACKING_IN_WM) public void testInputEventBringsCorrectDisplayInFocus() { DisplayContent dc0 = mWm.getDefaultDisplayContentLocked(); // Create a second display diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index 985be429d42b..4e4bbfe6371d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -697,6 +697,31 @@ public class LetterboxUiControllerTest extends WindowTestsBase { @Test @EnableCompatChanges({OVERRIDE_ANY_ORIENTATION_TO_USER}) + public void testOverrideOrientationIfNeeded_fullscreenOverrides_optOutSystem_returnsUser() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, /* value */ false); + prepareActivityThatShouldApplyUserFullscreenOverride(); + + // fullscreen override still applied + assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded( + /* candidate */ SCREEN_ORIENTATION_PORTRAIT)); + } + + @Test + @EnableCompatChanges({OVERRIDE_ANY_ORIENTATION_TO_USER}) + public void testOverrideOrientationIfNeeded_fullscreenOverrides_optOutUser_returnsUser() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE, + /* value */ false); + prepareActivityThatShouldApplyUserFullscreenOverride(); + + // fullscreen override still applied + assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded( + /* candidate */ SCREEN_ORIENTATION_PORTRAIT)); + } + + @Test + @EnableCompatChanges({OVERRIDE_ANY_ORIENTATION_TO_USER}) public void testOverrideOrientationIfNeeded_fullscreenOverrideEnabled_returnsUnchanged() throws Exception { mDisplayContent.setIgnoreOrientationRequest(false); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java index b5883b1aefe5..527ea0d35f02 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java @@ -140,7 +140,7 @@ public class RootTaskTests extends WindowTestsBase { final WindowContainer parent = activity1.getTask().getParent(); assertEquals(SCREEN_ORIENTATION_PORTRAIT, parent.getOrientation()); - mDisplayContent.mClosingApps.add(activity2); + activity2.setVisibleRequested(false); assertEquals(SCREEN_ORIENTATION_LANDSCAPE, parent.getOrientation()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java index e65a9feed1aa..b45fa31f057e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import android.os.Handler; @@ -35,7 +37,7 @@ class SystemServiceTestsBase { new DexmakerShareClassLoaderRule(); @Rule(order = 1) - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); @Rule(order = 2) public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule( diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index 06f29c262b42..a88285ac4c8f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -34,6 +34,7 @@ import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_TOP_OF_TAS import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_DIM_ON_TASK; import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE; @@ -74,6 +75,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.annotation.NonNull; +import android.app.IApplicationThread; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -104,6 +106,8 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import com.android.window.flags.Flags; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -123,7 +127,6 @@ import java.util.List; @Presubmit @RunWith(WindowTestRunner.class) public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { - private static final int TASK_ID = 10; private TaskFragmentOrganizerController mController; private WindowOrganizerController mWindowOrganizerController; @@ -143,6 +146,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private TaskFragmentInfo mTaskFragmentInfo; @Mock private Task mTask; + @Mock + private IApplicationThread mAppThread; @Captor private ArgumentCaptor<TaskFragmentTransaction> mTransactionCaptor; @@ -178,12 +183,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl(); doReturn(mFragmentToken).when(mTaskFragment).getFragmentToken(); doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration(); + doReturn(mAppThread).when(mController).getAppThread(anyInt(), anyInt()); + doAnswer(invocation -> { + final ITaskFragmentOrganizer organizer = + (ITaskFragmentOrganizer) invocation.getArguments()[0]; + final TaskFragmentTransaction taskFragmentTransaction = + (TaskFragmentTransaction) invocation.getArguments()[1]; + organizer.onTransactionReady(taskFragmentTransaction); + return null; + }).when(mAppThread).scheduleTaskFragmentTransaction(any(), any()); // To prevent it from calling the real server. doNothing().when(mOrganizer).applyTransaction(any(), anyInt(), anyBoolean()); doNothing().when(mOrganizer).onTransactionHandled(any(), any(), anyInt(), anyBoolean()); - mController.registerOrganizer(mIOrganizer); + registerTaskFragmentOrganizer(mIOrganizer); } @Test @@ -204,12 +218,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { } @Test - public void testOnTaskFragmentAppeared() { + public void testOnTaskFragmentAppeared_throughTaskFragmentOrganizer() throws RemoteException { + mSetFlagsRule.disableFlags(Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG); + // No-op when the TaskFragment is not attached. mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTransactionReady(any()); + verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); // Send callback when the TaskFragment is attached. setupMockParent(mTaskFragment, mTask); @@ -219,12 +236,40 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { assertTaskFragmentParentInfoChangedTransaction(mTask); assertTaskFragmentAppearedTransaction(false /* hasSurfaceControl */); + verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); + } + + @Test + public void testOnTaskFragmentAppeared_throughApplicationThread() throws RemoteException { + mSetFlagsRule.enableFlags(Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG); + // Re-register the organizer in case the flag was disabled during setup. + mController.unregisterOrganizer(mIOrganizer); + registerTaskFragmentOrganizer(mIOrganizer); + + // No-op when the TaskFragment is not attached. + mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); + + verify(mOrganizer, never()).onTransactionReady(any()); + verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); + + // Send callback when the TaskFragment is attached. + setupMockParent(mTaskFragment, mTask); + + mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); + + verify(mAppThread).scheduleTaskFragmentTransaction(eq(mIOrganizer), any()); + assertTaskFragmentParentInfoChangedTransaction(mTask); + assertTaskFragmentAppearedTransaction(false /* hasSurfaceControl */); } @Test public void testOnTaskFragmentAppeared_systemOrganizer() { + mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); + mController.unregisterOrganizer(mIOrganizer); - mController.registerOrganizerInternal(mIOrganizer, true /* isSystemOrganizer */); + registerTaskFragmentOrganizer(mIOrganizer, true /* isSystemOrganizer */); // No-op when the TaskFragment is not attached. mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); @@ -565,8 +610,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { @Test public void testApplyTransaction_allowRemoteTransitionForSystemOrganizer() { + mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); + mController.unregisterOrganizer(mIOrganizer); - mController.registerOrganizerInternal(mIOrganizer, true /* isSystemOrganizer */); + registerTaskFragmentOrganizer(mIOrganizer, true /* isSystemOrganizer */); mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100)); mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, @@ -824,12 +871,19 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { .setAnimationParams(animationParams) .build(); mTransaction.addTaskFragmentOperation(mFragmentToken, operation); + final TaskFragmentOperation dimOperation = new TaskFragmentOperation.Builder( + OP_TYPE_SET_DIM_ON_TASK) + .setDimOnTask(true) + .build(); + mTransaction.addTaskFragmentOperation(mFragmentToken, dimOperation); mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE, false /* shouldApplyIndependently */); assertApplyTransactionAllowed(mTransaction); assertEquals(animationParams, mTaskFragment.getAnimationParams()); assertEquals(Color.GREEN, mTaskFragment.getAnimationParams().getAnimationBackgroundColor()); + + assertTrue(mTaskFragment.isDimmingOnParentTask()); } @Test @@ -1056,7 +1110,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // Nothing should happen as the organizer is not registered. assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken)); - mController.registerOrganizer(mIOrganizer); + registerTaskFragmentOrganizer(mIOrganizer); assertApplyTransactionAllowed(mTransaction); // Successfully created when the organizer is registered. @@ -1692,8 +1746,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { @Test public void testApplyTransaction_reorderToBottomOfTask() { + mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); + mController.unregisterOrganizer(mIOrganizer); - mController.registerOrganizerInternal(mIOrganizer, true /* isSystemOrganizer */); + registerTaskFragmentOrganizer(mIOrganizer, true /* isSystemOrganizer */); final Task task = createTask(mDisplayContent); // Create a non-embedded Activity at the bottom. final ActivityRecord bottomActivity = new ActivityBuilder(mAtm) @@ -1727,8 +1783,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { @Test public void testApplyTransaction_reorderToTopOfTask() { + mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); + mController.unregisterOrganizer(mIOrganizer); - mController.registerOrganizerInternal(mIOrganizer, true /* isSystemOrganizer */); + registerTaskFragmentOrganizer(mIOrganizer, true /* isSystemOrganizer */); final Task task = createTask(mDisplayContent); // Create a non-embedded Activity at the bottom. final ActivityRecord bottomActivity = new ActivityBuilder(mAtm) @@ -1762,9 +1820,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { @Test public void testApplyTransaction_createTaskFragmentDecorSurface() { + mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); + // TODO(b/293654166) remove system organizer requirement once security review is cleared. mController.unregisterOrganizer(mIOrganizer); - mController.registerOrganizerInternal(mIOrganizer, true /* isSystemOrganizer */); + registerTaskFragmentOrganizer(mIOrganizer, true /* isSystemOrganizer */); final Task task = createTask(mDisplayContent); final TaskFragment tf = createTaskFragment(task); @@ -1779,9 +1839,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { @Test public void testApplyTransaction_removeTaskFragmentDecorSurface() { + mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); + // TODO(b/293654166) remove system organizer requirement once security review is cleared. mController.unregisterOrganizer(mIOrganizer); - mController.registerOrganizerInternal(mIOrganizer, true /* isSystemOrganizer */); + registerTaskFragmentOrganizer(mIOrganizer, true /* isSystemOrganizer */); final Task task = createTask(mDisplayContent); final TaskFragment tf = createTaskFragment(task); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 00e22fd7142a..e9fe4bb91329 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -90,8 +90,7 @@ public class TaskFragmentTest extends WindowTestsBase { mOrganizer = new TaskFragmentOrganizer(Runnable::run); mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizer.getOrganizerToken() .asBinder()); - mAtm.mWindowOrganizerController.mTaskFragmentOrganizerController - .registerOrganizer(mIOrganizer); + registerTaskFragmentOrganizer(mIOrganizer); mTaskFragment = new TaskFragmentBuilder(mAtm) .setCreateParentTask() .setOrganizer(mOrganizer) @@ -685,6 +684,9 @@ public class TaskFragmentTest extends WindowTestsBase { // Return Task bounds if dimming on parent Task. final Rect dimBounds = new Rect(); mTaskFragment.setEmbeddedDimArea(EMBEDDED_DIM_AREA_PARENT_TASK); + final Dimmer dimmer = mTaskFragment.getDimmer(); + spyOn(dimmer); + doReturn(taskBounds).when(dimmer).getDimBounds(); mTaskFragment.getDimBounds(dimBounds); assertEquals(taskBounds, dimBounds); 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 fddd77176bd9..0514943a83c5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -1639,7 +1639,7 @@ public class TransitionTests extends WindowTestsBase { final ActivityRecord nonEmbeddedActivity = createActivityRecord(task); assertFalse(nonEmbeddedActivity.isEmbedded()); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - mAtm.mTaskFragmentOrganizerController.registerOrganizer( + registerTaskFragmentOrganizer( ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder())); final TaskFragment embeddedTf = new TaskFragmentBuilder(mAtm) .setParentTask(task) @@ -1689,7 +1689,7 @@ public class TransitionTests extends WindowTestsBase { task.getConfiguration().windowConfiguration.setBounds(taskBounds); final ActivityRecord nonEmbeddedActivity = createActivityRecord(task); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - mAtm.mTaskFragmentOrganizerController.registerOrganizer( + registerTaskFragmentOrganizer( ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder())); final TaskFragment embeddedTf = new TaskFragmentBuilder(mAtm) .setParentTask(task) @@ -1818,7 +1818,7 @@ public class TransitionTests extends WindowTestsBase { // Skip manipulate the SurfaceControl. doNothing().when(activity).setDropInputMode(anyInt()); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - mAtm.mTaskFragmentOrganizerController.registerOrganizer( + registerTaskFragmentOrganizer( ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder())); final TaskFragment embeddedTf = new TaskFragmentBuilder(mAtm) .setParentTask(task) @@ -1849,7 +1849,7 @@ public class TransitionTests extends WindowTestsBase { // Test background color for Activity and embedded TaskFragment. final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - mAtm.mTaskFragmentOrganizerController.registerOrganizer( + registerTaskFragmentOrganizer( ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder())); final Task task = createTask(mDisplayContent); final TaskFragment embeddedTf = createTaskFragmentWithEmbeddedActivity(task, organizer); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 28e0c6b65599..74aabe15ba34 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -40,11 +40,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; -import static com.android.server.wm.testing.Assert.assertThrows; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.SYNC_STATE_READY; import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; +import static com.android.server.wm.testing.Assert.assertThrows; import static com.google.common.truth.Truth.assertThat; @@ -92,6 +92,7 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.server.wm.TaskOrganizerController.PendingTaskEvent; +import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Test; @@ -585,6 +586,8 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testTaskFragmentHiddenFocusableTranslucentChanges() { + mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); + removeGlobalMinSizeRestriction(); final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build(); @@ -660,6 +663,8 @@ public class WindowOrganizerTests extends WindowTestsBase { private void testTaskFragmentChangesWithoutSystemOrganizerThrowException( BiConsumer<WindowContainerTransaction, WindowContainerToken> addOp) { + mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); + removeGlobalMinSizeRestriction(); final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build(); @@ -1735,11 +1740,9 @@ public class WindowOrganizerTests extends WindowTestsBase { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final ITaskFragmentOrganizer organizerInterface = ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); - mWm.mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController - .registerOrganizerInternal( - ITaskFragmentOrganizer.Stub.asInterface( - organizer.getOrganizerToken().asBinder()), - isSystemOrganizer); + registerTaskFragmentOrganizer( + ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()), + isSystemOrganizer); t.setTaskFragmentOrganizer(organizerInterface); return organizer; 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 75e252f9a415..f24baba9ca0c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -814,7 +814,7 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testEmbeddedActivityResizing_clearAllDrawn() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - mAtm.mTaskFragmentOrganizerController.registerOrganizer( + registerTaskFragmentOrganizer( ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder())); final Task task = createTask(mDisplayContent); final TaskFragment embeddedTf = createTaskFragmentWithEmbeddedActivity(task, organizer); 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 a5f6190f2d51..60e84b03ec89 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -107,6 +107,7 @@ import android.view.WindowManager; import android.view.WindowManager.DisplayImePolicy; import android.view.inputmethod.ImeTracker; import android.window.ClientWindowFrames; +import android.window.ITaskFragmentOrganizer; import android.window.ITransitionPlayer; import android.window.ScreenCapture; import android.window.StartingWindowInfo; @@ -891,6 +892,22 @@ class WindowTestsBase extends SystemServiceTestsBase { return taskFragment; } + /** @see TaskFragmentOrganizerController#registerOrganizer */ + void registerTaskFragmentOrganizer(@NonNull ITaskFragmentOrganizer organizer) { + registerTaskFragmentOrganizer(organizer, false /* isSystemOrganizer */); + } + + /** @see TaskFragmentOrganizerController#registerOrganizer */ + void registerTaskFragmentOrganizer(@NonNull ITaskFragmentOrganizer organizer, + boolean isSystemOrganizer) { + // Ensure there is an IApplicationThread to dispatch TaskFragmentTransaction. + if (mAtm.mProcessMap.getProcess(WindowManagerService.MY_PID) == null) { + mSystemServicesTestRule.addProcess("pkgName", "procName", + WindowManagerService.MY_PID, WindowManagerService.MY_UID); + } + mAtm.mTaskFragmentOrganizerController.registerOrganizer(organizer, isSystemOrganizer); + } + /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay() { return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL); diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java index bfc17713b6a8..336bfdd0fb14 100644 --- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java +++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java @@ -35,6 +35,7 @@ import android.util.Slog; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.Keep; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.RingBuffer; import com.android.server.usage.BroadcastResponseStatsTracker.NotificationEventType; @@ -178,6 +179,7 @@ public class BroadcastResponseStatsLogger { } } + @Keep public static final class BroadcastEvent implements Data { public int sourceUid; public int targetUserId; @@ -198,6 +200,7 @@ public class BroadcastResponseStatsLogger { } } + @Keep public static final class NotificationEvent implements Data { public int type; public String packageName; diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index df349f89fbf8..c958aba1d758 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -563,7 +563,10 @@ public final class SmsManager { * raw pdu of the status report is in the extended data ("pdu"). * * @throws IllegalArgumentException if destinationAddress or text are empty + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { @@ -581,8 +584,11 @@ public final class SmsManager { * Used for logging and diagnostics purposes. The id may be 0. * * @throws IllegalArgumentException if destinationAddress or text are empty + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. * */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendTextMessage( @NonNull String destinationAddress, @Nullable String scAddress, @NonNull String text, @Nullable PendingIntent sentIntent, @Nullable PendingIntent deliveryIntent, @@ -788,12 +794,16 @@ public final class SmsManager { * </p> * * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent) + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(allOf = { android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS }) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendTextMessageWithoutPersisting( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { @@ -908,7 +918,10 @@ public final class SmsManager { * {@link #RESULT_REMOTE_EXCEPTION} for error. * * @throws IllegalArgumentException if the format is invalid. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void injectSmsPdu( byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent) { if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) { @@ -940,6 +953,7 @@ public final class SmsManager { * @return an <code>ArrayList</code> of strings that, in order, comprise the original message. * @throws IllegalArgumentException if text is null. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public ArrayList<String> divideMessage(String text) { if (null == text) { throw new IllegalArgumentException("text is null"); @@ -1046,7 +1060,10 @@ public final class SmsManager { * extended data ("pdu"). * * @throws IllegalArgumentException if destinationAddress or data are empty + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { @@ -1062,8 +1079,10 @@ public final class SmsManager { * Used for logging and diagnostics purposes. The id may be 0. * * @throws IllegalArgumentException if destinationAddress or data are empty - * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendMultipartTextMessage( @NonNull String destinationAddress, @Nullable String scAddress, @NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents, @@ -1089,7 +1108,11 @@ public final class SmsManager { * * @param packageName serves as the default package name if the package name that is * associated with the user id is null. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendMultipartTextMessage( @NonNull String destinationAddress, @Nullable String scAddress, @NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents, @@ -1191,10 +1214,14 @@ public final class SmsManager { * </p> * * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList) + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. * @hide **/ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendMultipartTextMessageWithoutPersisting( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { @@ -1498,7 +1525,10 @@ public final class SmsManager { * raw pdu of the status report is in the extended data ("pdu"). * * @throws IllegalArgumentException if destinationAddress or data are empty + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendDataMessage( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { @@ -1609,6 +1639,7 @@ public final class SmsManager { * .{@link #createForSubscriptionId createForSubscriptionId(subId)} instead */ @Deprecated + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public static SmsManager getSmsManagerForSubscriptionId(int subId) { return getSmsManagerForContextAndSubscriptionId(null, subId); } @@ -1626,6 +1657,7 @@ public final class SmsManager { * @see SubscriptionManager#getActiveSubscriptionInfoList() * @see SubscriptionManager#getDefaultSmsSubscriptionId() */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public @NonNull SmsManager createForSubscriptionId(int subId) { return getSmsManagerForContextAndSubscriptionId(mContext, subId); } @@ -1651,7 +1683,11 @@ public final class SmsManager { * @return associated subscription ID or {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if * the default subscription id cannot be determined or the device has multiple active * subscriptions and and no default is set ("ask every time") by the user. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public int getSubscriptionId() { try { return (mSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) @@ -2018,10 +2054,14 @@ public final class SmsManager { * * @throws IllegalArgumentException if endMessageId < startMessageId * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} instead. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. * {@hide} */ @Deprecated @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, @android.telephony.SmsCbMessage.MessageFormat int ranType) { boolean success = false; @@ -2079,11 +2119,15 @@ public final class SmsManager { * @see #enableCellBroadcastRange(int, int, int) * * @throws IllegalArgumentException if endMessageId < startMessageId + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. + * * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} instead. * {@hide} */ @Deprecated @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, @android.telephony.SmsCbMessage.MessageFormat int ranType) { boolean success = false; @@ -2223,7 +2267,11 @@ public final class SmsManager { * @return the user-defined default SMS subscription id, or the active subscription id if * there's only one active subscription available, otherwise * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public static int getDefaultSmsSubscriptionId() { try { return getISmsService().getPreferredSmsSubscription(); @@ -2271,10 +2319,14 @@ public final class SmsManager { * </p> * * @return the total number of SMS records which can be stored on the SIM card. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ @RequiresPermission(anyOf = {android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}) @IntRange(from = 0) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public int getSmsCapacityOnIcc() { int ret = 0; try { @@ -2819,7 +2871,10 @@ public final class SmsManager { * <code>MMS_ERROR_DATA_DISABLED</code><br> * <code>MMS_ERROR_MMS_DISABLED_BY_CARRIER</code><br> * @throws IllegalArgumentException if contentUri is empty + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent) { sendMultimediaMessage(context, contentUri, locationUrl, configOverrides, sentIntent, @@ -2863,7 +2918,10 @@ public final class SmsManager { * @param messageId an id that uniquely identifies the message requested to be sent. * Used for logging and diagnostics purposes. The id may be 0. * @throws IllegalArgumentException if contentUri is empty + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void sendMultimediaMessage(@NonNull Context context, @NonNull Uri contentUri, @Nullable String locationUrl, @SuppressWarnings("NullableCollection") @Nullable Bundle configOverrides, @@ -2922,7 +2980,10 @@ public final class SmsManager { * <code>MMS_ERROR_DATA_DISABLED</code><br> * <code>MMS_ERROR_MMS_DISABLED_BY_CARRIER</code><br> * @throws IllegalArgumentException if locationUrl or contentUri is empty + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent) { downloadMultimediaMessage(context, locationUrl, contentUri, configOverrides, @@ -2968,7 +3029,10 @@ public final class SmsManager { * @param messageId an id that uniquely identifies the message requested to be downloaded. * Used for logging and diagnostics purposes. The id may be 0. * @throws IllegalArgumentException if locationUrl or contentUri is empty + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void downloadMultimediaMessage(@NonNull Context context, @NonNull String locationUrl, @NonNull Uri contentUri, @SuppressWarnings("NullableCollection") @Nullable Bundle configOverrides, @@ -3079,7 +3143,11 @@ public final class SmsManager { * * @return the bundle key/values pairs that contains MMS configuration values * or an empty Bundle if they cannot be found. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) @NonNull public Bundle getCarrierConfigValues() { try { ISms iSms = getISmsService(); @@ -3115,7 +3183,11 @@ public final class SmsManager { * * @return Token to include in an SMS message. The token will be 11 characters long. * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public String createAppSpecificSmsToken(PendingIntent intent) { try { ISms iccSms = getISmsServiceOrThrow(); @@ -3233,7 +3305,11 @@ public final class SmsManager { * message. * @param intent this intent is sent when the matching SMS message is received. * @return Token to include in an SMS message. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) @Nullable public String createAppSpecificSmsTokenWithPackageInfo( @Nullable String prefixes, @NonNull PendingIntent intent) { @@ -3393,9 +3469,13 @@ public final class SmsManager { * </p> * * @return the SMSC address string, null if failed. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ @SuppressAutoDoc // for carrier privileges and default SMS application. @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) @Nullable public String getSmscAddress() { String smsc = null; @@ -3430,9 +3510,13 @@ public final class SmsManager { * * @param smsc the SMSC address string. * @return true for success, false otherwise. Failure can be due modem returning an error. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. */ @SuppressAutoDoc // for carrier privileges and default SMS application. @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public boolean setSmscAddress(@NonNull String smsc) { try { ISms iSms = getISmsService(); @@ -3455,10 +3539,14 @@ public final class SmsManager { * {@link SmsManager#PREMIUM_SMS_CONSENT_ASK_USER}, * {@link SmsManager#PREMIUM_SMS_CONSENT_NEVER_ALLOW}, or * {@link SmsManager#PREMIUM_SMS_CONSENT_ALWAYS_ALLOW} + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public @PremiumSmsConsent int getPremiumSmsConsent(@NonNull String packageName) { int permission = 0; try { @@ -3479,10 +3567,14 @@ public final class SmsManager { * @param permission one of {@link SmsManager#PREMIUM_SMS_CONSENT_ASK_USER}, * {@link SmsManager#PREMIUM_SMS_CONSENT_NEVER_ALLOW}, or * {@link SmsManager#PREMIUM_SMS_CONSENT_ALWAYS_ALLOW} + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void setPremiumSmsConsent( @NonNull String packageName, @PremiumSmsConsent int permission) { try { @@ -3498,11 +3590,15 @@ public final class SmsManager { /** * Reset all cell broadcast ranges. Previously enabled ranges will become invalid after this. * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} with empty list instead + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}. * @hide */ @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public void resetAllCellBroadcastRanges() { try { ISms iSms = getISmsService(); @@ -3530,6 +3626,8 @@ public final class SmsManager { * available. * @throws SecurityException if the caller does not have the required permission/privileges. * @throws IllegalStateException in case of telephony service is not available. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @NonNull diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 6c8663a8eb14..56156024fbab 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1757,6 +1757,9 @@ public class SubscriptionManager { * * @param subId The unique SubscriptionInfo key in database. * @return SubscriptionInfo, maybe null if its not active. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @@ -1790,6 +1793,8 @@ public class SubscriptionManager { * @param iccId the IccId of SIM card * @return SubscriptionInfo, maybe null if its not active * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @@ -1826,6 +1831,9 @@ public class SubscriptionManager { * * @param slotIndex the slot which the subscription is inserted * @return SubscriptionInfo, maybe null if its not active + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @@ -1870,6 +1878,8 @@ public class SubscriptionManager { * {@link SubscriptionInfo#getSubscriptionId()}. * * @throws SecurityException if callers do not hold the required permission. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @NonNull @RequiresPermission(anyOf = { @@ -1929,6 +1939,9 @@ public class SubscriptionManager { * then by {@link SubscriptionInfo#getSubscriptionId}. * </li> * </ul> + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) // @RequiresPermission(TODO(b/308809058)) @@ -1972,6 +1985,8 @@ public class SubscriptionManager { * This is similar to {@link #getActiveSubscriptionInfoList} except that it will return * both active and hidden SubscriptionInfos. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ public @NonNull List<SubscriptionInfo> getCompleteActiveSubscriptionInfoList() { List<SubscriptionInfo> completeList = getActiveSubscriptionInfoList( @@ -2056,6 +2071,9 @@ public class SubscriptionManager { * <p> * Permissions android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE is required * for #getAvailableSubscriptionInfoList to be invoked. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -2097,6 +2115,9 @@ public class SubscriptionManager { * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} * then by {@link SubscriptionInfo#getSubscriptionId}. * </ul> + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_EUICC}. */ public List<SubscriptionInfo> getAccessibleSubscriptionInfoList() { List<SubscriptionInfo> result = null; @@ -2125,6 +2146,8 @@ public class SubscriptionManager { * * @see TelephonyManager#getCardIdForDefaultEuicc() for more information on the card ID. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_EUICC}. * @hide */ @SystemApi @@ -2155,6 +2178,8 @@ public class SubscriptionManager { * * @see TelephonyManager#getCardIdForDefaultEuicc() for more information on the card ID. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_EUICC}. * @hide */ @SystemApi @@ -2177,6 +2202,9 @@ public class SubscriptionManager { * @return The current number of active subscriptions. * * @see #getActiveSubscriptionInfoList() + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) // @RequiresPermission(TODO(b/308809058)) @@ -2247,6 +2275,9 @@ public class SubscriptionManager { * @param slotIndex the slot assigned to this subscription. It is ignored for subscriptionType * of {@link #SUBSCRIPTION_TYPE_REMOTE_SIM}. * @param subscriptionType the {@link #SUBSCRIPTION_TYPE} + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @@ -2289,6 +2320,8 @@ public class SubscriptionManager { * @throws NullPointerException if {@code uniqueId} is {@code null}. * @throws SecurityException if callers do not hold the required permission. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @@ -2435,6 +2468,7 @@ public class SubscriptionManager { * @deprecated Use {@link #getSubscriptionId(int)} instead. * @hide */ + @Deprecated public static int[] getSubId(int slotIndex) { if (!isValidSlotIndex(slotIndex)) { return null; @@ -2489,6 +2523,9 @@ public class SubscriptionManager { * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID. * * @return the default voice subscription Id. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ public static int getDefaultVoiceSubscriptionId() { int subId = INVALID_SUBSCRIPTION_ID; @@ -2516,6 +2553,9 @@ public class SubscriptionManager { * * @param subscriptionId A valid subscription ID to set as the system default, or * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -2535,6 +2575,9 @@ public class SubscriptionManager { /** * Same as {@link #setDefaultVoiceSubscriptionId(int)}, but preserved for backwards * compatibility. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ public void setDefaultVoiceSubId(int subId) { @@ -2578,6 +2621,8 @@ public class SubscriptionManager { * * @param subscriptionId the supplied subscription ID * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -2612,6 +2657,8 @@ public class SubscriptionManager { * * @param subscriptionId the supplied subscription ID * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -2634,6 +2681,9 @@ public class SubscriptionManager { * Will return null on voice only devices, or on error. * * @return the SubscriptionInfo for the default data subscription. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @UnsupportedAppUsage @@ -2720,6 +2770,9 @@ public class SubscriptionManager { * * @return the list of subId's that are active, * is never null but the length may be 0. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -2738,6 +2791,9 @@ public class SubscriptionManager { * * @return the list of subId's that are active, * is never null but the length may be 0. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -2987,6 +3043,9 @@ public class SubscriptionManager { * @param context Context object * @param subId Subscription Id of Subscription whose resources are required * @return Resources associated with Subscription. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @NonNull @@ -3069,6 +3128,9 @@ public class SubscriptionManager { * @return {@code true} if the supplied subscription ID corresponds to an active subscription; * {@code false} if it does not correspond to an active subscription; or throw a * SecurityException if the caller hasn't got the right permission. + *i + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isActiveSubscriptionId(int subscriptionId) { @@ -3377,6 +3439,8 @@ public class SubscriptionManager { * * @throws IllegalStateException when subscription manager service is not available. * @throws SecurityException when clients do not have MODIFY_PHONE_STATE permission. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -3454,6 +3518,9 @@ public class SubscriptionManager { * {@link TelephonyManager#hasCarrierPrivileges}). * * @return the list of opportunistic subscription info. If none exists, an empty list. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @@ -3489,8 +3556,12 @@ public class SubscriptionManager { * PendingIntent)} and does not support Multiple Enabled Profile(MEP). Apps should use * {@link EuiccManager#switchToSubscription(int, PendingIntent)} or * {@link EuiccManager#switchToSubscription(int, int, PendingIntent)} instead. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_EUICC}. */ @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC) @Deprecated public void switchToSubscription(int subId, @NonNull PendingIntent callbackIntent) { Preconditions.checkNotNull(callbackIntent, "callbackIntent cannot be null"); @@ -3518,6 +3589,9 @@ public class SubscriptionManager { * @param opportunistic whether it’s opportunistic subscription. * @param subId the unique SubscriptionInfo index in database * @return {@code true} if the operation is succeed, {@code false} otherwise. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -3554,6 +3628,8 @@ public class SubscriptionManager { * outlined above. * @throws IllegalArgumentException if any of the subscriptions in the list doesn't exist. * @throws IllegalStateException if Telephony service is in bad state. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * * @param subIdList list of subId that will be in the same group * @return groupUUID a UUID assigned to the subscription group. @@ -3598,6 +3674,8 @@ public class SubscriptionManager { * outlined above. * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist. * @throws IllegalStateException if Telephony service is in bad state. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * * @param subIdList list of subId that need adding into the group * @param groupUuid the groupUuid the subscriptions are being added to. @@ -3647,6 +3725,8 @@ public class SubscriptionManager { * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong the * specified group. * @throws IllegalStateException if Telephony service is in bad state. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * * @see #createSubscriptionGroup(List) */ @@ -3696,6 +3776,8 @@ public class SubscriptionManager { * @throws IllegalStateException if Telephony service is in bad state. * @throws SecurityException if the caller doesn't meet the requirements * outlined above. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * * @param groupUuid of which list of subInfo will be returned. * @return list of subscriptionInfo that belong to the same group, including the given @@ -3785,9 +3867,9 @@ public class SubscriptionManager { Map<ParcelUuid, SubscriptionInfo> groupMap = new HashMap<>(); for (SubscriptionInfo info : availableList) { - // Opportunistic subscriptions are considered invisible + // Grouped opportunistic subscriptions are considered invisible // to users so they should never be returned. - if (!isSubscriptionVisible(info)) continue; + if (info.getGroupUuid() != null && info.isOpportunistic()) continue; ParcelUuid groupUuid = info.getGroupUuid(); if (groupUuid == null) { @@ -3817,6 +3899,8 @@ public class SubscriptionManager { * * @return whether the operation is successful. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -3844,6 +3928,9 @@ public class SubscriptionManager { * * @param subscriptionId which subscription to operate on. * @param enabled whether uicc applications are enabled or disabled. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -3872,6 +3959,8 @@ public class SubscriptionManager { * * @return whether can disable subscriptions on physical SIMs. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -3897,6 +3986,8 @@ public class SubscriptionManager { * * @param subscriptionId The subscription id. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -3923,6 +4014,8 @@ public class SubscriptionManager { * @param sharing The status sharing preference. * * @throws SecurityException if the caller doesn't have permissions required. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharingPreference(int subscriptionId, @@ -3941,6 +4034,8 @@ public class SubscriptionManager { * @return The device to device status sharing preference * * @throws SecurityException if the caller doesn't have permissions required. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ public @DeviceToDeviceStatusSharingPreference int getDeviceToDeviceStatusSharingPreference( int subscriptionId) { @@ -3960,6 +4055,8 @@ public class SubscriptionManager { * @param contacts The list of contacts that allow device to device status sharing. * * @throws SecurityException if the caller doesn't have permissions required. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharingContacts(int subscriptionId, @@ -3980,6 +4077,9 @@ public class SubscriptionManager { * @param subscriptionId Subscription id. * * @return The list of contacts that allow device to device status sharing. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ public @NonNull List<Uri> getDeviceToDeviceStatusSharingContacts(int subscriptionId) { String result = getStringSubscriptionProperty(mContext, subscriptionId, @@ -4012,6 +4112,8 @@ public class SubscriptionManager { * * @throws IllegalArgumentException if the provided slot index is invalid. * @throws SecurityException if callers do not hold the required permission. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * * @hide */ @@ -4152,6 +4254,8 @@ public class SubscriptionManager { * * @param data with the sim specific configs to be backed up. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -4206,6 +4310,8 @@ public class SubscriptionManager { * @throws IllegalArgumentException if {@code source} is invalid. * @throws IllegalStateException if the telephony process is not currently available. * @throws SecurityException if the caller doesn't have permissions required. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * * @see #PHONE_NUMBER_SOURCE_UICC * @see #PHONE_NUMBER_SOURCE_CARRIER @@ -4266,6 +4372,8 @@ public class SubscriptionManager { * * @throws IllegalStateException if the telephony process is not currently available. * @throws SecurityException if the caller doesn't have permissions required. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * * @see #getPhoneNumber(int, int) */ @@ -4309,6 +4417,8 @@ public class SubscriptionManager { * @throws IllegalStateException if the telephony process is not currently available. * @throws NullPointerException if {@code number} is {@code null}. * @throws SecurityException if the caller doesn't have permissions required. + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @RequiresPermission("carrier privileges") public void setCarrierPhoneNumber(int subscriptionId, @NonNull String number) { diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java index 60b5ce75e2f7..80c1e5be3a32 100644 --- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java +++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java @@ -810,6 +810,7 @@ public class GraphicsActivity extends Activity { private FpsRange convertCategory(int category) { switch (category) { + case Surface.FRAME_RATE_CATEGORY_HIGH_HINT: case Surface.FRAME_RATE_CATEGORY_HIGH: return FRAME_RATE_CATEGORY_HIGH; case Surface.FRAME_RATE_CATEGORY_NORMAL: diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java index 4b56c107cf22..caaee634c57a 100644 --- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java +++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java @@ -93,6 +93,12 @@ public class SurfaceControlTest { } @Test + public void testSurfaceControlFrameRateCategoryHighHint() throws InterruptedException { + GraphicsActivity activity = mActivityRule.getActivity(); + activity.testSurfaceControlFrameRateCategory(Surface.FRAME_RATE_CATEGORY_HIGH_HINT); + } + + @Test public void testSurfaceControlFrameRateCategoryNormal() throws InterruptedException { GraphicsActivity activity = mActivityRule.getActivity(); activity.testSurfaceControlFrameRateCategory(Surface.FRAME_RATE_CATEGORY_NORMAL); diff --git a/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt b/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt new file mode 100644 index 000000000000..e2b0c36ae694 --- /dev/null +++ b/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt @@ -0,0 +1,215 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.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 android.platform.test.flag.junit.SetFlagsRule +import android.view.KeyEvent +import androidx.test.core.app.ApplicationProvider +import com.android.server.testutils.any +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.`when` +import org.mockito.junit.MockitoJUnitRunner +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue +import kotlin.test.fail + +/** + * Tests for [InputManager.StickyModifierStateListener]. + * + * Build/Install/Run: + * atest InputTests:StickyModifierStateListenerTest + */ +@Presubmit +@RunWith(MockitoJUnitRunner::class) +class StickyModifierStateListenerTest { + + @get:Rule + val rule = SetFlagsRule() + + private val testLooper = TestLooper() + private val executor = HandlerExecutor(Handler(testLooper.looper)) + private var registeredListener: IStickyModifierStateListener? = null + private lateinit var context: Context + private lateinit var inputManager: InputManager + private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession + + @Mock + private lateinit var iInputManagerMock: IInputManager + + @Before + fun setUp() { + // Enable Sticky keys feature + rule.enableFlags(com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG) + rule.enableFlags(com.android.input.flags.Flags.FLAG_ENABLE_INPUT_FILTER_RUST_IMPL) + + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock) + inputManager = InputManager(context) + `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) + .thenReturn(inputManager) + + // Handle sticky modifier state listener registration. + doAnswer { + val listener = it.getArgument(0) as IStickyModifierStateListener + if (registeredListener != null && + registeredListener!!.asBinder() != listener.asBinder()) { + // There can only be one registered sticky modifier state listener per process. + fail("Trying to register a new listener when one already exists") + } + registeredListener = listener + null + }.`when`(iInputManagerMock).registerStickyModifierStateListener(any()) + + // Handle sticky modifier state listener being unregistered. + doAnswer { + val listener = it.getArgument(0) as IStickyModifierStateListener + if (registeredListener == null || + registeredListener!!.asBinder() != listener.asBinder()) { + fail("Trying to unregister a listener that is not registered") + } + registeredListener = null + null + }.`when`(iInputManagerMock).unregisterStickyModifierStateListener(any()) + } + + @After + fun tearDown() { + if (this::inputManagerGlobalSession.isInitialized) { + inputManagerGlobalSession.close() + } + } + + private fun notifyStickyModifierStateChanged(modifierState: Int, lockedModifierState: Int) { + registeredListener!!.onStickyModifierStateChanged(modifierState, lockedModifierState) + } + + @Test + fun testListenerIsNotifiedOnModifierStateChanged() { + var callbackCount = 0 + + // Add a sticky modifier state listener + inputManager.registerStickyModifierStateListener(executor) { + callbackCount++ + } + + // Notifying sticky modifier state change will notify the listener. + notifyStickyModifierStateChanged(0, 0) + testLooper.dispatchNext() + assertEquals(1, callbackCount) + } + + @Test + fun testListenerHasCorrectModifierStateNotified() { + // Add a sticky modifier state listener + inputManager.registerStickyModifierStateListener(executor) { + state: StickyModifierState -> + assertTrue(state.isAltModifierOn) + assertTrue(state.isAltModifierLocked) + assertTrue(state.isShiftModifierOn) + assertTrue(!state.isShiftModifierLocked) + assertTrue(!state.isCtrlModifierOn) + assertTrue(!state.isCtrlModifierLocked) + assertTrue(!state.isMetaModifierOn) + assertTrue(!state.isMetaModifierLocked) + assertTrue(!state.isAltGrModifierOn) + assertTrue(!state.isAltGrModifierLocked) + } + + // Notifying sticky modifier state change will notify the listener. + notifyStickyModifierStateChanged( + KeyEvent.META_ALT_ON or KeyEvent.META_ALT_LEFT_ON or + KeyEvent.META_SHIFT_ON or KeyEvent.META_SHIFT_LEFT_ON, + KeyEvent.META_ALT_ON or KeyEvent.META_ALT_LEFT_ON + ) + testLooper.dispatchNext() + } + + @Test + fun testAddingListenersRegistersInternalCallbackListener() { + // Set up two callbacks. + val callback1 = InputManager.StickyModifierStateListener {} + val callback2 = InputManager.StickyModifierStateListener {} + + assertNull(registeredListener) + + // Adding the listener should register the callback with InputManagerService. + inputManager.registerStickyModifierStateListener(executor, callback1) + assertNotNull(registeredListener) + + // Adding another listener should not register new internal listener. + val currListener = registeredListener + inputManager.registerStickyModifierStateListener(executor, callback2) + assertEquals(currListener, registeredListener) + } + + @Test + fun testRemovingListenersUnregistersInternalCallbackListener() { + // Set up two callbacks. + val callback1 = InputManager.StickyModifierStateListener {} + val callback2 = InputManager.StickyModifierStateListener {} + + inputManager.registerStickyModifierStateListener(executor, callback1) + inputManager.registerStickyModifierStateListener(executor, callback2) + + // Only removing all listeners should remove the internal callback + inputManager.unregisterStickyModifierStateListener(callback1) + assertNotNull(registeredListener) + inputManager.unregisterStickyModifierStateListener(callback2) + assertNull(registeredListener) + } + + @Test + fun testMultipleListeners() { + // Set up two callbacks. + var callbackCount1 = 0 + var callbackCount2 = 0 + val callback1 = InputManager.StickyModifierStateListener { _ -> callbackCount1++ } + val callback2 = InputManager.StickyModifierStateListener { _ -> callbackCount2++ } + + // Add both sticky modifier state listeners + inputManager.registerStickyModifierStateListener(executor, callback1) + inputManager.registerStickyModifierStateListener(executor, callback2) + + // Notifying sticky modifier state change trigger the both callbacks. + notifyStickyModifierStateChanged(0, 0) + testLooper.dispatchAll() + assertEquals(1, callbackCount1) + assertEquals(1, callbackCount2) + + inputManager.unregisterStickyModifierStateListener(callback2) + // Notifying sticky modifier state change should still trigger callback1 but not callback2. + notifyStickyModifierStateChanged(0, 0) + testLooper.dispatchAll() + assertEquals(2, callbackCount1) + assertEquals(1, callbackCount2) + } +} |